diff --git a/.codeclimate.yml b/.codeclimate.yml index 9c6d37baf6..3beadbce4a 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -3,6 +3,7 @@ languages: JavaScript: true PHP: true exclude_paths: +- "gulpfile.js" - "public/packages/maximebf/php-debugbar/debugbar.js" - "public/packages/maximebf/php-debugbar/widgets.js" - "public/packages/maximebf/php-debugbar/openhandler.js" diff --git a/.env.example b/.env.example old mode 100644 new mode 100755 index 1784ebbb83..b4ab896c88 --- a/.env.example +++ b/.env.example @@ -11,15 +11,22 @@ DB_PASSWORD=secret CACHE_DRIVER=file SESSION_DRIVER=file +QUEUE_DRIVER=sync DEFAULT_CURRENCY=EUR DEFAULT_LANGUAGE=en_US -EMAIL_SMTP= -EMAIL_DRIVER=smtp -EMAIL_USERNAME= -EMAIL_PASSWORD= -EMAIL_PRETEND=false +REDIS_HOST=localhost +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_DRIVER=smtp +MAIL_HOST=mailtrap.io +MAIL_PORT=2525 +MAIL_FROM=enter_your_email_here +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null SHOW_INCOMPLETE_TRANSLATIONS=false diff --git a/.env.testing b/.env.testing old mode 100644 new mode 100755 index 5443422bda..a7c8505a17 --- a/.env.testing +++ b/.env.testing @@ -1,6 +1,7 @@ APP_ENV=testing APP_DEBUG=true -APP_KEY=SomeRandomString +APP_KEY=SomeRandomStringOf32CharsExactly + DB_CONNECTION=sqlite DB_HOST=localhost @@ -10,9 +11,27 @@ DB_PASSWORD=secret CACHE_DRIVER=array SESSION_DRIVER=array +QUEUE_DRIVER=array -EMAIL_SMTP= -EMAIL_USERNAME= -EMAIL_PASSWORD= -ANALYTICS_ID=ABC -EMAIL_PRETEND=true \ No newline at end of file +DEFAULT_CURRENCY=EUR +DEFAULT_LANGUAGE=en_US + +REDIS_HOST=localhost +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_DRIVER=log +MAIL_HOST=mailtrap.io +MAIL_PORT=2525 +MAIL_FROM=your_address_here@example.com +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null + +SHOW_INCOMPLETE_TRANSLATIONS=false + +ANALYTICS_ID=abcde +RUNCLEANUP=false +SITE_OWNER=your_address_here@example.com + +BLOCKED_DOMAINS= \ No newline at end of file diff --git a/.gitattributes b/.gitattributes old mode 100644 new mode 100755 index 176a458f94..95883deab5 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ * text=auto +*.css linguist-vendored +*.less linguist-vendored diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 5cb379f496..b59bed9bb4 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1,18 @@ -/bootstrap/compiled.php /vendor -composer.phar -Thumbs.db -.idea/ -tests/_output/* -_ide_helper.php -/build/logs -index.html* -app/storage/firefly-export* -.vagrant -firefly-iii-import-*.json -tests/_output/* -testing.sqlite -_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 -db.sqlite_snapshot -c3.php -db.sqlite-journal -tests/_output/* +/node_modules +Homestead.yaml +Homestead.json .env -clover.xml -node_modules/ -addNewLines.php +.idea/ +_ide_helper.php +_ide_helper_models.php .phpstorm.meta.php -.env.backup -.env.local -tests/_output/* -tests/_output/* +storage/ + +# Eclipse project files +.buildpath +.project +.settings/ + +.env.local diff --git a/.travis.yml b/.travis.yml index 820282fa3a..f9ca51f24e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,16 +3,18 @@ sudo: false php: - - 5.5 - 5.6 + - 7 install: - - composer update + - composer install - php artisan env - mv -v .env.testing .env + - php artisan env + - touch storage/upload/at-1.data + - touch storage/upload/at-2.data - touch storage/database/testing.db - - php artisan migrate --env=testing - - php artisan migrate --seed --env=testing + - php artisan migrate --seed script: - phpunit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..88ab8e15bb --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright (C) 2016 Sander Dorigo + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 9c903b7412..a030166466 100644 --- a/README.md +++ b/README.md @@ -2,129 +2,25 @@ [![Latest Stable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/stable)](https://packagist.org/packages/grumpydictator/firefly-iii) [![Total Downloads](https://poser.pugx.org/grumpydictator/firefly-iii/downloads)](https://packagist.org/packages/grumpydictator/firefly-iii) - [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/JC5/firefly-iii/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/JC5/firefly-iii/?branch=master) [![Build Status](https://scrutinizer-ci.com/g/JC5/firefly-iii/badges/build.png?b=master)](https://scrutinizer-ci.com/g/JC5/firefly-iii/build-status/master) +[![SensioLabsInsight](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102/mini.png)](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102) +[![Code Climate](https://codeclimate.com/github/JC5/firefly-iii/badges/gpa.svg)](https://codeclimate.com/github/JC5/firefly-iii) +[![Project Status](http://stillmaintained.com/JC5/firefly-iii.png?a=b)](http://stillmaintained.com/JC5/firefly-iii) ## About "Firefly III" is a financial manager. It can help you keep track of expenses, income, budgets and everything in between. It even supports credit cards, shared household accounts and savings accounts! It's pretty fancy. You should use it to save and organise money. - -Personal financial management is pretty difficult, and everybody has their own approach to it. Some people -make budgets, other people limit their cashflow by throwing away their credit cards, others try to increase -their current cashflow. There are tons of ways to save and earn money. + +Personal financial management is pretty difficult, and everybody has their own approach to it. Some people make budgets, other people limit their cashflow by throwing away their credit cards, others try to increase their current cashflow. There are tons of ways to save and earn money. Firefly works on the principle that if you know where you're money is going, you can stop it from going there. -To get to know Firefly, and to see if it fits you, check out these resources: +#### Some advantages of using Firefly -- The screenshots below on this very page. -- The featurelist below, also on this very page. -- The [full description](https://github.com/JC5/firefly-iii/wiki/full-description), which will tell you how Firefly works, -and the philosophy behind it. +- Firefly can import any CSV file, so migrating from other systems is easy. +- Firefly runs on your own server, so you are fully in control of your data. +- If you feel you're missing something you can just ask me and I'll add it! -#### A quick technical overview - -Firefly is a system you'll have install yourself on webhosting of your choosing. It needs PHP and MySQL. The current version of Firefly III requires PHP 5.6.4 or -higher. Soon, this will be PHP 7.0.0 or higher. - - -#### About the name (should you care) - -It's III, or 3, because [version 2](https://github.com/JC5/Firefly) and version 1 (not online) preceded it. It has been growing steadily ever since. - -## Current features - -- [A double-entry bookkeeping system](https://en.wikipedia.org/wiki/Double-entry_bookkeeping_system); -- You can store, edit and remove [withdrawals, deposits and transfers](https://en.wikipedia.org/wiki/Financial_transaction). This allows you full financial management; -- You can manage different types of accounts; - - [Asset](https://en.wikipedia.org/wiki/Asset) accounts - - Shared [asset accounts](https://en.wikipedia.org/wiki/Asset) ([household accounts](https://en.wikipedia.org/wiki/Household)) - - Saving accounts - - Credit cards -- It's possible to create, change and manage money using _[budgets](https://en.wikipedia.org/wiki/Envelope_system)_; -- Organize transactions using categories; -- Save towards a goal using [piggy banks](https://en.wikipedia.org/wiki/Piggy_bank); -- Predict and anticipate [bills](https://en.wikipedia.org/wiki/Invoice); -- View income / expense [reports](https://en.wikipedia.org/wiki/Financial_statement); -- Organize expenses using tags; -- Lots of help text in case you don't get it. - -Everything is organised: - -- Clear views that should show you how you're doing; -- Easy navigation through your records; -- Browse back and forth to see previous months or even years; -- Lots of charts because we all love them; -- Financial reporting showing you how well you are doing. - -## Screenshots - -_Please note that everything in these screenshots is fictional and may not be realistic._ - -![Index](https://i.nder.be/hmp5mhw5) - -![Accounts](https://i.nder.be/hf5k02g9) - -![Budgets](https://i.nder.be/gzv635mz) - -![Reports 1](https://i.nder.be/g0w698s3) - -![Reports 2](https://i.nder.be/cr77nyxq) - -![Bills](https://i.nder.be/c7sugsz5) - -![Piggy banks](https://i.nder.be/gy2nk0y4) - -## Running and installing - -If you're still interested please read [the installation guide](https://github.com/JC5/firefly-iii/wiki/Installation), -[the upgrade guide](https://github.com/JC5/firefly-iii/wiki/Upgrade-instructions) (if applicable) -and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**. - -If you want to try out Firefly III, you can do so on [this dedicated website](https://geld.nder.be/). -This site always runs the latest version of Firefly III. If you want to use it, please read the [privacy considerations](https://github.com/JC5/firefly-iii/wiki/Privacy-on-demo-site) for this demo-site. Accounts on the demo sites will stop working after one month. It's a trial. - -## Security - -You should always run Firefly III on a site with TLS enabled (https://). Please note that although some parts of the -database are encrypted (transaction descriptions, names, etc.) some parts are _not_ (amounts, dates, etc). If you need -more security, you must enable transparent database encryption or a comparable technology. Please remember that this -is open source software under active development, and it is in no way guaranteed to be safe or secure. - -## Translations - -Firefly III is currently available in Dutch and English. Support for other languages is being worked on. I could use -your help. Checkout [Crowdin](https://crowdin.com/project/firefly-iii) for more information. - -## Credits - -Firefly III uses the following libraries and tools: - -* The AdminLTE template by [Almsaseed Studio](https://almsaeedstudio.com/) -* The [Google charts](https://developers.google.com/chart/) library. -* [Chart.js](http://www.chartjs.org/) -* [Bootstrap](http://getbootstrap.com/) -* [Laravel](http://laravel.com/) -* [Twig](http://twig.sensiolabs.org/) -* For development, some of the excellent tools made by [Barry van den Heuvel](https://github.com/barryvdh) -* [Bootstrap sortable](https://github.com/drvic10k/bootstrap-sortable) by [Matúš Brliť](https://github.com/drvic10k). -* [Date range picker](https://github.com/dangrossman/bootstrap-daterangepicker/) by [Dan Grossman](https://github.com/dangrossman) -* The [real favicon generator](http://realfavicongenerator.net/) -* Various other open source components (see [composer.json](https://github.com/JC5/firefly-iii/blob/master/composer.json)) - - -## Current state - -Firefly III is pretty much all grown up. Full test coverage (nerd alert!) is coming. Translations are a work in progress. - -Questions, ideas, bugs or other things to contribute? [Let me know](https://github.com/JC5/firefly-iii/issues/new)! - -If you like this tool, feel free to [donate me some beer money](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2ZMV952UUSCLU&lc=NL&item_name=Development%20of%20Firefly¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted). - -[![SensioLabsInsight](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102/mini.png)](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102) -[![Code Climate](https://codeclimate.com/github/JC5/firefly-iii/badges/gpa.svg)](https://codeclimate.com/github/JC5/firefly-iii) -[![Project Status](http://stillmaintained.com/JC5/firefly-iii.png?a=b)](http://stillmaintained.com/JC5/firefly-iii) -[![Latest Stable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/stable.svg)](https://packagist.org/packages/grumpydictator/firefly-iii) -![GA](https://ga-beacon.appspot.com/UA-58172398-6/firefly-iii/readme) +Firefly is pretty awesome. [You can read more about Firefly III, and its features, on the Github Pages](https://jc5.github.io/firefly-iii/). diff --git a/app/Commands/Command.php b/app/Commands/Command.php deleted file mode 100644 index 1212b4e554..0000000000 --- a/app/Commands/Command.php +++ /dev/null @@ -1,12 +0,0 @@ -line('+------------------------------------------------------------------------------+'); + $this->line(''); + + if (is_null($text)) { + $this->line('Thank you for installing Firefly III, v' . $version); + $this->line('If you are upgrading from a previous version,'); + $this->info('there are no extra upgrade instructions.'); + $this->line('Firefly III should be ready for use.'); + } else { + $this->line('Thank you for installing Firefly III, v' . $version); + $this->line('If you are upgrading from a previous version,'); + $this->line('please follow these upgrade instructions carefully:'); + $this->info(wordwrap($text)); + } + + $this->line(''); + $this->line('+------------------------------------------------------------------------------+'); + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php old mode 100644 new mode 100755 index 6f8232dbc0..88960c8a36 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -1,17 +1,25 @@ -renderHttpException($e); - } else { - return parent::render($request, $e); - } - } - /** * Report or log an exception. * * This is a great spot to send exceptions to Sentry, Bugsnag, etc. - * @SuppressWarnings(PHPMD.ShortVariable) * - * @param \Exception $e + * @param Exception $exception * * @return void */ - public function report(Exception $e) + public function report(Exception $exception) { - parent::report($e); + parent::report($exception); } + /** + * Render an exception into an HTTP response. + * + * @param \Illuminate\Http\Request $request + * @param \Exception $exception + * + * @return \Illuminate\Http\Response + */ + public function render($request, Exception $exception) + { + return parent::render($request, $exception); + } } diff --git a/app/Generator/Chart/Account/AccountChartGenerator.php b/app/Generator/Chart/Account/AccountChartGenerator.php index 5969d86178..5601e86306 100644 --- a/app/Generator/Chart/Account/AccountChartGenerator.php +++ b/app/Generator/Chart/Account/AccountChartGenerator.php @@ -14,6 +14,15 @@ use Illuminate\Support\Collection; interface AccountChartGenerator { + /** + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end); + /** * @param Collection $accounts * @param Carbon $start @@ -31,13 +40,4 @@ interface AccountChartGenerator * @return array */ public function single(Account $account, Carbon $start, Carbon $end); - - /** - * @param Collection $accounts - * @param Carbon $start - * @param Carbon $end - * - * @return array - */ - public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end); } diff --git a/app/Generator/Chart/Account/ChartJsAccountChartGenerator.php b/app/Generator/Chart/Account/ChartJsAccountChartGenerator.php index 20f59a922d..b9807954c5 100644 --- a/app/Generator/Chart/Account/ChartJsAccountChartGenerator.php +++ b/app/Generator/Chart/Account/ChartJsAccountChartGenerator.php @@ -62,22 +62,6 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator return $data; } - /** - * @param $array - * @param $entryId - * - * @return string - */ - protected function isInArray($array, $entryId) - { - if (isset($array[$entryId])) { - return $array[$entryId]; - } - - return '0'; - } - - /** * @param Collection $accounts * @param Carbon $start @@ -89,18 +73,13 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator { // language: $format = trans('config.month_and_day'); - $data = [ - 'count' => 0, - 'labels' => [], - 'datasets' => [], - ]; + $data = ['count' => 0, 'labels' => [], 'datasets' => [],]; $current = clone $start; while ($current <= $end) { $data['labels'][] = $current->formatLocalized($format); $current->addDay(); } - foreach ($accounts as $account) { $set = [ 'label' => $account->name, @@ -114,10 +93,10 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator ]; $current = clone $start; $range = Steam::balanceInRange($account, $start, clone $end); - $previous = array_values($range)[0]; + $previous = round(array_values($range)[0], 2); while ($current <= $end) { $format = $current->format('Y-m-d'); - $balance = isset($range[$format]) ? $range[$format] : $previous; + $balance = isset($range[$format]) ? round($range[$format], 2) : $previous; $set['data'][] = $balance; $previous = $balance; @@ -148,8 +127,8 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator 'datasets' => [ [ 'label' => $account->name, - 'data' => [] - ] + 'data' => [], + ], ], ]; $range = Steam::balanceInRange($account, $start, $end); @@ -184,4 +163,19 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator return array_unique($ids); } + + /** + * @param $array + * @param $entryId + * + * @return string + */ + protected function isInArray($array, $entryId) + { + if (isset($array[$entryId])) { + return $array[$entryId]; + } + + return '0'; + } } diff --git a/app/Generator/Chart/Bill/ChartJsBillChartGenerator.php b/app/Generator/Chart/Bill/ChartJsBillChartGenerator.php index 879a1f8d84..ff1c9b6150 100644 --- a/app/Generator/Chart/Bill/ChartJsBillChartGenerator.php +++ b/app/Generator/Chart/Bill/ChartJsBillChartGenerator.php @@ -35,7 +35,7 @@ class ChartJsBillChartGenerator implements BillChartGenerator 'color' => 'rgba(0, 141, 76, 0.7)', 'highlight' => 'rgba(0, 141, 76, 0.9)', 'label' => trans('firefly.paid'), - ] + ], ]; return $data; diff --git a/app/Generator/Chart/Budget/ChartJsBudgetChartGenerator.php b/app/Generator/Chart/Budget/ChartJsBudgetChartGenerator.php index 77678b93e9..65db28db6b 100644 --- a/app/Generator/Chart/Budget/ChartJsBudgetChartGenerator.php +++ b/app/Generator/Chart/Budget/ChartJsBudgetChartGenerator.php @@ -106,6 +106,40 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator return $data; } + /** + * @param Collection $entries + * + * @return array + */ + public function multiYear(Collection $entries) + { + // dataset: + $data = [ + 'count' => 0, + 'labels' => [], + 'datasets' => [], + ]; + // get labels from one of the budgets (assuming there's at least one): + $first = $entries->first(); + $keys = array_keys($first['budgeted']); + foreach ($keys as $year) { + $data['labels'][] = strval($year); + } + + // then, loop all entries and create datasets: + foreach ($entries as $entry) { + $name = $entry['name']; + $spent = $entry['spent']; + $budgeted = $entry['budgeted']; + $data['datasets'][] = ['label' => 'Spent on ' . $name, 'data' => array_values($spent)]; + $data['datasets'][] = ['label' => 'Budgeted for ' . $name, 'data' => array_values($budgeted)]; + } + $data['count'] = count($data['datasets']); + + return $data; + + } + /** * @param Collection $budgets * @param Collection $entries @@ -140,37 +174,4 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator return $data; } - - /** - * @param Collection $entries - * - * @return array - */ - public function multiYear(Collection $entries) - { - // dataset: - $data = [ - 'count' => 0, - 'labels' => [], - 'datasets' => [], - ]; - // get labels from one of the budgets (assuming there's at least one): - $first = $entries->first(); - foreach ($first['budgeted'] as $year => $noInterest) { - $data['labels'][] = strval($year); - } - - // then, loop all entries and create datasets: - foreach ($entries as $entry) { - $name = $entry['name']; - $spent = $entry['spent']; - $budgeted = $entry['budgeted']; - $data['datasets'][] = ['label' => 'Spent on ' . $name, 'data' => array_values($spent)]; - $data['datasets'][] = ['label' => 'Budgeted for ' . $name, 'data' => array_values($budgeted)]; - } - $data['count'] = count($data['datasets']); - - return $data; - - } } diff --git a/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php b/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php index 8bb0402d25..3c744cb9de 100644 --- a/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php +++ b/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php @@ -28,12 +28,12 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator 'datasets' => [ [ 'label' => trans('firefly.spent'), - 'data' => [] + 'data' => [], ], [ 'label' => trans('firefly.earned'), - 'data' => [] - ] + 'data' => [], + ], ], ]; @@ -95,8 +95,8 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator 'datasets' => [ [ 'label' => trans('firefly.spent'), - 'data' => [] - ] + 'data' => [], + ], ], ]; foreach ($entries as $entry) { @@ -124,7 +124,8 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator ]; // get labels from one of the categories (assuming there's at least one): $first = $entries->first(); - foreach ($first['spent'] as $year => $noInterest) { + $keys = array_keys($first['spent']); + foreach ($keys as $year) { $data['labels'][] = strval($year); } diff --git a/app/Generator/Chart/PiggyBank/ChartJsPiggyBankChartGenerator.php b/app/Generator/Chart/PiggyBank/ChartJsPiggyBankChartGenerator.php index bea4b9605a..a33b867911 100644 --- a/app/Generator/Chart/PiggyBank/ChartJsPiggyBankChartGenerator.php +++ b/app/Generator/Chart/PiggyBank/ChartJsPiggyBankChartGenerator.php @@ -31,8 +31,8 @@ class ChartJsPiggyBankChartGenerator implements PiggyBankChartGenerator 'datasets' => [ [ 'label' => 'Diff', - 'data' => [] - ] + 'data' => [], + ], ], ]; $sum = '0'; diff --git a/app/Generator/Chart/Report/ChartJsReportChartGenerator.php b/app/Generator/Chart/Report/ChartJsReportChartGenerator.php index 1089ba7305..3b64f1a8b1 100644 --- a/app/Generator/Chart/Report/ChartJsReportChartGenerator.php +++ b/app/Generator/Chart/Report/ChartJsReportChartGenerator.php @@ -27,12 +27,12 @@ class ChartJsReportChartGenerator implements ReportChartGenerator 'datasets' => [ [ 'label' => trans('firefly.income'), - 'data' => [] + 'data' => [], ], [ 'label' => trans('firefly.expenses'), - 'data' => [] - ] + 'data' => [], + ], ], ]; @@ -60,12 +60,12 @@ class ChartJsReportChartGenerator implements ReportChartGenerator 'datasets' => [ [ 'label' => trans('firefly.income'), - 'data' => [] + 'data' => [], ], [ 'label' => trans('firefly.expenses'), - 'data' => [] - ] + 'data' => [], + ], ], ]; $data['datasets'][0]['data'][] = round($income, 2); @@ -92,12 +92,12 @@ class ChartJsReportChartGenerator implements ReportChartGenerator 'datasets' => [ [ 'label' => trans('firefly.income'), - 'data' => [] + 'data' => [], ], [ 'label' => trans('firefly.expenses'), - 'data' => [] - ] + 'data' => [], + ], ], ]; @@ -126,12 +126,12 @@ class ChartJsReportChartGenerator implements ReportChartGenerator 'datasets' => [ [ 'label' => trans('firefly.income'), - 'data' => [] + 'data' => [], ], [ 'label' => trans('firefly.expenses'), - 'data' => [] - ] + 'data' => [], + ], ], ]; $data['datasets'][0]['data'][] = round($income, 2); diff --git a/app/Handlers/Events/ConnectJournalToPiggyBank.php b/app/Handlers/Events/ConnectJournalToPiggyBank.php index 4b599a9dec..0b6c96da8a 100644 --- a/app/Handlers/Events/ConnectJournalToPiggyBank.php +++ b/app/Handlers/Events/ConnectJournalToPiggyBank.php @@ -1,7 +1,7 @@ journal; @@ -42,12 +42,12 @@ class ConnectJournalToPiggyBank $piggyBank = Auth::user()->piggybanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']); if (is_null($piggyBank)) { - return false; + return true; } // update piggy bank rep for date of transaction journal. $repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first(); if (is_null($repetition)) { - return false; + return true; } bcscale(2); diff --git a/app/Handlers/Events/FireRulesForStore.php b/app/Handlers/Events/FireRulesForStore.php new file mode 100644 index 0000000000..2adb382390 --- /dev/null +++ b/app/Handlers/Events/FireRulesForStore.php @@ -0,0 +1,79 @@ +ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get(); + // + /** @var RuleGroup $group */ + foreach ($groups as $group) { + Log::debug('Now processing group "' . $group->title . '".'); + $rules = $group->rules() + ->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id') + ->where('rule_triggers.trigger_type', 'user_action') + ->where('rule_triggers.trigger_value', 'store-journal') + ->where('rules.active', 1) + ->get(['rules.*']); + /** @var Rule $rule */ + foreach ($rules as $rule) { + Log::debug('Now handling rule #' . $rule->id . ' (' . $rule->title . ')'); + $processor = new Processor($rule, $event->journal); + + // get some return out of this? + $processor->handle(); + + if ($rule->stop_processing) { + break; + } + + } + } + // echo 'Done processing rules. See log.'; + // exit; + } +} \ No newline at end of file diff --git a/app/Handlers/Events/FireRulesForUpdate.php b/app/Handlers/Events/FireRulesForUpdate.php new file mode 100644 index 0000000000..6e891626fc --- /dev/null +++ b/app/Handlers/Events/FireRulesForUpdate.php @@ -0,0 +1,74 @@ +ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get(); + // + /** @var RuleGroup $group */ + foreach ($groups as $group) { + Log::debug('Now processing group "' . $group->title . '".'); + $rules = $group->rules() + ->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id') + ->where('rule_triggers.trigger_type', 'user_action') + ->where('rule_triggers.trigger_value', 'update-journal') + ->where('rules.active', 1) + ->get(['rules.*']); + /** @var Rule $rule */ + foreach ($rules as $rule) { + Log::debug('Now handling rule #' . $rule->id . ' (' . $rule->title . ')'); + $processor = new Processor($rule, $event->journal); + + // get some return out of this? + $processor->handle(); + + if ($rule->stop_processing) { + break; + } + + } + } + } +} \ No newline at end of file diff --git a/app/Handlers/Events/RescanJournal.php b/app/Handlers/Events/RescanJournal.php index 02926a1102..d8717803a6 100644 --- a/app/Handlers/Events/RescanJournal.php +++ b/app/Handlers/Events/RescanJournal.php @@ -1,6 +1,6 @@ journal; diff --git a/app/Handlers/Events/ScanForBillsAfterStore.php b/app/Handlers/Events/ScanForBillsAfterStore.php new file mode 100644 index 0000000000..26f807fac1 --- /dev/null +++ b/app/Handlers/Events/ScanForBillsAfterStore.php @@ -0,0 +1,61 @@ +journal; + + Log::debug('Triggered saved event for journal #' . $journal->id . ' (' . $journal->description . ')'); + + /** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */ + $repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface'); + $list = $journal->user->bills()->where('active', 1)->where('automatch', 1)->get(); + + Log::debug('Found ' . $list->count() . ' bills to check.'); + + /** @var \FireflyIII\Models\Bill $bill */ + foreach ($list as $bill) { + Log::debug('Now calling bill #' . $bill->id . ' (' . $bill->name . ')'); + $repository->scan($bill, $journal); + } + + Log::debug('Done!'); + } + +} diff --git a/app/Handlers/Events/ScanForBillsAfterUpdate.php b/app/Handlers/Events/ScanForBillsAfterUpdate.php new file mode 100644 index 0000000000..424e1c0e84 --- /dev/null +++ b/app/Handlers/Events/ScanForBillsAfterUpdate.php @@ -0,0 +1,61 @@ +journal; + + Log::debug('Triggered saved event for journal #' . $journal->id . ' (' . $journal->description . ')'); + + /** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */ + $repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface'); + $list = $journal->user->bills()->where('active', 1)->where('automatch', 1)->get(); + + Log::debug('Found ' . $list->count() . ' bills to check.'); + + /** @var \FireflyIII\Models\Bill $bill */ + foreach ($list as $bill) { + Log::debug('Now calling bill #' . $bill->id . ' (' . $bill->name . ')'); + $repository->scan($bill, $journal); + } + + Log::debug('Done!'); + } + +} diff --git a/app/Handlers/Events/UpdateJournalConnection.php b/app/Handlers/Events/UpdateJournalConnection.php index 768a85f5bf..e04b44f088 100644 --- a/app/Handlers/Events/UpdateJournalConnection.php +++ b/app/Handlers/Events/UpdateJournalConnection.php @@ -1,6 +1,6 @@ journal; diff --git a/app/Helpers/Attachments/AttachmentHelper.php b/app/Helpers/Attachments/AttachmentHelper.php index 981a1a0a8a..692287d0f7 100644 --- a/app/Helpers/Attachments/AttachmentHelper.php +++ b/app/Helpers/Attachments/AttachmentHelper.php @@ -19,14 +19,14 @@ use Symfony\Component\HttpFoundation\File\UploadedFile; class AttachmentHelper implements AttachmentHelperInterface { - /** @var int */ - protected $maxUploadSize; - /** @var array */ - protected $allowedMimes; /** @var MessageBag */ public $errors; /** @var MessageBag */ public $messages; + /** @var array */ + protected $allowedMimes; + /** @var int */ + protected $maxUploadSize; /** * @@ -51,6 +51,22 @@ class AttachmentHelper implements AttachmentHelperInterface return $path; } + /** + * @return MessageBag + */ + public function getErrors() + { + return $this->errors; + } + + /** + * @return MessageBag + */ + public function getMessages() + { + return $this->messages; + } + /** * @param Model $model * @@ -98,27 +114,6 @@ class AttachmentHelper implements AttachmentHelperInterface return false; } - /** - * @param UploadedFile $file - * @param Model $model - * - * @return bool - */ - protected function validateUpload(UploadedFile $file, Model $model) - { - if (!$this->validMime($file)) { - return false; - } - if (!$this->validSize($file)) { - return false; - } - if ($this->hasFile($file, $model)) { - return false; - } - - return true; - } - /** * @param UploadedFile $file * @param Model $model @@ -205,19 +200,24 @@ class AttachmentHelper implements AttachmentHelperInterface } /** - * @return MessageBag + * @param UploadedFile $file + * @param Model $model + * + * @return bool */ - public function getErrors() + protected function validateUpload(UploadedFile $file, Model $model) { - return $this->errors; - } + if (!$this->validMime($file)) { + return false; + } + if (!$this->validSize($file)) { + return false; + } + if ($this->hasFile($file, $model)) { + return false; + } - /** - * @return MessageBag - */ - public function getMessages() - { - return $this->messages; + return true; } diff --git a/app/Helpers/Attachments/AttachmentHelperInterface.php b/app/Helpers/Attachments/AttachmentHelperInterface.php index f25971a173..bcc36a642f 100644 --- a/app/Helpers/Attachments/AttachmentHelperInterface.php +++ b/app/Helpers/Attachments/AttachmentHelperInterface.php @@ -15,11 +15,11 @@ interface AttachmentHelperInterface { /** - * @param Model $model + * @param Attachment $attachment * - * @return bool + * @return mixed */ - public function saveAttachmentsForModel(Model $model); + public function getAttachmentLocation(Attachment $attachment); /** * @return MessageBag @@ -32,10 +32,10 @@ interface AttachmentHelperInterface public function getMessages(); /** - * @param Attachment $attachment + * @param Model $model * - * @return mixed + * @return bool */ - public function getAttachmentLocation(Attachment $attachment); + public function saveAttachmentsForModel(Model $model); } diff --git a/app/Helpers/Csv/Converter/Amount.php b/app/Helpers/Csv/Converter/Amount.php index bbad0932a0..7ec25ce17e 100644 --- a/app/Helpers/Csv/Converter/Amount.php +++ b/app/Helpers/Csv/Converter/Amount.php @@ -2,8 +2,6 @@ namespace FireflyIII\Helpers\Csv\Converter; -use FireflyIII\Models\Account; - /** * Class Amount * @@ -13,7 +11,7 @@ class Amount extends BasicConverter implements ConverterInterface { /** - * @return Account|null + * @return string|int */ public function convert() { diff --git a/app/Helpers/Csv/Converter/AmountComma.php b/app/Helpers/Csv/Converter/AmountComma.php new file mode 100644 index 0000000000..5fed5587b9 --- /dev/null +++ b/app/Helpers/Csv/Converter/AmountComma.php @@ -0,0 +1,28 @@ +value); + + if (is_numeric($value)) { + return floatval($value); + } + + return 0; + } +} diff --git a/app/Helpers/Csv/Converter/BasicConverter.php b/app/Helpers/Csv/Converter/BasicConverter.php index bdfb3c2612..2c7bff6f2a 100644 --- a/app/Helpers/Csv/Converter/BasicConverter.php +++ b/app/Helpers/Csv/Converter/BasicConverter.php @@ -18,8 +18,6 @@ class BasicConverter /** @var array */ protected $mapped; /** @var string */ - protected $role; - /** @var string */ protected $value; /** @@ -86,22 +84,6 @@ class BasicConverter $this->mapped = $mapped; } - /** - * @return string - */ - public function getRole() - { - return $this->role; - } - - /** - * @param string $role - */ - public function setRole($role) - { - $this->role = $role; - } - /** * @return string */ diff --git a/app/Helpers/Csv/Converter/BudgetId.php b/app/Helpers/Csv/Converter/BudgetId.php index 1025a289a2..5fa10d1fb0 100644 --- a/app/Helpers/Csv/Converter/BudgetId.php +++ b/app/Helpers/Csv/Converter/BudgetId.php @@ -5,7 +5,7 @@ use Auth; use FireflyIII\Models\Budget; /** - * Class AccountId + * Class BudgetId * * @package FireflyIII\Helpers\Csv\Converter */ diff --git a/app/Helpers/Csv/Converter/CategoryName.php b/app/Helpers/Csv/Converter/CategoryName.php index 52e371ad58..54fa5b72f7 100644 --- a/app/Helpers/Csv/Converter/CategoryName.php +++ b/app/Helpers/Csv/Converter/CategoryName.php @@ -24,7 +24,7 @@ class CategoryName extends BasicConverter implements ConverterInterface $category = Category::firstOrCreateEncrypted( [ 'name' => $this->value, - 'user_id' => Auth::user()->id + 'user_id' => Auth::user()->id, ] ); } diff --git a/app/Helpers/Csv/Converter/ConverterInterface.php b/app/Helpers/Csv/Converter/ConverterInterface.php index cb7aebcade..1eb2e37db9 100644 --- a/app/Helpers/Csv/Converter/ConverterInterface.php +++ b/app/Helpers/Csv/Converter/ConverterInterface.php @@ -36,11 +36,6 @@ interface ConverterInterface */ public function setMapped($mapped); - /** - * @param string $role - */ - public function setRole($role); - /** * @param string $value */ diff --git a/app/Helpers/Csv/Converter/CurrencyCode.php b/app/Helpers/Csv/Converter/CurrencyCode.php index 598bd4bd5e..c17d675457 100644 --- a/app/Helpers/Csv/Converter/CurrencyCode.php +++ b/app/Helpers/Csv/Converter/CurrencyCode.php @@ -13,7 +13,7 @@ class CurrencyCode extends BasicConverter implements ConverterInterface { /** - * @return mixed|static + * @return TransactionCurrency */ public function convert() { diff --git a/app/Helpers/Csv/Converter/CurrencyId.php b/app/Helpers/Csv/Converter/CurrencyId.php index f620711bd1..25bf449850 100644 --- a/app/Helpers/Csv/Converter/CurrencyId.php +++ b/app/Helpers/Csv/Converter/CurrencyId.php @@ -13,7 +13,7 @@ class CurrencyId extends BasicConverter implements ConverterInterface { /** - * @return mixed|static + * @return TransactionCurrency */ public function convert() { diff --git a/app/Helpers/Csv/Converter/CurrencyName.php b/app/Helpers/Csv/Converter/CurrencyName.php index 549cb922f2..95c57e7d31 100644 --- a/app/Helpers/Csv/Converter/CurrencyName.php +++ b/app/Helpers/Csv/Converter/CurrencyName.php @@ -13,7 +13,7 @@ class CurrencyName extends BasicConverter implements ConverterInterface { /** - * @return mixed|static + * @return TransactionCurrency */ public function convert() { diff --git a/app/Helpers/Csv/Converter/CurrencySymbol.php b/app/Helpers/Csv/Converter/CurrencySymbol.php index c21617dc73..97184fdfb0 100644 --- a/app/Helpers/Csv/Converter/CurrencySymbol.php +++ b/app/Helpers/Csv/Converter/CurrencySymbol.php @@ -13,7 +13,7 @@ class CurrencySymbol extends BasicConverter implements ConverterInterface { /** - * @return mixed|static + * @return TransactionCurrency */ public function convert() { diff --git a/app/Helpers/Csv/Converter/Date.php b/app/Helpers/Csv/Converter/Date.php index fa6a6a8cb4..d2487ccd24 100644 --- a/app/Helpers/Csv/Converter/Date.php +++ b/app/Helpers/Csv/Converter/Date.php @@ -17,7 +17,7 @@ class Date extends BasicConverter implements ConverterInterface { /** - * @return static + * @return Carbon * @throws FireflyException */ public function convert() diff --git a/app/Helpers/Csv/Converter/Description.php b/app/Helpers/Csv/Converter/Description.php index dfd704c25f..bb5626e251 100644 --- a/app/Helpers/Csv/Converter/Description.php +++ b/app/Helpers/Csv/Converter/Description.php @@ -12,7 +12,7 @@ class Description extends BasicConverter implements ConverterInterface /** - * @return mixed + * @return string */ public function convert() { diff --git a/app/Helpers/Csv/Converter/Ignore.php b/app/Helpers/Csv/Converter/Ignore.php index d7175841bd..a9dff94088 100644 --- a/app/Helpers/Csv/Converter/Ignore.php +++ b/app/Helpers/Csv/Converter/Ignore.php @@ -2,8 +2,6 @@ namespace FireflyIII\Helpers\Csv\Converter; -use FireflyIII\Models\Account; - /** * Class Amount * @@ -13,7 +11,7 @@ class Ignore extends BasicConverter implements ConverterInterface { /** - * @return Account|null + * @return null */ public function convert() { diff --git a/app/Helpers/Csv/Converter/OpposingAccountId.php b/app/Helpers/Csv/Converter/OpposingAccountId.php index f0379d57b3..48d0cbe6e0 100644 --- a/app/Helpers/Csv/Converter/OpposingAccountId.php +++ b/app/Helpers/Csv/Converter/OpposingAccountId.php @@ -6,7 +6,7 @@ use Auth; use FireflyIII\Models\Account; /** - * Class OpposingName + * Class OpposingAccountId * * @package FireflyIII\Helpers\Csv\Converter */ diff --git a/app/Helpers/Csv/Converter/OpposingAccountName.php b/app/Helpers/Csv/Converter/OpposingAccountName.php index 01efa1c8fd..ef9e9ad97c 100644 --- a/app/Helpers/Csv/Converter/OpposingAccountName.php +++ b/app/Helpers/Csv/Converter/OpposingAccountName.php @@ -6,7 +6,7 @@ use Auth; use FireflyIII\Models\Account; /** - * Class OpposingName + * Class OpposingAccountName * * @package FireflyIII\Helpers\Csv\Converter */ diff --git a/app/Helpers/Csv/Converter/RabobankDebetCredit.php b/app/Helpers/Csv/Converter/RabobankDebetCredit.php index 933bc9e245..1861f6e172 100644 --- a/app/Helpers/Csv/Converter/RabobankDebetCredit.php +++ b/app/Helpers/Csv/Converter/RabobankDebetCredit.php @@ -13,7 +13,7 @@ class RabobankDebetCredit extends BasicConverter implements ConverterInterface /** - * @return mixed + * @return int */ public function convert() { diff --git a/app/Helpers/Csv/Converter/TagsComma.php b/app/Helpers/Csv/Converter/TagsComma.php index b854d2a09f..9356856294 100644 --- a/app/Helpers/Csv/Converter/TagsComma.php +++ b/app/Helpers/Csv/Converter/TagsComma.php @@ -3,7 +3,6 @@ namespace FireflyIII\Helpers\Csv\Converter; use Auth; -use FireflyIII\Models\Bill; use FireflyIII\Models\Tag; use Illuminate\Support\Collection; @@ -16,7 +15,7 @@ class TagsComma extends BasicConverter implements ConverterInterface { /** - * @return Bill + * @return Collection */ public function convert() { diff --git a/app/Helpers/Csv/Converter/TagsSpace.php b/app/Helpers/Csv/Converter/TagsSpace.php index 14d91a34f8..323f6005cc 100644 --- a/app/Helpers/Csv/Converter/TagsSpace.php +++ b/app/Helpers/Csv/Converter/TagsSpace.php @@ -3,7 +3,6 @@ namespace FireflyIII\Helpers\Csv\Converter; use Auth; -use FireflyIII\Models\Bill; use FireflyIII\Models\Tag; use Illuminate\Support\Collection; @@ -16,7 +15,7 @@ class TagsSpace extends BasicConverter implements ConverterInterface { /** - * @return Bill + * @return Collection */ public function convert() { diff --git a/app/Helpers/Csv/Data.php b/app/Helpers/Csv/Data.php index f77391cb37..32e1ca4477 100644 --- a/app/Helpers/Csv/Data.php +++ b/app/Helpers/Csv/Data.php @@ -1,5 +1,4 @@ sessionMapped(); $this->sessionSpecifix(); $this->sessionImportAccount(); + $this->sessionDelimiter(); + } + + /** + * + * @return string + */ + public function getCsvFileContent() + { + return $this->csvFileContent; + } + + /** + * + * @param string $csvFileContent + */ + public function setCsvFileContent($csvFileContent) + { + $this->csvFileContent = $csvFileContent; + } + + /** + * + * @return string + */ + public function getCsvFileLocation() + { + return $this->csvFileLocation; + } + + /** + * + * @param string $csvFileLocation + */ + public function setCsvFileLocation($csvFileLocation) + { + Session::put('csv-file', $csvFileLocation); + $this->csvFileLocation = $csvFileLocation; + } + + /** + * + * @return string + */ + public function getDateFormat() + { + return $this->dateFormat; + } + + /** + * + * @param mixed $dateFormat + */ + public function setDateFormat($dateFormat) + { + Session::put('csv-date-format', $dateFormat); + $this->dateFormat = $dateFormat; + } + + /** + * + * @return string + */ + public function getDelimiter() + { + return $this->delimiter; + } + + /** + * + * @param string $delimiter + */ + public function setDelimiter($delimiter) + { + Session::put('csv-delimiter', $delimiter); + $this->delimiter = $delimiter; + } + + /** + * + * @return array + */ + public function getMap() + { + return $this->map; + } + + /** + * + * @param array $map + */ + public function setMap(array $map) + { + Session::put('csv-map', $map); + $this->map = $map; + } + + /** + * + * @return array + */ + public function getMapped() + { + return $this->mapped; + } + + /** + * + * @param array $mapped + */ + public function setMapped(array $mapped) + { + Session::put('csv-mapped', $mapped); + $this->mapped = $mapped; + } + + /** + * + * @return Reader + */ + public function getReader() + { + if (strlen($this->csvFileContent) === 0) { + $this->loadCsvFile(); + } + + if (is_null($this->reader)) { + $this->reader = Reader::createFromString($this->getCsvFileContent()); + $this->reader->setDelimiter($this->delimiter); + } + + return $this->reader; + } + + /** + * + * @return array + */ + public function getRoles() + { + return $this->roles; + } + + /** + * + * @param array $roles + */ + public function setRoles(array $roles) + { + Session::put('csv-roles', $roles); + $this->roles = $roles; + } + + /** + * + * @return array + */ + public function getSpecifix() + { + return is_array($this->specifix) ? $this->specifix : []; + } + + /** + * + * @param array $specifix + */ + public function setSpecifix(array $specifix) + { + Session::put('csv-specifix', $specifix); + $this->specifix = $specifix; + } + + /** + * + * @return bool + */ + public function hasHeaders() + { + return $this->hasHeaders; + } + + /** + * + * @param bool $hasHeaders + */ + public function setHasHeaders($hasHeaders) + { + Session::put('csv-has-headers', $hasHeaders); + $this->hasHeaders = $hasHeaders; + } + + /** + * + * @param int $importAccount + */ + public function setImportAccount($importAccount) + { + Session::put('csv-import-account', $importAccount); + $this->importAccount = $importAccount; + } + + protected function loadCsvFile() + { + $file = $this->getCsvFileLocation(); + $content = file_get_contents($file); + $contentDecrypted = Crypt::decrypt($content); + $this->setCsvFileContent($contentDecrypted); + } + + protected function sessionCsvFileLocation() + { + if (Session::has('csv-file')) { + $this->csvFileLocation = (string)Session::get('csv-file'); + } + } + + protected function sessionDateFormat() + { + if (Session::has('csv-date-format')) { + $this->dateFormat = (string)Session::get('csv-date-format'); + } + } + + protected function sessionDelimiter() + { + if (Session::has('csv-delimiter')) { + $this->delimiter = Session::get('csv-delimiter'); + } } protected function sessionHasHeaders() @@ -68,20 +292,6 @@ class Data } } - protected function sessionDateFormat() - { - if (Session::has('csv-date-format')) { - $this->dateFormat = (string)Session::get('csv-date-format'); - } - } - - protected function sessionCsvFileLocation() - { - if (Session::has('csv-file')) { - $this->csvFileLocation = (string)Session::get('csv-file'); - } - } - protected function sessionMap() { if (Session::has('csv-map')) { @@ -89,13 +299,6 @@ class Data } } - protected function sessionRoles() - { - if (Session::has('csv-roles')) { - $this->roles = (array)Session::get('csv-roles'); - } - } - protected function sessionMapped() { if (Session::has('csv-mapped')) { @@ -103,181 +306,17 @@ class Data } } + protected function sessionRoles() + { + if (Session::has('csv-roles')) { + $this->roles = (array)Session::get('csv-roles'); + } + } + protected function sessionSpecifix() { if (Session::has('csv-specifix')) { $this->specifix = (array)Session::get('csv-specifix'); } } - - /** - * @return string - */ - public function getDateFormat() - { - return $this->dateFormat; - } - - /** - * @param mixed $dateFormat - */ - public function setDateFormat($dateFormat) - { - Session::put('csv-date-format', $dateFormat); - $this->dateFormat = $dateFormat; - } - - /** - * @param int $importAccount - */ - public function setImportAccount($importAccount) - { - Session::put('csv-import-account', $importAccount); - $this->importAccount = $importAccount; - } - - /** - * @return bool - */ - public function hasHeaders() - { - return $this->hasHeaders; - } - - /** - * @param bool $hasHeaders - */ - public function setHasHeaders($hasHeaders) - { - Session::put('csv-has-headers', $hasHeaders); - $this->hasHeaders = $hasHeaders; - } - - /** - * @return array - */ - public function getMap() - { - return $this->map; - } - - /** - * @param array $map - */ - public function setMap(array $map) - { - Session::put('csv-map', $map); - $this->map = $map; - } - - /** - * @return array - */ - public function getMapped() - { - return $this->mapped; - } - - /** - * @param array $mapped - */ - public function setMapped(array $mapped) - { - Session::put('csv-mapped', $mapped); - $this->mapped = $mapped; - } - - /** - * @return Reader - */ - public function getReader() - { - - if (strlen($this->csvFileContent) === 0) { - $this->loadCsvFile(); - } - - if (is_null($this->reader)) { - $this->reader = Reader::createFromString($this->getCsvFileContent()); - } - - return $this->reader; - } - - protected function loadCsvFile() - { - $file = $this->getCsvFileLocation(); - $content = file_get_contents($file); - $contentDecrypted = Crypt::decrypt($content); - $this->setCsvFileContent($contentDecrypted); - } - - /** - * @return string - */ - public function getCsvFileLocation() - { - return $this->csvFileLocation; - } - - /** - * @param string $csvFileLocation - */ - public function setCsvFileLocation($csvFileLocation) - { - Session::put('csv-file', $csvFileLocation); - $this->csvFileLocation = $csvFileLocation; - } - - /** - * @return string - */ - public function getCsvFileContent() - { - return $this->csvFileContent; - } - - /** - * @param string $csvFileContent - */ - public function setCsvFileContent($csvFileContent) - { - $this->csvFileContent = $csvFileContent; - } - - /** - * @return array - */ - public function getRoles() - { - return $this->roles; - } - - /** - * @param array $roles - */ - public function setRoles(array $roles) - { - Session::put('csv-roles', $roles); - $this->roles = $roles; - } - - /** - * @return array - */ - public function getSpecifix() - { - return is_array($this->specifix) ? $this->specifix : []; - } - - /** - * @param array $specifix - */ - public function setSpecifix($specifix) - { - Session::put('csv-specifix', $specifix); - $this->specifix = $specifix; - } - - } diff --git a/app/Helpers/Csv/Importer.php b/app/Helpers/Csv/Importer.php index 936cee2956..963b615027 100644 --- a/app/Helpers/Csv/Importer.php +++ b/app/Helpers/Csv/Importer.php @@ -34,6 +34,8 @@ class Importer protected $importRow; /** @var int */ protected $imported = 0; + /** @var Collection */ + protected $journals; /** @var array */ protected $map; /** @var array */ @@ -45,9 +47,6 @@ class Importer /** @var array */ protected $specifix = []; - /** @var Collection */ - protected $journals; - /** * Used by CsvController. * @@ -68,6 +67,14 @@ class Importer return $this->imported; } + /** + * @return Collection + */ + public function getJournals() + { + return $this->journals; + } + /** * Used by CsvController * @@ -79,14 +86,13 @@ class Importer } /** - * @return Collection + * @return array */ - public function getJournals() + public function getSpecifix() { - return $this->journals; + return is_array($this->specifix) ? $this->specifix : []; } - /** * @throws FireflyException */ @@ -118,136 +124,11 @@ class Importer } /** - * @param int $index - * - * @return bool + * @param Data $data */ - protected function parseRow($index) + public function setData($data) { - return (($this->data->hasHeaders() && $index >= 1) || !$this->data->hasHeaders()); - } - - /** - * @param $row - * - * @throws FireflyException - * @return string|bool - */ - protected function importRow($row) - { - - $data = $this->getFiller(); // These fields are necessary to create a new transaction journal. Some are optional - foreach ($row as $index => $value) { - $role = isset($this->roles[$index]) ? $this->roles[$index] : '_ignore'; - $class = Config::get('csv.roles.' . $role . '.converter'); - $field = Config::get('csv.roles.' . $role . '.field'); - - Log::debug('Column #' . $index . ' (role: ' . $role . ') : converter ' . $class . ' stores its data into field ' . $field . ':'); - - /** @var ConverterInterface $converter */ - $converter = app('FireflyIII\Helpers\Csv\Converter\\' . $class); - $converter->setData($data); // the complete array so far. - $converter->setField($field); - $converter->setIndex($index); - $converter->setMapped($this->mapped); - $converter->setValue($value); - $converter->setRole($role); - $data[$field] = $converter->convert(); - } - // move to class vars. - $this->importData = $data; - $this->importRow = $row; - unset($data, $row); - // post processing and validating. - $this->postProcess(); - $result = $this->validateData(); - - if (!($result === true)) { - return $result; // return error. - } - $journal = $this->createTransactionJournal(); - - return $journal; - } - - /** - * @return array - */ - protected function getFiller() - { - $filler = []; - foreach (Config::get('csv.roles') as $role) { - if (isset($role['field'])) { - $fieldName = $role['field']; - $filler[$fieldName] = null; - } - } - // some extra's: - $filler['bill-id'] = null; - $filler['opposing-account-object'] = null; - $filler['asset-account-object'] = null; - $filler['amount-modifier'] = '1'; - - return $filler; - - } - - /** - * Row denotes the original data. - * - * @return void - */ - protected function postProcess() - { - // do bank specific fixes (must be enabled but now all of them. - - foreach ($this->getSpecifix() as $className) { - /** @var SpecifixInterface $specifix */ - $specifix = app('FireflyIII\Helpers\Csv\Specifix\\' . $className); - $specifix->setData($this->importData); - $specifix->setRow($this->importRow); - Log::debug('Now post-process specifix named ' . $className . ':'); - $this->importData = $specifix->fix(); - } - - - $set = Config::get('csv.post_processors'); - foreach ($set as $className) { - /** @var PostProcessorInterface $postProcessor */ - $postProcessor = app('FireflyIII\Helpers\Csv\PostProcessing\\' . $className); - $postProcessor->setData($this->importData); - Log::debug('Now post-process processor named ' . $className . ':'); - $this->importData = $postProcessor->process(); - } - - } - - /** - * @return array - */ - public function getSpecifix() - { - return is_array($this->specifix) ? $this->specifix : []; - } - - /** - * - * @return bool|string - */ - protected function validateData() - { - if (is_null($this->importData['date']) && is_null($this->importData['date-rent'])) { - return 'No date value for this row.'; - } - if (is_null($this->importData['opposing-account-object'])) { - return 'Opposing account is null'; - } - - if (!($this->importData['asset-account-object'] instanceof Account)) { - return 'No asset account to import into.'; - } - - return true; + $this->data = $data; } /** @@ -309,6 +190,28 @@ class Importer return $journal; } + /** + * @return array + */ + protected function getFiller() + { + $filler = []; + foreach (Config::get('csv.roles') as $role) { + if (isset($role['field'])) { + $fieldName = $role['field']; + $filler[$fieldName] = null; + } + } + // some extra's: + $filler['bill-id'] = null; + $filler['opposing-account-object'] = null; + $filler['asset-account-object'] = null; + $filler['amount-modifier'] = '1'; + + return $filler; + + } + /** * @return TransactionType */ @@ -326,6 +229,92 @@ class Importer return $transactionType; } + /** + * @param $row + * + * @throws FireflyException + * @return string|bool + */ + protected function importRow($row) + { + + $data = $this->getFiller(); // These fields are necessary to create a new transaction journal. Some are optional + foreach ($row as $index => $value) { + $role = isset($this->roles[$index]) ? $this->roles[$index] : '_ignore'; + $class = Config::get('csv.roles.' . $role . '.converter'); + $field = Config::get('csv.roles.' . $role . '.field'); + + Log::debug('Column #' . $index . ' (role: ' . $role . ') : converter ' . $class . ' stores its data into field ' . $field . ':'); + + // here would be the place where preprocessors would fire. + + /** @var ConverterInterface $converter */ + $converter = app('FireflyIII\Helpers\Csv\Converter\\' . $class); + $converter->setData($data); // the complete array so far. + $converter->setField($field); + $converter->setIndex($index); + $converter->setMapped($this->mapped); + $converter->setValue($value); + $data[$field] = $converter->convert(); + } + // move to class vars. + $this->importData = $data; + $this->importRow = $row; + unset($data, $row); + // post processing and validating. + $this->postProcess(); + $result = $this->validateData(); + + if (!($result === true)) { + return $result; // return error. + } + $journal = $this->createTransactionJournal(); + + return $journal; + } + + /** + * @param int $index + * + * @return bool + */ + protected function parseRow($index) + { + return (($this->data->hasHeaders() && $index >= 1) || !$this->data->hasHeaders()); + } + + /** + * Row denotes the original data. + * + * @return void + */ + protected function postProcess() + { + // do bank specific fixes (must be enabled but now all of them. + + foreach ($this->getSpecifix() as $className) { + /** @var SpecifixInterface $specifix */ + $specifix = app('FireflyIII\Helpers\Csv\Specifix\\' . $className); + if ($specifix->getProcessorType() == SpecifixInterface::POST_PROCESSOR) { + $specifix->setData($this->importData); + $specifix->setRow($this->importRow); + Log::debug('Now post-process specifix named ' . $className . ':'); + $this->importData = $specifix->fix(); + } + } + + + $set = Config::get('csv.post_processors'); + foreach ($set as $className) { + /** @var PostProcessorInterface $postProcessor */ + $postProcessor = app('FireflyIII\Helpers\Csv\PostProcessing\\' . $className); + $postProcessor->setData($this->importData); + Log::debug('Now post-process processor named ' . $className . ':'); + $this->importData = $postProcessor->process(); + } + + } + /** * @param TransactionJournal $journal */ @@ -361,11 +350,23 @@ class Importer } /** - * @param Data $data + * + * @return bool|string */ - public function setData($data) + protected function validateData() { - $this->data = $data; + if (is_null($this->importData['date']) && is_null($this->importData['date-rent'])) { + return 'No date value for this row.'; + } + if (is_null($this->importData['opposing-account-object'])) { + return 'Opposing account is null'; + } + + if (!($this->importData['asset-account-object'] instanceof Account)) { + return 'No asset account to import into.'; + } + + return true; } } diff --git a/app/Helpers/Csv/PostProcessing/PostProcessorInterface.php b/app/Helpers/Csv/PostProcessing/PostProcessorInterface.php index da9877cc8b..88c0b60559 100644 --- a/app/Helpers/Csv/PostProcessing/PostProcessorInterface.php +++ b/app/Helpers/Csv/PostProcessing/PostProcessorInterface.php @@ -1,10 +1,4 @@ setProcessorType(self::POST_PROCESSOR); + } + + + /** + * @return array + */ + public function fix() + { + // Try to parse the description in known formats. + $parsed = $this->parseSepaDescription() || $this->parseTRTPDescription() || $this->parseGEABEADescription() || $this->parseABNAMRODescription(); + + // If the description could not be parsed, specify an unknown opposing + // account, as an opposing account is required + if (!$parsed) { + $this->data['opposing-account-name'] = trans('firefly.unknown'); + } + + return $this->data; + } + + /** + * @param array $data + */ + public function setData($data) + { + $this->data = $data; + } + + /** + * @param array $row + */ + public function setRow($row) + { + $this->row = $row; + } + + /** + * Parses the current description with costs from ABN AMRO itself + * + * @return boolean true if the description is GEA/BEA-format, false otherwise + */ + protected function parseABNAMRODescription() + { + // See if the current description is formatted in ABN AMRO format + if (preg_match('/ABN AMRO.{24} (.*)/', $this->data['description'], $matches)) { + Log::debug('AbnAmroSpecifix: Description is structured as costs from ABN AMRO itself.'); + + $this->data['opposing-account-name'] = "ABN AMRO"; + $this->data['description'] = $matches[1]; + + return true; + } + + return false; + } + + /** + * Parses the current description in GEA/BEA format + * + * @return boolean true if the description is GEA/BEAformat, false otherwise + */ + protected function parseGEABEADescription() + { + // See if the current description is formatted in GEA/BEA format + if (preg_match('/([BG]EA) +(NR:[a-zA-Z:0-9]+) +([0-9.\/]+) +([^,]*)/', $this->data['description'], $matches)) { + Log::debug('AbnAmroSpecifix: Description is structured as GEA or BEA format.'); + + // description and opposing account will be the same. + $this->data['opposing-account-name'] = $matches[4]; + $this->data['description'] = $matches[4]; + + return true; + } + + return false; + } + + /** + * Parses the current description in SEPA format + * + * @return boolean true if the description is SEPA format, false otherwise + */ + protected function parseSepaDescription() + { + // See if the current description is formatted as a SEPA plain description + if (preg_match('/^SEPA(.{28})/', $this->data['description'], $matches)) { + Log::debug('AbnAmroSpecifix: Description is structured as SEPA plain description.'); + + // SEPA plain descriptions contain several key-value pairs, split by a colon + preg_match_all('/([A-Za-z]+(?=:\s)):\s([A-Za-z 0-9._#-]+(?=\s))/', $this->data['description'], $matches, PREG_SET_ORDER); + + foreach ($matches as $match) { + $key = $match[1]; + $value = trim($match[2]); + + switch (strtoupper($key)) { + case 'OMSCHRIJVING': + $this->data['description'] = $value; + break; + case 'NAAM': + $this->data['opposing-account-name'] = $value; + break; + case 'IBAN': + $this->data['opposing-account-iban'] = $value; + break; + default: + // Ignore the rest + } + } + + return true; + } + + return false; + } + + /** + * Parses the current description in TRTP format + * + * @return boolean true if the description is TRTP format, false otherwise + */ + protected function parseTRTPDescription() + { + // See if the current description is formatted in TRTP format + if (preg_match_all('!\/([A-Z]{3,4})\/([^/]*)!', $this->data['description'], $matches, PREG_SET_ORDER)) { + Log::debug('AbnAmroSpecifix: Description is structured as TRTP format.'); + + foreach ($matches as $match) { + $key = $match[1]; + $value = trim($match[2]); + + switch (strtoupper($key)) { + // is not being used. + // case 'TRTP': + // $type = $value; + // break; + case 'NAME': + $this->data['opposing-account-name'] = $value; + break; + case 'REMI': + $this->data['description'] = $value; + break; + case 'IBAN': + $this->data['opposing-account-iban'] = $value; + break; + default: + // Ignore the rest + } + } + + return true; + } + + return false; + } + +} diff --git a/app/Helpers/Csv/Specifix/Dummy.php b/app/Helpers/Csv/Specifix/Dummy.php index ad2a7c0b58..915e87bd37 100644 --- a/app/Helpers/Csv/Specifix/Dummy.php +++ b/app/Helpers/Csv/Specifix/Dummy.php @@ -7,7 +7,7 @@ namespace FireflyIII\Helpers\Csv\Specifix; * * @package FireflyIII\Helpers\Csv\Specifix */ -class Dummy +class Dummy extends Specifix implements SpecifixInterface { /** @var array */ protected $data; @@ -15,6 +15,13 @@ class Dummy /** @var array */ protected $row; + /** + * Dummy constructor. + */ + public function __construct() + { + $this->setProcessorType(self::POST_PROCESSOR); + } /** * @return array diff --git a/app/Helpers/Csv/Specifix/RabobankDescription.php b/app/Helpers/Csv/Specifix/RabobankDescription.php index 426688d758..a8fced085a 100644 --- a/app/Helpers/Csv/Specifix/RabobankDescription.php +++ b/app/Helpers/Csv/Specifix/RabobankDescription.php @@ -9,7 +9,7 @@ use Log; * * @package FireflyIII\Helpers\Csv\Specifix */ -class RabobankDescription +class RabobankDescription extends Specifix implements SpecifixInterface { /** @var array */ protected $data; @@ -17,6 +17,14 @@ class RabobankDescription /** @var array */ protected $row; + /** + * RabobankDescription constructor. + */ + public function __construct() + { + $this->setProcessorType(self::POST_PROCESSOR); + } + /** * @return array diff --git a/app/Helpers/Csv/Specifix/Specifix.php b/app/Helpers/Csv/Specifix/Specifix.php new file mode 100644 index 0000000000..627ba651ca --- /dev/null +++ b/app/Helpers/Csv/Specifix/Specifix.php @@ -0,0 +1,44 @@ +processorType; + } + + /** + * @param $processorType + * + * @return $this + */ + public function setProcessorType($processorType) + { + $this->processorType = $processorType; + + return $this; + } + + +} \ No newline at end of file diff --git a/app/Helpers/Csv/Specifix/SpecifixInterface.php b/app/Helpers/Csv/Specifix/SpecifixInterface.php index 142d224c4d..34e9a3e833 100644 --- a/app/Helpers/Csv/Specifix/SpecifixInterface.php +++ b/app/Helpers/Csv/Specifix/SpecifixInterface.php @@ -8,16 +8,30 @@ namespace FireflyIII\Helpers\Csv\Specifix; */ interface SpecifixInterface { + const PRE_PROCESSOR = 1; + const POST_PROCESSOR = 2; /** * Implement bank and locale related fixes. */ public function fix(); + /** + * @return int + */ + public function getProcessorType(); + /** * @param array $data */ public function setData($data); + /** + * @param int $processorType + * + * @return $this + */ + public function setProcessorType($processorType); + /** * @param array $row */ diff --git a/app/Helpers/Csv/Wizard.php b/app/Helpers/Csv/Wizard.php index 148934ee60..bf93c16ec8 100644 --- a/app/Helpers/Csv/Wizard.php +++ b/app/Helpers/Csv/Wizard.php @@ -63,7 +63,8 @@ class Wizard implements WizardInterface if (is_array($map)) { - foreach ($map as $index => $field) { + $keys = array_keys($map); + foreach ($keys as $index) { if (isset($roles[$index])) { $name = $roles[$index]; if ($configRoles[$name]['mappable']) { @@ -167,17 +168,6 @@ class Wizard implements WizardInterface } - /** - * @param bool $hasHeaders - * @param int $index - * - * @return bool - */ - protected function useRow($hasHeaders, $index) - { - return ($hasHeaders && $index > 1) || !$hasHeaders; - } - /** * @param array $array * @@ -191,4 +181,15 @@ class Wizard implements WizardInterface return $array; } + + /** + * @param bool $hasHeaders + * @param int $index + * + * @return bool + */ + protected function useRow($hasHeaders, $index) + { + return ($hasHeaders && $index > 1) || !$hasHeaders; + } } diff --git a/app/Helpers/Report/ReportHelper.php b/app/Helpers/Report/ReportHelper.php index 93b4592986..9cfccfd6f7 100644 --- a/app/Helpers/Report/ReportHelper.php +++ b/app/Helpers/Report/ReportHelper.php @@ -19,9 +19,12 @@ use FireflyIII\Helpers\Collection\Income; use FireflyIII\Models\Account; use FireflyIII\Models\Bill; use FireflyIII\Models\Budget as BudgetModel; +use FireflyIII\Models\Budget; use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\Tag; use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; +use FireflyIII\Repositories\Tag\TagRepositoryInterface; use Illuminate\Support\Collection; /** @@ -32,81 +35,27 @@ use Illuminate\Support\Collection; class ReportHelper implements ReportHelperInterface { + /** @var BudgetRepositoryInterface */ + protected $budgetRepository; /** @var ReportQueryInterface */ protected $query; + /** @var TagRepositoryInterface */ + protected $tagRepository; /** + * ReportHelper constructor. + * * @codeCoverageIgnore * - * @param ReportQueryInterface $query - * + * @param ReportQueryInterface $query + * @param BudgetRepositoryInterface $budgetRepository + * @param TagRepositoryInterface $tagRepository */ - public function __construct(ReportQueryInterface $query) + public function __construct(ReportQueryInterface $query, BudgetRepositoryInterface $budgetRepository, TagRepositoryInterface $tagRepository) { - $this->query = $query; - - } - - /** - * @param Carbon $start - * @param Carbon $end - * @param Collection $accounts - * - * @return CategoryCollection - */ - public function getCategoryReport(Carbon $start, Carbon $end, Collection $accounts) - { - $object = new CategoryCollection; - - /** - * GET CATEGORIES: - */ - /** @var \FireflyIII\Repositories\Category\CategoryRepositoryInterface $repository */ - $repository = app('FireflyIII\Repositories\Category\CategoryRepositoryInterface'); - - $set = $repository->spentForAccountsPerMonth($accounts, $start, $end); - foreach ($set as $category) { - $object->addCategory($category); - } - - return $object; - } - - /** - * @param Carbon $date - * - * @return array - */ - public function listOfMonths(Carbon $date) - { - - $start = clone $date; - $end = Carbon::now(); - $months = []; - while ($start <= $end) { - $year = $start->year; - - if (!isset($months[$year])) { - $months[$year] = [ - 'start' => Carbon::createFromDate($year, 1, 1)->format('Y-m-d'), - 'end' => Carbon::createFromDate($year, 12, 31)->format('Y-m-d'), - 'months' => [], - ]; - } - - $currentEnd = clone $start; - $currentEnd->endOfMonth(); - $months[$year]['months'][] = [ - 'formatted' => $start->formatLocalized('%B %Y'), - 'start' => $start->format('Y-m-d'), - 'end' => $currentEnd->format('Y-m-d'), - 'month' => $start->month, - 'year' => $year, - ]; - $start->addMonth(); - } - - return $months; + $this->query = $query; + $this->budgetRepository = $budgetRepository; + $this->tagRepository = $tagRepository; } /** @@ -198,47 +147,86 @@ class ReportHelper implements ReportHelperInterface } /** - * Get a full report on the users incomes during the period for the given accounts. - * * @param Carbon $start * @param Carbon $end * @param Collection $accounts * - * @return Income + * @return Balance */ - public function getIncomeReport($start, $end, Collection $accounts) + public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts) { - $object = new Income; - $set = $this->query->income($accounts, $start, $end); + $balance = new Balance; - foreach ($set as $entry) { - $object->addToTotal($entry->journalAmount); - $object->addOrCreateIncome($entry); + // build a balance header: + $header = new BalanceHeader; + $budgets = $this->budgetRepository->getBudgetsAndLimitsInRange($start, $end); + $spentData = $this->budgetRepository->spentPerBudgetPerAccount($budgets, $accounts, $start, $end); + foreach ($accounts as $account) { + $header->addAccount($account); } - return $object; + /** @var BudgetModel $budget */ + foreach ($budgets as $budget) { + $balance->addBalanceLine($this->createBalanceLine($budget, $accounts, $spentData)); + } + + $balance->addBalanceLine($this->createEmptyBalanceLine($accounts, $spentData)); + $balance->addBalanceLine($this->createTagsBalanceLine($accounts, $start, $end)); + $balance->addBalanceLine($this->createDifferenceBalanceLine($accounts, $spentData, $start, $end)); + + $balance->setBalanceHeader($header); + + return $balance; } /** - * Get a full report on the users expenses during the period for a list of accounts. + * This method generates a full report for the given period on all + * the users bills and their payments. + * + * Excludes bills which have not had a payment on the mentioned accounts. * * @param Carbon $start * @param Carbon $end * @param Collection $accounts * - * @return Expense + * @return BillCollection */ - public function getExpenseReport($start, $end, Collection $accounts) + public function getBillReport(Carbon $start, Carbon $end, Collection $accounts) { - $object = new Expense; - $set = $this->query->expense($accounts, $start, $end); + /** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */ + $repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface'); + $bills = $repository->getBillsForAccounts($accounts); + $journals = $repository->getAllJournalsInRange($bills, $start, $end); + $collection = new BillCollection; + + /** @var Bill $bill */ + foreach ($bills as $bill) { + $billLine = new BillLine; + $billLine->setBill($bill); + $billLine->setActive(intval($bill->active) == 1); + $billLine->setMin($bill->amount_min); + $billLine->setMax($bill->amount_max); + + // is hit in period? + bcscale(2); + + $entry = $journals->filter( + function (TransactionJournal $journal) use ($bill) { + return $journal->bill_id == $bill->id; + } + ); + if (!is_null($entry->first())) { + $billLine->setAmount($entry->first()->journalAmount); + $billLine->setHit(true); + } else { + $billLine->setHit(false); + } + + $collection->addBill($billLine); - foreach ($set as $entry) { - $object->addToTotal($entry->journalAmount); // can be positive, if it's a transfer - $object->addOrCreateExpense($entry); } - return $object; + return $collection; } /** @@ -325,163 +313,105 @@ class ReportHelper implements ReportHelperInterface * @param Carbon $end * @param Collection $accounts * - * @return Balance + * @return CategoryCollection */ - public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts) + public function getCategoryReport(Carbon $start, Carbon $end, Collection $accounts) { - /** @var \FireflyIII\Repositories\Budget\BudgetRepositoryInterface $repository */ - $repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $object = new CategoryCollection; - /** @var \FireflyIII\Repositories\Tag\TagRepositoryInterface $tagRepository */ - $tagRepository = app('FireflyIII\Repositories\Tag\TagRepositoryInterface'); + /** + * GET CATEGORIES: + */ + /** @var \FireflyIII\Repositories\Category\CategoryRepositoryInterface $repository */ + $repository = app('FireflyIII\Repositories\Category\CategoryRepositoryInterface'); - $balance = new Balance; - - // build a balance header: - $header = new BalanceHeader; - $budgets = $repository->getBudgetsAndLimitsInRange($start, $end); - $spentData = $repository->spentPerBudgetPerAccount($budgets, $accounts, $start, $end); - foreach ($accounts as $account) { - $header->addAccount($account); + $set = $repository->spentForAccountsPerMonth($accounts, $start, $end); + foreach ($set as $category) { + $object->addCategory($category); } - /** @var BudgetModel $budget */ - foreach ($budgets as $budget) { - $line = new BalanceLine; - $line->setBudget($budget); - - // loop accounts: - foreach ($accounts as $account) { - $balanceEntry = new BalanceEntry; - $balanceEntry->setAccount($account); - - // get spent: - $entry = $spentData->filter( - function (TransactionJournal $model) use ($budget, $account) { - return $model->account_id == $account->id && $model->budget_id == $budget->id; - } - ); - $spent = 0; - if (!is_null($entry->first())) { - $spent = $entry->first()->spent; - } - $balanceEntry->setSpent($spent); - $line->addBalanceEntry($balanceEntry); - } - // add line to balance: - $balance->addBalanceLine($line); - } - - // then a new line for without budget. - // and one for the tags: - // and one for "left unbalanced". - $empty = new BalanceLine; - $tags = new BalanceLine; - $diffLine = new BalanceLine; - $tagsLeft = $tagRepository->allCoveredByBalancingActs($accounts, $start, $end); - - $tags->setRole(BalanceLine::ROLE_TAGROLE); - $diffLine->setRole(BalanceLine::ROLE_DIFFROLE); - - foreach ($accounts as $account) { - $entry = $spentData->filter( - function (TransactionJournal $model) use ($account) { - return $model->account_id == $account->id && is_null($model->budget_id); - } - ); - $spent = 0; - if (!is_null($entry->first())) { - $spent = $entry->first()->spent; - } - $leftEntry = $tagsLeft->filter( - function (Tag $tag) use ($account) { - return $tag->account_id == $account->id; - } - ); - $left = 0; - if (!is_null($leftEntry->first())) { - $left = $leftEntry->first()->sum; - } - bcscale(2); - $diff = bcadd($spent, $left); - - // budget - $budgetEntry = new BalanceEntry; - $budgetEntry->setAccount($account); - $budgetEntry->setSpent($spent); - $empty->addBalanceEntry($budgetEntry); - - // balanced by tags - $tagEntry = new BalanceEntry; - $tagEntry->setAccount($account); - $tagEntry->setLeft($left); - $tags->addBalanceEntry($tagEntry); - - // difference: - $diffEntry = new BalanceEntry; - $diffEntry->setAccount($account); - $diffEntry->setSpent($diff); - $diffLine->addBalanceEntry($diffEntry); - - } - - $balance->addBalanceLine($empty); - $balance->addBalanceLine($tags); - $balance->addBalanceLine($diffLine); - - $balance->setBalanceHeader($header); - - return $balance; + return $object; } /** - * This method generates a full report for the given period on all - * the users bills and their payments. - * - * Excludes bills which have not had a payment on the mentioned accounts. + * Get a full report on the users expenses during the period for a list of accounts. * * @param Carbon $start * @param Carbon $end * @param Collection $accounts * - * @return BillCollection + * @return Expense */ - public function getBillReport(Carbon $start, Carbon $end, Collection $accounts) + public function getExpenseReport($start, $end, Collection $accounts) { - /** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */ - $repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface'); - $bills = $repository->getBillsForAccounts($accounts); - $journals = $repository->getAllJournalsInRange($bills, $start, $end); - $collection = new BillCollection; - - /** @var Bill $bill */ - foreach ($bills as $bill) { - $billLine = new BillLine; - $billLine->setBill($bill); - $billLine->setActive(intval($bill->active) == 1); - $billLine->setMin($bill->amount_min); - $billLine->setMax($bill->amount_max); - - // is hit in period? - bcscale(2); - - $entry = $journals->filter( - function (TransactionJournal $journal) use ($bill) { - return $journal->bill_id == $bill->id; - } - ); - if (!is_null($entry->first())) { - $billLine->setAmount($entry->first()->journalAmount); - $billLine->setHit(true); - } else { - $billLine->setHit(false); - } - - $collection->addBill($billLine); + $object = new Expense; + $set = $this->query->expense($accounts, $start, $end); + foreach ($set as $entry) { + $object->addToTotal($entry->journalAmount); // can be positive, if it's a transfer + $object->addOrCreateExpense($entry); } - return $collection; + return $object; + } + + /** + * Get a full report on the users incomes during the period for the given accounts. + * + * @param Carbon $start + * @param Carbon $end + * @param Collection $accounts + * + * @return Income + */ + public function getIncomeReport($start, $end, Collection $accounts) + { + $object = new Income; + $set = $this->query->income($accounts, $start, $end); + + foreach ($set as $entry) { + $object->addToTotal($entry->journalAmount); + $object->addOrCreateIncome($entry); + } + + return $object; + } + + /** + * @param Carbon $date + * + * @return array + */ + public function listOfMonths(Carbon $date) + { + + $start = clone $date; + $end = Carbon::now(); + $months = []; + while ($start <= $end) { + $year = $start->year; + + if (!isset($months[$year])) { + $months[$year] = [ + 'start' => Carbon::createFromDate($year, 1, 1)->format('Y-m-d'), + 'end' => Carbon::createFromDate($year, 12, 31)->format('Y-m-d'), + 'months' => [], + ]; + } + + $currentEnd = clone $start; + $currentEnd->endOfMonth(); + $months[$year]['months'][] = [ + 'formatted' => $start->formatLocalized('%B %Y'), + 'start' => $start->format('Y-m-d'), + 'end' => $currentEnd->format('Y-m-d'), + 'month' => $start->month, + 'year' => $year, + ]; + $start->addMonth(); + } + + return $months; } /** @@ -511,4 +441,157 @@ class ReportHelper implements ReportHelperInterface return $sum; } -} \ No newline at end of file + + /** + * @param Budget $budget + * @param Collection $accounts + * @param Collection $spentData + * + * @return BalanceLine + */ + private function createBalanceLine(BudgetModel $budget, Collection $accounts, Collection $spentData) + { + $line = new BalanceLine; + $line->setBudget($budget); + + // loop accounts: + foreach ($accounts as $account) { + $balanceEntry = new BalanceEntry; + $balanceEntry->setAccount($account); + + // get spent: + $entry = $spentData->filter( + function (TransactionJournal $model) use ($budget, $account) { + return $model->account_id == $account->id && $model->budget_id == $budget->id; + } + ); + $spent = 0; + if (!is_null($entry->first())) { + $spent = $entry->first()->spent; + } + $balanceEntry->setSpent($spent); + $line->addBalanceEntry($balanceEntry); + } + + return $line; + } + + /** + * @param Collection $accounts + * @param Collection $spentData + * @param Carbon $start + * @param Carbon $end + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * + * @return BalanceLine + */ + private function createDifferenceBalanceLine(Collection $accounts, Collection $spentData, Carbon $start, Carbon $end) + { + $diff = new BalanceLine; + $tagsLeft = $this->tagRepository->allCoveredByBalancingActs($accounts, $start, $end); + + $diff->setRole(BalanceLine::ROLE_DIFFROLE); + + foreach ($accounts as $account) { + $entry = $spentData->filter( + function (TransactionJournal $model) use ($account) { + return $model->account_id == $account->id && is_null($model->budget_id); + } + ); + $spent = 0; + if (!is_null($entry->first())) { + $spent = $entry->first()->spent; + } + $leftEntry = $tagsLeft->filter( + function (Tag $tag) use ($account) { + return $tag->account_id == $account->id; + } + ); + $left = 0; + if (!is_null($leftEntry->first())) { + $left = $leftEntry->first()->sum; + } + bcscale(2); + $diffValue = bcadd($spent, $left); + + // difference: + $diffEntry = new BalanceEntry; + $diffEntry->setAccount($account); + $diffEntry->setSpent($diffValue); + $diff->addBalanceEntry($diffEntry); + + } + + return $diff; + } + + /** + * @param Collection $accounts + * @param Collection $spentData + * + * @return BalanceLine + */ + private function createEmptyBalanceLine(Collection $accounts, Collection $spentData) + { + $empty = new BalanceLine; + + foreach ($accounts as $account) { + $entry = $spentData->filter( + function (TransactionJournal $model) use ($account) { + return $model->account_id == $account->id && is_null($model->budget_id); + } + ); + $spent = 0; + if (!is_null($entry->first())) { + $spent = $entry->first()->spent; + } + + // budget + $budgetEntry = new BalanceEntry; + $budgetEntry->setAccount($account); + $budgetEntry->setSpent($spent); + $empty->addBalanceEntry($budgetEntry); + + } + + return $empty; + } + + /** + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return BalanceLine + */ + private function createTagsBalanceLine(Collection $accounts, Carbon $start, Carbon $end) + { + $tags = new BalanceLine; + $tagsLeft = $this->tagRepository->allCoveredByBalancingActs($accounts, $start, $end); + + $tags->setRole(BalanceLine::ROLE_TAGROLE); + + foreach ($accounts as $account) { + $leftEntry = $tagsLeft->filter( + function (Tag $tag) use ($account) { + return $tag->account_id == $account->id; + } + ); + $left = 0; + if (!is_null($leftEntry->first())) { + $left = $leftEntry->first()->sum; + } + bcscale(2); + + // balanced by tags + $tagEntry = new BalanceEntry; + $tagEntry->setAccount($account); + $tagEntry->setLeft($left); + $tags->addBalanceEntry($tagEntry); + + } + + return $tags; + } +} diff --git a/app/Helpers/Report/ReportHelperInterface.php b/app/Helpers/Report/ReportHelperInterface.php index f52036cac2..9759d755d7 100644 --- a/app/Helpers/Report/ReportHelperInterface.php +++ b/app/Helpers/Report/ReportHelperInterface.php @@ -32,6 +32,15 @@ interface ReportHelperInterface */ public function getAccountReport(Carbon $start, Carbon $end, Collection $accounts); + /** + * @param Carbon $start + * @param Carbon $end + * @param Collection $accounts + * + * @return Balance + */ + public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts); + /** * This method generates a full report for the given period on all * the users bills and their payments. @@ -46,15 +55,6 @@ interface ReportHelperInterface */ public function getBillReport(Carbon $start, Carbon $end, Collection $accounts); - /** - * @param Carbon $start - * @param Carbon $end - * @param Collection $accounts - * - * @return Balance - */ - public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts); - /** * @param Carbon $start * @param Carbon $end diff --git a/app/Helpers/Report/ReportQuery.php b/app/Helpers/Report/ReportQuery.php index 24fa89dc7d..24027b2e0c 100644 --- a/app/Helpers/Report/ReportQuery.php +++ b/app/Helpers/Report/ReportQuery.php @@ -17,51 +17,6 @@ use Illuminate\Support\Collection; class ReportQuery implements ReportQueryInterface { - /** - * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers) - * grouped by month like so: "2015-01" => '123.45' - * - * @param Collection $accounts - * @param Carbon $start - * @param Carbon $end - * - * @return array - */ - public function spentPerMonth(Collection $accounts, Carbon $start, Carbon $end) - { - $ids = $accounts->pluck('id')->toArray(); - $query = Auth::user()->transactionjournals() - ->leftJoin( - 'transactions AS t_from', function (JoinClause $join) { - $join->on('transaction_journals.id', '=', 't_from.transaction_journal_id')->where('t_from.amount', '<', 0); - } - ) - ->leftJoin( - 'transactions AS t_to', function (JoinClause $join) { - $join->on('transaction_journals.id', '=', 't_to.transaction_journal_id')->where('t_to.amount', '>', 0); - } - ) - ->whereIn('t_from.account_id', $ids) - ->whereNotIn('t_to.account_id', $ids) - ->after($start) - ->before($end) - ->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]) - ->groupBy('dateFormatted') - ->get( - [ - DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") AS `dateFormatted`'), - DB::Raw('SUM(`t_from`.`amount`) AS `sum`') - ] - ); - $array = []; - foreach ($query as $result) { - $array[$result->dateFormatted] = $result->sum; - } - - return $array; - - } - /** * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers) * grouped by month like so: "2015-01" => '123.45' @@ -95,7 +50,7 @@ class ReportQuery implements ReportQueryInterface ->get( [ DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") AS `dateFormatted`'), - DB::Raw('SUM(`t_to`.`amount`) AS `sum`') + DB::Raw('SUM(`t_to`.`amount`) AS `sum`'), ] ); $array = []; @@ -106,6 +61,41 @@ class ReportQuery implements ReportQueryInterface return $array; } + /** + * This method returns all the "out" transaction journals for the given account and given period. The amount + * is stored in "journalAmount". + * + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function expense(Collection $accounts, Carbon $start, Carbon $end) + { + $ids = $accounts->pluck('id')->toArray(); + $set = Auth::user()->transactionjournals() + ->leftJoin( + 'transactions as t_from', function (JoinClause $join) { + $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); + } + ) + ->leftJoin( + 'transactions as t_to', function (JoinClause $join) { + $join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0); + } + ) + ->leftJoin('accounts', 't_to.account_id', '=', 'accounts.id') + ->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]) + ->before($end) + ->after($start) + ->whereIn('t_from.account_id', $ids) + ->whereNotIn('t_to.account_id', $ids) + ->get(['transaction_journals.*', 't_from.amount as journalAmount', 'accounts.id as account_id', 'accounts.name as account_name']); + + return $set; + } + /** * This method returns all the "in" transaction journals for the given account and given period. The amount * is stored in "journalAmount". @@ -142,37 +132,47 @@ class ReportQuery implements ReportQueryInterface } /** - * This method returns all the "out" transaction journals for the given account and given period. The amount - * is stored in "journalAmount". + * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers) + * grouped by month like so: "2015-01" => '123.45' * * @param Collection $accounts * @param Carbon $start * @param Carbon $end * - * @return Collection + * @return array */ - public function expense(Collection $accounts, Carbon $start, Carbon $end) + public function spentPerMonth(Collection $accounts, Carbon $start, Carbon $end) { - $ids = $accounts->pluck('id')->toArray(); - $set = Auth::user()->transactionjournals() - ->leftJoin( - 'transactions as t_from', function (JoinClause $join) { - $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); - } - ) - ->leftJoin( - 'transactions as t_to', function (JoinClause $join) { - $join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0); - } - ) - ->leftJoin('accounts', 't_to.account_id', '=', 'accounts.id') - ->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]) - ->before($end) - ->after($start) - ->whereIn('t_from.account_id', $ids) - ->whereNotIn('t_to.account_id', $ids) - ->get(['transaction_journals.*', 't_from.amount as journalAmount', 'accounts.id as account_id', 'accounts.name as account_name']); + $ids = $accounts->pluck('id')->toArray(); + $query = Auth::user()->transactionjournals() + ->leftJoin( + 'transactions AS t_from', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 't_from.transaction_journal_id')->where('t_from.amount', '<', 0); + } + ) + ->leftJoin( + 'transactions AS t_to', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 't_to.transaction_journal_id')->where('t_to.amount', '>', 0); + } + ) + ->whereIn('t_from.account_id', $ids) + ->whereNotIn('t_to.account_id', $ids) + ->after($start) + ->before($end) + ->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]) + ->groupBy('dateFormatted') + ->get( + [ + DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") AS `dateFormatted`'), + DB::Raw('SUM(`t_from`.`amount`) AS `sum`'), + ] + ); + $array = []; + foreach ($query as $result) { + $array[$result->dateFormatted] = $result->sum; + } + + return $array; - return $set; } } diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index e018002bfc..44d210ca40 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -133,7 +133,7 @@ class AccountController extends Controller 'ccMonthlyPaymentDate' => $account->getMeta('ccMonthlyPaymentDate'), 'openingBalanceDate' => $openingBalance ? $openingBalance->date->format('Y-m-d') : null, 'openingBalance' => $openingBalanceAmount, - 'virtualBalance' => round($account->virtual_balance, 2) + 'virtualBalance' => round($account->virtual_balance, 2), ]; Session::flash('preFilled', $preFilled); Session::flash('gaEventCategory', 'accounts'); @@ -251,12 +251,10 @@ class AccountController extends Controller 'virtualBalance' => round($request->input('virtualBalance'), 2), 'openingBalance' => round($request->input('openingBalance'), 2), 'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')), - 'openingBalanceCurrency' => intval($request->input('balance_currency_id')), + 'openingBalanceCurrency' => intval($request->input('amount_currency_id_openingBalance')), 'ccType' => $request->input('ccType'), 'ccMonthlyPaymentDate' => $request->input('ccMonthlyPaymentDate'), ]; - - $repository->update($account, $accountData); Session::flash('success', 'Account "' . $account->name . '" updated.'); diff --git a/app/Http/Controllers/AttachmentController.php b/app/Http/Controllers/AttachmentController.php index 5a750ac786..22aabdf8fe 100644 --- a/app/Http/Controllers/AttachmentController.php +++ b/app/Http/Controllers/AttachmentController.php @@ -2,7 +2,6 @@ namespace FireflyIII\Http\Controllers; - use Crypt; use File; use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; @@ -11,6 +10,7 @@ use FireflyIII\Models\Attachment; use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface; use Input; use Preferences; +use Request; use Response; use Session; use URL; @@ -34,26 +34,6 @@ class AttachmentController extends Controller View::share('title', trans('firefly.attachments')); } - - /** - * @param Attachment $attachment - * - * @return \Illuminate\View\View - */ - public function edit(Attachment $attachment) - { - $subTitleIcon = 'fa-pencil'; - $subTitle = trans('firefly.edit_attachment', ['name' => $attachment->filename]); - - // put previous url in session if not redirect from store (not "return_to_edit"). - if (Session::get('attachments.edit.fromUpdate') !== true) { - Session::put('attachments.edit.url', URL::previous()); - } - Session::forget('attachments.edit.fromUpdate'); - - return view('attachments.edit', compact('attachment', 'subTitleIcon', 'subTitle')); - } - /** * @param Attachment $attachment * @@ -101,23 +81,42 @@ class AttachmentController extends Controller $quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\')); - header('Content-Description: File Transfer'); - header('Content-Type: application/octet-stream'); - header('Content-Disposition: attachment; filename=' . $quoted); - header('Content-Transfer-Encoding: binary'); - header('Connection: Keep-Alive'); - header('Expires: 0'); - header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - header('Pragma: public'); - header('Content-Length: ' . $attachment->size); + Request::header('Content-Description: File Transfer'); + Request::header('Content-Type: application/octet-stream'); + Request::header('Content-Disposition: attachment; filename=' . $quoted); + Request::header('Content-Transfer-Encoding: binary'); + Request::header('Connection: Keep-Alive'); + Request::header('Expires: 0'); + Request::header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + Request::header('Pragma: public'); + Request::header('Content-Length: ' . $attachment->size); - echo Crypt::decrypt(file_get_contents($file)); + return Crypt::decrypt(file_get_contents($file)); } else { abort(404); } } + /** + * @param Attachment $attachment + * + * @return \Illuminate\View\View + */ + public function edit(Attachment $attachment) + { + $subTitleIcon = 'fa-pencil'; + $subTitle = trans('firefly.edit_attachment', ['name' => $attachment->filename]); + + // put previous url in session if not redirect from store (not "return_to_edit"). + if (Session::get('attachments.edit.fromUpdate') !== true) { + Session::put('attachments.edit.url', URL::previous()); + } + Session::forget('attachments.edit.fromUpdate'); + + return view('attachments.edit', compact('attachment', 'subTitleIcon', 'subTitle')); + } + /** * @param Attachment $attachment * diff --git a/app/Http/Controllers/Auth/AuthController.php b/app/Http/Controllers/Auth/AuthController.php old mode 100644 new mode 100755 index c4f5ba4f9b..fb248a267b --- a/app/Http/Controllers/Auth/AuthController.php +++ b/app/Http/Controllers/Auth/AuthController.php @@ -1,7 +1,8 @@ -middleware('guest', ['except' => 'logout']); + parent::__construct(); } /** @@ -56,7 +51,7 @@ class AuthController extends Controller * * @return \Illuminate\Http\Response */ - public function postLogin(Request $request) + public function login(Request $request) { $this->validate($request, [$this->loginUsername() => 'required', 'password' => 'required',]); $throttles = $this->isUsingThrottlesLoginsTrait(); @@ -68,16 +63,19 @@ class AuthController extends Controller $credentials = $this->getCredentials($request); $credentials['blocked'] = 0; // most not be blocked. - if (Auth::attempt($credentials, $request->has('remember'))) { + if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) { + return $this->handleUserWasAuthenticated($request, $throttles); } - $message = $this->getFailedLoginMessage(); + // check if user is blocked: + $message = ''; /** @var User $foundUser */ $foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first(); if (!is_null($foundUser)) { // if it exists, show message: $code = $foundUser->blocked_code; + if (strlen($code) == 0) { $code = 'general_blocked'; } @@ -88,47 +86,17 @@ class AuthController extends Controller $this->incrementLoginAttempts($request); } - return redirect($this->loginPath()) - ->withInput($request->only($this->loginUsername(), 'remember')) - ->withErrors([$this->loginUsername() => $message,]); - } - - - public $redirectTo = '/'; - - /** - * Create a new authentication controller instance. - * - * @codeCoverageIgnore - * - */ - public function __construct() - { - parent::__construct(); - - $this->middleware('guest', ['except' => 'getLogout']); - } - - /** - * Show the application login form. - * - * @codeCoverageIgnore - * @return \Illuminate\Http\Response - * - */ - public function getLogin() - { - return Twig::render('auth.login'); + return $this->sendFailedLoginResponse($request, $message); } /** * Handle a registration request for the application. * - * @param Request $request + * @param \Illuminate\Http\Request $request * - * @return \Illuminate\Http\RedirectResponse + * @return \Illuminate\Http\Response */ - public function postRegister(Request $request) + public function register(Request $request) { $validator = $this->validator($request->all()); @@ -136,10 +104,7 @@ class AuthController extends Controller $this->throwValidationException( $request, $validator ); - // @codeCoverageIgnoreStart } - // @codeCoverageIgnoreEnd - $data = $request->all(); $data['password'] = bcrypt($data['password']); @@ -152,7 +117,8 @@ class AuthController extends Controller ); } - Auth::login($this->create($data)); + + Auth::login($this->create($request->all())); // get the email address if (Auth::user() instanceof User) { @@ -187,8 +153,37 @@ class AuthController extends Controller // @codeCoverageIgnoreStart abort(500, 'Not a user!'); - return redirect('/'); - // @codeCoverageIgnoreEnd + + return redirect($this->redirectPath()); + } + + /** + * Show the application registration form. + * + * @return \Illuminate\Http\Response + */ + public function showRegistrationForm() + { + $host = Rq::getHttpHost(); + + return view('auth.register', compact('host')); + } + + /** + * Create a new user instance after a valid registration. + * + * @param array $data + * + * @return User + */ + protected function create(array $data) + { + return User::create( + [ + 'email' => $data['email'], + 'password' => bcrypt($data['password']), + ] + ); } /** @@ -196,7 +191,7 @@ class AuthController extends Controller */ protected function getBlockedDomains() { - $set = Config::get('mail.blocked_domains'); + $set = explode(',', env('BLOCKED_DOMAINS', '')); $domains = []; foreach ($set as $entry) { $domain = trim($entry); @@ -208,6 +203,24 @@ class AuthController extends Controller return $domains; } + /** + * Get the failed login message. + * + * @param $message + * + * @return string + */ + protected function getFailedLoginMessage($message) + { + if (strlen($message) > 0) { + return $message; + } + + return Lang::has('auth.failed') + ? Lang::get('auth.failed') + : 'These credentials do not match our records.'; + } + /** * @param $email * @@ -225,6 +238,26 @@ class AuthController extends Controller return false; } + /** + * Get the failed login response instance. + * + * @param \Illuminate\Http\Request $request + * + * @param $message + * + * @return \Illuminate\Http\Response + */ + protected function sendFailedLoginResponse(Request $request, $message) + { + return redirect()->back() + ->withInput($request->only($this->loginUsername(), 'remember')) + ->withErrors( + [ + $this->loginUsername() => $this->getFailedLoginMessage($message), + ] + ); + } + /** * Get a validator for an incoming registration request. * @@ -232,7 +265,7 @@ class AuthController extends Controller * * @return \Illuminate\Contracts\Validation\Validator */ - public function validator(array $data) + protected function validator(array $data) { return Validator::make( $data, [ @@ -241,21 +274,4 @@ class AuthController extends Controller ] ); } - - /** - * Create a new user instance after a valid registration. - * - * @param array $data - * - * @return User - */ - public function create(array $data) - { - return User::create( - [ - 'email' => $data['email'], - 'password' => $data['password'], - ] - ); - } } diff --git a/app/Http/Controllers/Auth/PasswordController.php b/app/Http/Controllers/Auth/PasswordController.php old mode 100644 new mode 100755 index 72944e31f1..855cfb5924 --- a/app/Http/Controllers/Auth/PasswordController.php +++ b/app/Http/Controllers/Auth/PasswordController.php @@ -1,4 +1,6 @@ -validate($request, ['email' => 'required|email']); @@ -70,16 +66,13 @@ class PasswordController extends Controller switch ($response) { case Password::RESET_LINK_SENT: - return redirect()->back()->with('status', trans($response)); + return $this->getSendResetLinkEmailSuccessResponse($response); case Password::INVALID_USER: case 'passwords.blocked': - return redirect()->back()->withErrors(['email' => trans($response)]); - + default: + return $this->getSendResetLinkEmailFailureResponse($response); } - abort(404); - - return ''; } } diff --git a/app/Http/Controllers/CategoryController.php b/app/Http/Controllers/CategoryController.php index d564789c21..1b59519808 100644 --- a/app/Http/Controllers/CategoryController.php +++ b/app/Http/Controllers/CategoryController.php @@ -144,33 +144,6 @@ class CategoryController extends Controller return view('categories.noCategory', compact('list', 'subTitle')); } - /** - * @param SCRI $repository - * @param Category $category - * - * @param $date - * - * @return \Illuminate\View\View - */ - public function showWithDate(SCRI $repository, Category $category, $date) - { - $carbon = new Carbon($date); - $range = Preferences::get('viewRange', '1M')->data; - $start = Navigation::startOfPeriod($carbon, $range); - $end = Navigation::endOfPeriod($carbon, $range); - $subTitle = $category->name; - - $hideCategory = true; // used in list. - $page = intval(Input::get('page')); - - $set = $repository->getJournalsInRange($category, $page, $start, $end); - $count = $repository->countJournalsInRange($category, $start, $end); - $journals = new LengthAwarePaginator($set, $count, 50, $page); - $journals->setPath('categories/show/' . $category->id . '/' . $date); - - return view('categories.show_with_date', compact('category', 'journals', 'hideCategory', 'subTitle', 'carbon')); - } - /** * @param SCRI $repository * @param Category $category @@ -232,6 +205,33 @@ class CategoryController extends Controller return view('categories.show', compact('category', 'journals', 'entries', 'hideCategory', 'subTitle')); } + /** + * @param SCRI $repository + * @param Category $category + * + * @param $date + * + * @return \Illuminate\View\View + */ + public function showWithDate(SCRI $repository, Category $category, $date) + { + $carbon = new Carbon($date); + $range = Preferences::get('viewRange', '1M')->data; + $start = Navigation::startOfPeriod($carbon, $range); + $end = Navigation::endOfPeriod($carbon, $range); + $subTitle = $category->name; + + $hideCategory = true; // used in list. + $page = intval(Input::get('page')); + + $set = $repository->getJournalsInRange($category, $page, $start, $end); + $count = $repository->countJournalsInRange($category, $start, $end); + $journals = new LengthAwarePaginator($set, $count, 50, $page); + $journals->setPath('categories/show/' . $category->id . '/' . $date); + + return view('categories.show_with_date', compact('category', 'journals', 'hideCategory', 'subTitle', 'carbon')); + } + /** * @param CategoryFormRequest $request * @param SCRI $repository diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index 39d3c4dffa..3fc267d732 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -46,6 +46,8 @@ class BudgetController extends Controller * @param Collection $accounts * @param Collection $budgets * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) // need all parameters + * * @return \Illuminate\Http\JsonResponse */ public function multiYear(BudgetRepositoryInterface $repository, $reportType, Carbon $start, Carbon $end, Collection $accounts, Collection $budgets) diff --git a/app/Http/Controllers/Chart/CategoryController.php b/app/Http/Controllers/Chart/CategoryController.php index 2314d61c74..27c97ab7c6 100644 --- a/app/Http/Controllers/Chart/CategoryController.php +++ b/app/Http/Controllers/Chart/CategoryController.php @@ -43,6 +43,8 @@ class CategoryController extends Controller * @param SCRI $repository * @param Category $category * + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * * @return \Symfony\Component\HttpFoundation\Response */ public function all(SCRI $repository, Category $category) @@ -53,8 +55,6 @@ class CategoryController extends Controller $start = Navigation::startOfPeriod($start, $range); $end = new Carbon; $entries = new Collection; - - // chart properties for cache: $cache = new CacheProperties(); $cache->addProperty($start); @@ -67,29 +67,21 @@ class CategoryController extends Controller $spentArray = $repository->spentPerDay($category, $start, $end); $earnedArray = $repository->earnedPerDay($category, $start, $end); - while ($start <= $end) { $currentEnd = Navigation::endOfPeriod($start, $range); - - // get the sum from $spentArray and $earnedArray: - $spent = $this->getSumOfRange($start, $currentEnd, $spentArray); - $earned = $this->getSumOfRange($start, $currentEnd, $earnedArray); - - $date = Navigation::periodShow($start, $range); + $spent = $this->getSumOfRange($start, $currentEnd, $spentArray); + $earned = $this->getSumOfRange($start, $currentEnd, $earnedArray); + $date = Navigation::periodShow($start, $range); $entries->push([clone $start, $date, $spent, $earned]); $start = Navigation::addPeriod($start, $range, 0); } - // limit the set to the last 40: $entries = $entries->reverse(); $entries = $entries->slice(0, 48); $entries = $entries->reverse(); - - $data = $this->generator->all($entries); + $data = $this->generator->all($entries); $cache->store($data); return Response::json($data); - - } @@ -121,12 +113,12 @@ class CategoryController extends Controller $outside = $repository->sumSpentNoCategory(new Collection, $start, $end); // this is a "fake" entry for the "no category" entry. - $entry = new stdClass(); - $entry->name = trans('firefly.no_category'); + $entry = new stdClass(); + $entry->name = trans('firefly.no_category'); $entry->spent = $outside; $set->push($entry); - $set = $set->sortBy('spent'); + $set = $set->sortBy('spent'); $data = $this->generator->frontpage($set); $cache->store($data); @@ -161,23 +153,8 @@ class CategoryController extends Controller return Response::json($cache->get()); // @codeCoverageIgnore } - /** - * category - * year: - * spent: x - * earned: x - * year - * spent: x - * earned: x - */ $entries = new Collection; - // go by category, not by year. - - // given a set of categories and accounts, it should not be difficult to get - // the exact array of data we need. - - // then get the data for "no category". - $set = $repository->listMultiYear($categories, $accounts, $start, $end); + $set = $repository->listMultiYear($categories, $accounts, $start, $end); /** @var Category $category */ foreach ($categories as $category) { @@ -336,6 +313,10 @@ class CategoryController extends Controller * @param Carbon $end * @param Collection $accounts * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) // cant avoid it. + * @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly 5. + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) // it's long but ok. + * * @return \Illuminate\Http\JsonResponse */ public function earnedInPeriod(CRI $repository, $reportType, Carbon $start, Carbon $end, Collection $accounts) @@ -360,18 +341,15 @@ class CategoryController extends Controller $entries = new Collection; while ($start < $end) { // filter the set: - $row = [clone $start]; - // get possibly relevant entries from the big $set - $currentSet = $set->filter( + $row = [clone $start]; + $currentSet = $set->filter( // get possibly relevant entries from the big $set function (Category $category) use ($start) { return $category->dateFormatted == $start->format("Y-m"); } ); - // check for each category if its in the current set. /** @var Category $category */ - foreach ($categories as $category) { - // if its in there, use the value. - $entry = $currentSet->filter( + foreach ($categories as $category) { // check for each category if its in the current set. + $entry = $currentSet->filter( // if its in there, use the value. function (Category $cat) use ($category) { return ($cat->id == $category->id); } @@ -382,7 +360,6 @@ class CategoryController extends Controller $row[] = 0; } } - $entries->push($row); $start->addMonth(); } @@ -403,6 +380,9 @@ class CategoryController extends Controller * @param Carbon $end * @param Collection $accounts * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) // need all parameters + * @SuppressWarnings(PHPMD.ExcessuveMethodLength) // need the length + * * @return \Illuminate\Http\JsonResponse */ public function spentInPeriod(CRI $repository, $reportType, Carbon $start, Carbon $end, Collection $accounts) @@ -427,18 +407,15 @@ class CategoryController extends Controller $entries = new Collection; while ($start < $end) { // filter the set: - $row = [clone $start]; - // get possibly relevant entries from the big $set - $currentSet = $set->filter( + $row = [clone $start]; + $currentSet = $set->filter(// get possibly relevant entries from the big $set function (Category $category) use ($start) { return $category->dateFormatted == $start->format("Y-m"); } ); - // check for each category if its in the current set. /** @var Category $category */ - foreach ($categories as $category) { - // if its in there, use the value. - $entry = $currentSet->filter( + foreach ($categories as $category) {// check for each category if its in the current set. + $entry = $currentSet->filter(// if its in there, use the value. function (Category $cat) use ($category) { return ($cat->id == $category->id); } diff --git a/app/Http/Controllers/Chart/ReportController.php b/app/Http/Controllers/Chart/ReportController.php index 545fe46d7a..3ffb128691 100644 --- a/app/Http/Controllers/Chart/ReportController.php +++ b/app/Http/Controllers/Chart/ReportController.php @@ -41,6 +41,8 @@ class ReportController extends Controller * @param Carbon $end * @param Collection $accounts * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) // cant avoid it. + * * @return \Illuminate\Http\JsonResponse */ public function yearInOut(ReportQueryInterface $query, $reportType, Carbon $start, Carbon $end, Collection $accounts) diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php old mode 100644 new mode 100755 index 55d0bc1765..ae59eb0af3 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -1,10 +1,15 @@ -monthFormat = trans('config.month'); $this->monthAndDayFormat = trans('config.month_and_day'); + App::setLocale($lang); + Carbon::setLocale(substr($lang, 0, 2)); + $locale = explode(',', trans('config.locale')); + $locale = array_map('trim', $locale); + + setlocale(LC_TIME, $locale); + setlocale(LC_MONETARY, $locale); + + // change localeconv to a new array: + $numberFormatter = numfmt_create($lang, NumberFormatter::CURRENCY); + $localeconv = [ + 'mon_decimal_point' => $numberFormatter->getSymbol($numberFormatter->getAttribute(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL)), + 'mon_thousands_sep' => $numberFormatter->getSymbol($numberFormatter->getAttribute(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL)), + 'frac_digits' => $numberFormatter->getAttribute(NumberFormatter::MAX_FRACTION_DIGITS), + ]; View::share('monthFormat', $this->monthFormat); View::share('monthAndDayFormat', $this->monthAndDayFormat); View::share('language', $lang); - View::share('localeconv', localeconv()); + View::share('localeconv', $localeconv); } } @@ -73,4 +92,6 @@ abstract class Controller extends BaseController return $sum; } + + } diff --git a/app/Http/Controllers/CsvController.php b/app/Http/Controllers/CsvController.php index bde7d5b7e0..75fa433460 100644 --- a/app/Http/Controllers/CsvController.php +++ b/app/Http/Controllers/CsvController.php @@ -13,6 +13,7 @@ use Illuminate\Http\Request; use Input; use Log; use Preferences; +use Request as RequestFacade; use Session; use View; @@ -30,7 +31,7 @@ class CsvController extends Controller protected $wizard; /** - * + * @codeCoverageIgnore */ public function __construct() { @@ -57,8 +58,9 @@ class CsvController extends Controller public function columnRoles() { - $fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-import-account']; + $fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-import-account', 'csv-specifix', 'csv-delimiter']; if (!$this->wizard->sessionHasValues($fields)) { + Log::error('Could not recover upload.'); Session::flash('warning', 'Could not recover upload.'); return redirect(route('csv.index')); @@ -79,9 +81,9 @@ class CsvController extends Controller if ($this->data->hasHeaders()) { $headers = $firstRow; } - - foreach (Config::get('csv.roles') as $name => $role) { - $availableRoles[$name] = trans('firefly.csv_column_' . $name);//$role['name']; + $keys = array_keys(Config::get('csv.roles')); + foreach ($keys as $name) { + $availableRoles[$name] = trans('firefly.csv_column_' . $name); } ksort($availableRoles); @@ -97,7 +99,7 @@ class CsvController extends Controller */ public function downloadConfig() { - $fields = ['csv-date-format', 'csv-has-headers']; + $fields = ['csv-date-format', 'csv-has-headers', 'csv-delimiter']; if (!$this->wizard->sessionHasValues($fields)) { Session::flash('warning', 'Could not recover upload.'); @@ -105,7 +107,7 @@ class CsvController extends Controller } $data = [ 'date-format' => Session::get('csv-date-format'), - 'has-headers' => Session::get('csv-has-headers') + 'has-headers' => Session::get('csv-has-headers'), ]; if (Session::has('csv-map')) { $data['map'] = Session::get('csv-map'); @@ -122,13 +124,18 @@ class CsvController extends Controller } $result = json_encode($data, JSON_PRETTY_PRINT); - $name = 'csv-configuration-' . date('Y-m-d') . '.json'; + $name = sprintf('"%s"', addcslashes('csv-configuration-' . date('Y-m-d') . '.json', '"\\')); - header('Content-disposition: attachment; filename=' . $name); - header('Content-type: application/json'); - echo $result; + RequestFacade::header('Content-disposition: attachment; filename=' . $name); + RequestFacade::header('Content-Type: application/json'); + RequestFacade::header('Content-Description: File Transfer'); + RequestFacade::header('Connection: Keep-Alive'); + RequestFacade::header('Expires: 0'); + RequestFacade::header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + RequestFacade::header('Pragma: public'); + RequestFacade::header('Content-Length: ' . strlen($result)); - return ''; + return $result; } /** @@ -136,6 +143,13 @@ class CsvController extends Controller */ public function downloadConfigPage() { + $fields = ['csv-date-format', 'csv-has-headers', 'csv-delimiter']; + if (!$this->wizard->sessionHasValues($fields)) { + Session::flash('warning', 'Could not recover upload.'); + + return redirect(route('csv.index')); + } + $subTitle = trans('firefly.csv_download_config_title'); return view('csv.download-config', compact('subTitle')); @@ -162,6 +176,7 @@ class CsvController extends Controller Session::forget('csv-roles'); Session::forget('csv-mapped'); Session::forget('csv-specifix'); + Session::forget('csv-delimiter'); // get list of supported specifix $specifix = []; @@ -169,6 +184,13 @@ class CsvController extends Controller $specifix[$entry] = trans('firefly.csv_specifix_' . $entry); } + // get a list of delimiters: + $delimiters = [ + ',' => trans('form.csv_comma'), + ';' => trans('form.csv_semicolon'), + 'tab' => trans('form.csv_tab'), + ]; + // get a list of asset accounts: $accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Asset account', 'Default account'])); @@ -176,7 +198,7 @@ class CsvController extends Controller $uploadPossible = is_writable(storage_path('upload')); $path = storage_path('upload'); - return view('csv.index', compact('subTitle', 'uploadPossible', 'path', 'specifix', 'accounts')); + return view('csv.index', compact('subTitle', 'uploadPossible', 'path', 'specifix', 'accounts', 'delimiters')); } /** @@ -188,7 +210,7 @@ class CsvController extends Controller */ public function initialParse() { - $fields = ['csv-file', 'csv-date-format', 'csv-has-headers']; + $fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-delimiter']; if (!$this->wizard->sessionHasValues($fields)) { Session::flash('warning', 'Could not recover upload.'); @@ -238,7 +260,7 @@ class CsvController extends Controller { // Make sure all fields we need are accounted for. - $fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-map', 'csv-roles']; + $fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-map', 'csv-roles', 'csv-delimiter']; if (!$this->wizard->sessionHasValues($fields)) { Session::flash('warning', 'Could not recover upload.'); @@ -258,6 +280,8 @@ class CsvController extends Controller try { $options = $this->wizard->showOptions($this->data->getMap()); } catch (FireflyException $e) { + Log::error($e->getMessage()); + return view('error', ['message' => $e->getMessage()]); } @@ -286,7 +310,7 @@ class CsvController extends Controller /* * Make sure all fields we need are accounted for. */ - $fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-map', 'csv-roles', 'csv-mapped']; + $fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-map', 'csv-roles', 'csv-mapped', 'csv-delimiter']; if (!$this->wizard->sessionHasValues($fields)) { Session::flash('warning', 'Could not recover upload.'); @@ -323,6 +347,8 @@ class CsvController extends Controller * * STEP SIX * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) it's 6, but it's allright. + * * @return \Illuminate\Http\RedirectResponse */ public function saveMapping() @@ -330,7 +356,7 @@ class CsvController extends Controller /* * Make sure all fields we need are accounted for. */ - $fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-map', 'csv-roles']; + $fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-map', 'csv-roles', 'csv-delimiter']; if (!$this->wizard->sessionHasValues($fields)) { Session::flash('warning', 'Could not recover upload.'); @@ -367,6 +393,9 @@ class CsvController extends Controller * * STEP TWO * + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) // need the length. + * @SuppressWarnings(PHPMD.CyclomaticComplexity) // its exactly 5, its ok + * * @param Request $request * * @return \Illuminate\Http\RedirectResponse @@ -383,11 +412,19 @@ class CsvController extends Controller $settings = []; $settings['date-format'] = Input::get('date_format'); $settings['has-headers'] = intval(Input::get('has_headers')) === 1; - $settings['specifix'] = Input::get('specifix'); + $settings['specifix'] = is_array(Input::get('specifix')) ? Input::get('specifix') : []; $settings['import-account'] = intval(Input::get('csv_import_account')); - $settings['map'] = []; - $settings['mapped'] = []; - $settings['roles'] = []; + $settings['delimiter'] = Input::get('csv_delimiter', ','); + + // A tab character cannot be used itself as option value in HTML + // See http://stackoverflow.com/questions/6064135/valid-characters-in-option-value + if ($settings['delimiter'] == 'tab') { + $settings['delimiter'] = "\t"; + } + + $settings['map'] = []; + $settings['mapped'] = []; + $settings['roles'] = []; if ($request->hasFile('csv_config')) { // Process config file if present. $data = file_get_contents($request->file('csv_config')->getRealPath()); @@ -405,6 +442,7 @@ class CsvController extends Controller $this->data->setRoles($settings['roles']); $this->data->setSpecifix($settings['specifix']); $this->data->setImportAccount($settings['import-account']); + $this->data->setDelimiter($settings['delimiter']); return redirect(route('csv.column-roles')); diff --git a/app/Http/Controllers/CurrencyController.php b/app/Http/Controllers/CurrencyController.php index d2bdbf7e06..d62ba35cb1 100644 --- a/app/Http/Controllers/CurrencyController.php +++ b/app/Http/Controllers/CurrencyController.php @@ -6,6 +6,7 @@ use FireflyIII\Http\Requests\CurrencyFormRequest; use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use Input; +use Log; use Preferences; use Session; use URL; @@ -60,7 +61,7 @@ class CurrencyController extends Controller Preferences::set('currencyPreference', $currency->code); Preferences::mark(); - Session::flash('success', $currency->name . ' is now the default currency.'); + Session::flash('success', trans('firefly.new_default_currency', ['name' => $currency->name])); Cache::forget('FFCURRENCYSYMBOL'); Cache::forget('FFCURRENCYCODE'); @@ -78,7 +79,7 @@ class CurrencyController extends Controller { if ($repository->countJournals($currency) > 0) { - Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.'); + Session::flash('error', trans('firefly.cannot_delete_currency', ['name' => $currency->name])); return redirect(route('currency.index')); } @@ -103,12 +104,12 @@ class CurrencyController extends Controller public function destroy(CurrencyRepositoryInterface $repository, TransactionCurrency $currency) { if ($repository->countJournals($currency) > 0) { - Session::flash('error', 'Cannot destroy ' . e($currency->name) . ' because there are still transactions attached to it.'); + Session::flash('error', trans('firefly.cannot_delete_currency', ['name' => $currency->name])); return redirect(route('currency.index')); } - Session::flash('success', 'Currency "' . e($currency->name) . '" deleted'); + Session::flash('success', trans('firefly.deleted_currency', ['name' => $currency->name])); if (Auth::user()->hasRole('owner')) { $currency->delete(); } @@ -151,7 +152,7 @@ class CurrencyController extends Controller if (!Auth::user()->hasRole('owner')) { - Session::flash('warning', 'Please ask ' . env('SITE_OWNER') . ' to add, remove or edit currencies.'); + Session::flash('warning', trans('firefly.ask_site_owner', ['owner' => env('SITE_OWNER')])); } @@ -170,8 +171,9 @@ class CurrencyController extends Controller $data = $request->getCurrencyData(); if (Auth::user()->hasRole('owner')) { $currency = $repository->store($data); - Session::flash('success', 'Currency "' . $currency->name . '" created'); - + Session::flash('success', trans('firefly.created_currency', ['name' => $currency->name])); + } else { + Log::error('User ' . Auth::user()->id . ' is not admin, but tried to store a currency.'); } if (intval(Input::get('create_another')) === 1) { @@ -199,7 +201,7 @@ class CurrencyController extends Controller if (Auth::user()->hasRole('owner')) { $currency = $repository->update($currency, $data); } - Session::flash('success', 'Currency "' . e($currency->name) . '" updated.'); + Session::flash('success', trans('firefly.updated_currency', ['name' => $currency->name])); Preferences::mark(); diff --git a/app/Http/Controllers/HelpController.php b/app/Http/Controllers/HelpController.php index 7220742700..667aef28f3 100644 --- a/app/Http/Controllers/HelpController.php +++ b/app/Http/Controllers/HelpController.php @@ -11,6 +11,13 @@ use Response; */ class HelpController extends Controller { + /** + * HelpController constructor. + */ + public function __construct() + { + parent::__construct(); + } /** * @param HelpInterface $help diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index a838ba8736..1d638813da 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -6,6 +6,7 @@ use Config; use FireflyIII\Models\Tag; use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI; use Input; +use Log; use Preferences; use Session; use Steam; @@ -17,6 +18,13 @@ use Steam; */ class HomeController extends Controller { + /** + * HomeController constructor. + */ + public function __construct() + { + parent::__construct(); + } public function dateRange() { @@ -68,6 +76,7 @@ class HomeController extends Controller */ public function index(ARI $repository) { + Log::debug('You are at index.'); $types = Config::get('firefly.accountTypesByIdentifier.asset'); $count = $repository->countAccounts($types); bcscale(2); diff --git a/app/Http/Controllers/JsonController.php b/app/Http/Controllers/JsonController.php index bc1b25539b..682299f4d3 100644 --- a/app/Http/Controllers/JsonController.php +++ b/app/Http/Controllers/JsonController.php @@ -2,6 +2,7 @@ use Amount; use Carbon\Carbon; +use Config; use FireflyIII\Helpers\Report\ReportQueryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI; use FireflyIII\Repositories\Bill\BillRepositoryInterface; @@ -9,6 +10,7 @@ use FireflyIII\Repositories\Category\CategoryRepositoryInterface as CRI; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Support\CacheProperties; +use Input; use Preferences; use Response; use Session; @@ -20,43 +22,31 @@ use Session; */ class JsonController extends Controller { + /** + * JsonController constructor. + * + * @codeCoverageIgnore + */ + public function __construct() + { + parent::__construct(); + } /** * @return \Illuminate\Http\JsonResponse */ - public function endTour() + public function action() { - Preferences::set('tour', false); - - return Response::json('true'); - } - - /** - * - */ - public function tour() - { - $pref = Preferences::get('tour', true); - if (!$pref) { - abort(404); + $count = intval(Input::get('count')) > 0 ? intval(Input::get('count')) : 1; + $keys = array_keys(Config::get('firefly.rule-actions')); + $actions = []; + foreach ($keys as $key) { + $actions[$key] = trans('firefly.rule_action_' . $key . '_choice'); } - $headers = ['main-content', 'sidebar-toggle', 'account-menu', 'budget-menu', 'report-menu', 'transaction-menu', 'option-menu', 'main-content-end']; - $steps = []; - foreach ($headers as $header) { - $steps[] = [ - 'element' => '#' . $header, - 'title' => trans('help.' . $header . '-title'), - 'content' => trans('help.' . $header . '-text'), - ]; - } - $steps[0]['orphan'] = true;// orphan and backdrop for first element. - $steps[0]['backdrop'] = true; - $steps[1]['placement'] = 'left';// sidebar position left: - $steps[7]['orphan'] = true; // final in the center again. - $steps[7]['backdrop'] = true; - $template = view('json.tour')->render(); + $view = view('rules.partials.action', compact('actions', 'count'))->render(); - return Response::json(['steps' => $steps, 'template' => $template]); + + return Response::json(['html' => $view]); } /** @@ -188,6 +178,16 @@ class JsonController extends Controller return Response::json($return); } + /** + * @return \Illuminate\Http\JsonResponse + */ + public function endTour() + { + Preferences::set('tour', false); + + return Response::json('true'); + } + /** * Returns a JSON list of all beneficiaries. * @@ -243,6 +243,34 @@ class JsonController extends Controller } + /** + * + */ + public function tour() + { + $pref = Preferences::get('tour', true); + if (!$pref) { + abort(404); + } + $headers = ['main-content', 'sidebar-toggle', 'account-menu', 'budget-menu', 'report-menu', 'transaction-menu', 'option-menu', 'main-content-end']; + $steps = []; + foreach ($headers as $header) { + $steps[] = [ + 'element' => '#' . $header, + 'title' => trans('help.' . $header . '-title'), + 'content' => trans('help.' . $header . '-text'), + ]; + } + $steps[0]['orphan'] = true;// orphan and backdrop for first element. + $steps[0]['backdrop'] = true; + $steps[1]['placement'] = 'left';// sidebar position left: + $steps[7]['orphan'] = true; // final in the center again. + $steps[7]['backdrop'] = true; + $template = view('json.tour')->render(); + + return Response::json(['steps' => $steps, 'template' => $template]); + } + /** * @param JournalRepositoryInterface $repository * @param $what @@ -267,4 +295,24 @@ class JsonController extends Controller } + /** + * @return \Illuminate\Http\JsonResponse + */ + public function trigger() + { + $count = intval(Input::get('count')) > 0 ? intval(Input::get('count')) : 1; + $keys = array_keys(Config::get('firefly.rule-triggers')); + $triggers = []; + foreach ($keys as $key) { + if ($key != 'user_action') { + $triggers[$key] = trans('firefly.rule_trigger_' . $key . '_choice'); + } + } + + $view = view('rules.partials.trigger', compact('triggers', 'count'))->render(); + + + return Response::json(['html' => $view]); + } + } diff --git a/app/Http/Controllers/NewUserController.php b/app/Http/Controllers/NewUserController.php index 440c5c74d0..58a68a45fa 100644 --- a/app/Http/Controllers/NewUserController.php +++ b/app/Http/Controllers/NewUserController.php @@ -17,6 +17,13 @@ use View; */ class NewUserController extends Controller { + /** + * NewUserController constructor. + */ + public function __construct() + { + parent::__construct(); + } /** diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php index 92ceb4cb88..56ea5322ab 100644 --- a/app/Http/Controllers/PiggyBankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -10,6 +10,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use Illuminate\Support\Collection; use Input; +use Log; use Preferences; use Session; use Steam; @@ -156,7 +157,7 @@ class PiggyBankController extends Controller } /** - * @param ARI $repository + * @param ARI $repository * @param PiggyBankRepositoryInterface $piggyRepository * * @return View @@ -186,7 +187,7 @@ class PiggyBankController extends Controller 'leftForPiggyBanks' => $repository->leftOnAccount($account, $end), 'sumOfSaved' => $piggyBank->savedSoFar, 'sumOfTargets' => round($piggyBank->targetamount, 2), - 'leftToSave' => $piggyBank->leftToSave + 'leftToSave' => $piggyBank->leftToSave, ]; } else { $accounts[$account->id]['sumOfSaved'] = bcadd($accounts[$account->id]['sumOfSaved'], $piggyBank->savedSoFar); @@ -244,6 +245,7 @@ class PiggyBankController extends Controller Session::flash('success', 'Added ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".'); Preferences::mark(); } else { + Log::error('Cannot add ' . $amount . ' because max amount is ' . $maxAmount . ' (left on account is ' . $leftOnAccount . ')'); Session::flash('error', 'Could not add ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".'); } @@ -322,6 +324,7 @@ class PiggyBankController extends Controller 'targetamount' => round($request->get('targetamount'), 2), 'remind_me' => false, 'reminder_skip' => 0, + 'order' => $repository->getMaxOrder() + 1, 'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null, ]; diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 71e3ffc473..89c82545b6 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -1,7 +1,6 @@ $email, 'password' => 'deleted', 'blocked' => 1, - 'blocked_code' => 'deleted' + 'blocked_code' => 'deleted', ] ); return redirect(route('index')); } + /** + * + * @param string $old + * @param string $new1 + * + * @return string|bool + */ + protected function validatePassword($old, $new1) + { + if ($new1 == $old) { + return trans('firefly.should_change'); + } + + return true; + + } + } diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 59f4f112b4..87b0f4054b 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -16,6 +16,7 @@ use View; class ReportController extends Controller { + /** @var ReportHelperInterface */ protected $helper; @@ -34,83 +35,6 @@ class ReportController extends Controller } - /** - * @param ARI $repository - * - * @return View - * @internal param ReportHelperInterface $helper - */ - public function index(ARI $repository) - { - $start = Session::get('first'); - $months = $this->helper->listOfMonths($start); - $startOfMonth = clone Session::get('start'); - $endOfMonth = clone Session::get('start'); - $startOfYear = clone Session::get('start'); - $endOfYear = clone Session::get('start'); - $startOfMonth->startOfMonth(); - $endOfMonth->endOfMonth(); - $startOfYear->startOfYear(); - $endOfYear->endOfYear(); - - // does the user have shared accounts? - $accounts = $repository->getAccounts(['Default account', 'Asset account']); - // get id's for quick links: - $accountIds = []; - /** @var Account $account */ - foreach ($accounts as $account) { - $accountIds [] = $account->id; - } - $accountList = join(',', $accountIds); - - - return view( - 'reports.index', compact( - 'months', 'accounts', 'start', 'accountList', - 'startOfMonth', 'endOfMonth', 'startOfYear', 'endOfYear' - ) - ); - } - - /** - * @param $reportType - * @param Carbon $start - * @param Carbon $end - * @param Collection $accounts - * - * @return View - */ - public function defaultYear($reportType, Carbon $start, Carbon $end, Collection $accounts) - { - $incomeTopLength = 8; - $expenseTopLength = 8; - - $accountReport = $this->helper->getAccountReport($start, $end, $accounts); - $incomes = $this->helper->getIncomeReport($start, $end, $accounts); - $expenses = $this->helper->getExpenseReport($start, $end, $accounts); - - Session::flash('gaEventCategory', 'report'); - Session::flash('gaEventAction', 'year'); - Session::flash('gaEventLabel', $start->format('Y')); - - // and some id's, joined: - $accountIds = []; - /** @var Account $account */ - foreach ($accounts as $account) { - $accountIds[] = $account->id; - } - $accountIds = join(',', $accountIds); - - return view( - 'reports.default.year', - compact( - 'start', 'accountReport', 'incomes', 'reportType', 'accountIds', 'end', - 'expenses', 'incomeTopLength', 'expenseTopLength' - ) - ); - } - - /** * @param $reportType * @param Carbon $start @@ -189,6 +113,73 @@ class ReportController extends Controller ); } + /** + * @param $reportType + * @param Carbon $start + * @param Carbon $end + * @param Collection $accounts + * + * @return View + */ + public function defaultYear($reportType, Carbon $start, Carbon $end, Collection $accounts) + { + $incomeTopLength = 8; + $expenseTopLength = 8; + + $accountReport = $this->helper->getAccountReport($start, $end, $accounts); + $incomes = $this->helper->getIncomeReport($start, $end, $accounts); + $expenses = $this->helper->getExpenseReport($start, $end, $accounts); + + Session::flash('gaEventCategory', 'report'); + Session::flash('gaEventAction', 'year'); + Session::flash('gaEventLabel', $start->format('Y')); + + // and some id's, joined: + $accountIds = []; + /** @var Account $account */ + foreach ($accounts as $account) { + $accountIds[] = $account->id; + } + $accountIds = join(',', $accountIds); + + return view( + 'reports.default.year', + compact( + 'start', 'accountReport', 'incomes', 'reportType', 'accountIds', 'end', + 'expenses', 'incomeTopLength', 'expenseTopLength' + ) + ); + } + + /** + * @param ARI $repository + * + * @return View + * @internal param ReportHelperInterface $helper + */ + public function index(ARI $repository) + { + $start = Session::get('first'); + $months = $this->helper->listOfMonths($start); + + // does the user have shared accounts? + $accounts = $repository->getAccounts(['Default account', 'Asset account']); + // get id's for quick links: + $accountIds = []; + /** @var Account $account */ + foreach ($accounts as $account) { + $accountIds [] = $account->id; + } + $accountList = join(',', $accountIds); + + + return view( + 'reports.index', compact( + 'months', 'accounts', 'start', 'accountList' + ) + ); + } + /** * @param $reportType * @param Carbon $start diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php new file mode 100644 index 0000000000..dac4bb1459 --- /dev/null +++ b/app/Http/Controllers/RuleController.php @@ -0,0 +1,493 @@ +getPreviousTriggers(); + $triggerCount = count($oldTriggers); + + // process old actions + $oldActions = $this->getPreviousActions(); + $actionCount = count($oldActions); + } + + $subTitleIcon = 'fa-clone'; + $subTitle = trans('firefly.make_new_rule', ['title' => $ruleGroup->title]); + + // put previous url in session if not redirect from store (not "create another"). + if (Session::get('rules.rule.create.fromStore') !== true) { + Session::put('rules.rule.create.url', URL::previous()); + } + Session::forget('rules.rule.create.fromStore'); + Session::flash('gaEventCategory', 'rules'); + Session::flash('gaEventAction', 'create-rule'); + + return view( + 'rules.rule.create', compact('subTitleIcon', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup', 'subTitle') + ); + } + + /** + * @param Rule $rule + * + * @return View + * @internal param RuleRepositoryInterface $repository + */ + public function delete(Rule $rule) + { + $subTitle = trans('firefly.delete_rule', ['title' => $rule->title]); + + // put previous url in session + Session::put('rules.rule.delete.url', URL::previous()); + Session::flash('gaEventCategory', 'rules'); + Session::flash('gaEventAction', 'delete-rule'); + + return view('rules.rule.delete', compact('rule', 'subTitle')); + } + + /** + * @param Rule $rule + * @param RuleRepositoryInterface $repository + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(RuleRepositoryInterface $repository, Rule $rule) + { + + $title = $rule->title; + $repository->destroy($rule); + + Session::flash('success', trans('firefly.deleted_rule', ['title' => $title])); + Preferences::mark(); + + + return redirect(Session::get('rules.rule.delete.url')); + } + + /** + * @param RuleRepositoryInterface $repository + * @param Rule $rule + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function down(RuleRepositoryInterface $repository, Rule $rule) + { + $repository->moveDown($rule); + + return redirect(route('rules.index')); + + } + + /** + * @param Rule $rule + * + * @return View + */ + public function edit(Rule $rule) + { + // has old input? + if (Input::old()) { + $oldTriggers = $this->getPreviousTriggers(); + $triggerCount = count($oldTriggers); + $oldActions = $this->getPreviousActions(); + $actionCount = count($oldActions); + } else { + $oldTriggers = $this->getCurrentTriggers($rule); + $triggerCount = count($oldTriggers); + $oldActions = $this->getCurrentActions($rule); + $actionCount = count($oldActions); + } + + // get rule trigger for update / store-journal: + $primaryTrigger = $rule->ruleTriggers()->where('trigger_type', 'user_action')->first()->trigger_value; + $subTitle = trans('firefly.edit_rule', ['title' => $rule->title]); + + // put previous url in session if not redirect from store (not "return_to_edit"). + if (Session::get('rules.rule.edit.fromUpdate') !== true) { + Session::put('rules.rule.edit.url', URL::previous()); + } + Session::forget('rules.rule.edit.fromUpdate'); + Session::flash('gaEventCategory', 'rules'); + Session::flash('gaEventAction', 'edit-rule'); + + return view('rules.rule.edit', compact('rule', 'subTitle', 'primaryTrigger', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount')); + } + + /** + * @return View + */ + public function index() + { + $this->createDefaultRuleGroup(); + $this->createDefaultRule(); + + + $ruleGroups = Auth::user() + ->ruleGroups() + ->orderBy('active', 'DESC') + ->orderBy('order', 'ASC') + ->with( + [ + 'rules' => function ($query) { + $query->orderBy('active', 'DESC'); + $query->orderBy('order', 'ASC'); + + }, + 'rules.ruleTriggers' => function ($query) { + $query->orderBy('order', 'ASC'); + }, + 'rules.ruleActions' => function ($query) { + $query->orderBy('order', 'ASC'); + }, + ] + )->get(); + + return view('rules.index', compact('ruleGroups')); + } + + /** + * @param RuleRepositoryInterface $repository + * @param Rule $rule + * + * @return \Illuminate\Http\JsonResponse + */ + public function reorderRuleActions(RuleRepositoryInterface $repository, Rule $rule) + { + $ids = Input::get('actions'); + if (is_array($ids)) { + $repository->reorderRuleActions($rule, $ids); + } + + return Response::json(true); + + } + + /** + * @param RuleRepositoryInterface $repository + * @param Rule $rule + * + * @return \Illuminate\Http\JsonResponse + */ + public function reorderRuleTriggers(RuleRepositoryInterface $repository, Rule $rule) + { + $ids = Input::get('triggers'); + if (is_array($ids)) { + $repository->reorderRuleTriggers($rule, $ids); + } + + return Response::json(true); + + } + + /** + * @param RuleFormRequest $request + * @param RuleRepositoryInterface $repository + * @param RuleGroup $ruleGroup + * + * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function store(RuleFormRequest $request, RuleRepositoryInterface $repository, RuleGroup $ruleGroup) + { + + + // process the rule itself: + $data = [ + 'rule_group_id' => $ruleGroup->id, + 'title' => $request->get('title'), + 'trigger' => $request->get('trigger'), + 'description' => $request->get('description'), + 'rule-triggers' => $request->get('rule-trigger'), + 'rule-trigger-values' => $request->get('rule-trigger-value'), + 'rule-trigger-stop' => $request->get('rule-trigger-stop'), + 'rule-actions' => $request->get('rule-action'), + 'rule-action-values' => $request->get('rule-action-value'), + 'rule-action-stop' => $request->get('rule-action-stop'), + 'stop_processing' => $request->get('stop_processing'), + ]; + + $rule = $repository->store($data); + Session::flash('success', trans('firefly.stored_new_rule', ['title' => $rule->title])); + Preferences::mark(); + + if (intval(Input::get('create_another')) === 1) { + // set value so create routine will not overwrite URL: + Session::put('rules.rule.create.fromStore', true); + + return redirect(route('rules.rule.create', [$request->input('what')]))->withInput(); + } + + // redirect to previous URL. + return redirect(Session::get('rules.rule.create.url')); + + } + + /** + * @param RuleRepositoryInterface $repository + * @param Rule $rule + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function up(RuleRepositoryInterface $repository, Rule $rule) + { + $repository->moveUp($rule); + + return redirect(route('rules.index')); + + } + + /** + * @param RuleRepositoryInterface $repository + * @param RuleFormRequest $request + * @param Rule $rule + * + * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function update(RuleRepositoryInterface $repository, RuleFormRequest $request, Rule $rule) + { + + // process the rule itself: + $data = [ + 'title' => $request->get('title'), + 'active' => intval($request->get('active')) == 1, + 'trigger' => $request->get('trigger'), + 'description' => $request->get('description'), + 'rule-triggers' => $request->get('rule-trigger'), + 'rule-trigger-values' => $request->get('rule-trigger-value'), + 'rule-trigger-stop' => $request->get('rule-trigger-stop'), + 'rule-actions' => $request->get('rule-action'), + 'rule-action-values' => $request->get('rule-action-value'), + 'rule-action-stop' => $request->get('rule-action-stop'), + 'stop_processing' => intval($request->get('stop_processing')) == 1, + ]; + $repository->update($rule, $data); + + Session::flash('success', trans('firefly.updated_rule', ['title' => $rule->title])); + Preferences::mark(); + + if (intval(Input::get('return_to_edit')) === 1) { + // set value so edit routine will not overwrite URL: + Session::put('rules.rule.edit.fromUpdate', true); + + return redirect(route('rules.rule.edit', [$rule->id]))->withInput(['return_to_edit' => 1]); + } + + // redirect to previous URL. + return redirect(Session::get('rules.rule.edit.url')); + } + + private function createDefaultRule() + { + /** @var RuleRepositoryInterface $repository */ + $repository = app('FireflyIII\Repositories\Rule\RuleRepositoryInterface'); + + if ($repository->count() === 0) { + $data = [ + 'rule_group_id' => $repository->getFirstRuleGroup()->id, + 'stop_processing' => 0, + 'title' => trans('firefly.default_rule_name'), + 'description' => trans('firefly.default_rule_description'), + 'trigger' => 'store-journal', + 'rule-trigger-values' => [ + trans('firefly.default_rule_trigger_description'), + trans('firefly.default_rule_trigger_from_account'), + ], + 'rule-action-values' => [ + trans('firefly.default_rule_action_prepend'), + trans('firefly.default_rule_action_set_category'), + ], + + 'rule-triggers' => ['description_is', 'from_account_is'], + 'rule-actions' => ['prepend_description', 'set_category'], + ]; + + $repository->store($data); + } + + } + + /** + * + */ + private function createDefaultRuleGroup() + { + + /** @var RuleGroupRepositoryInterface $repository */ + $repository = app('FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface'); + + if ($repository->count() === 0) { + $data = [ + 'user' => Auth::user()->id, + 'title' => trans('firefly.default_rule_group_name'), + 'description' => trans('firefly.default_rule_group_description'), + ]; + + $repository->store($data); + } + } + + /** + * @param Rule $rule + * + * @return array + */ + private function getCurrentActions(Rule $rule) + { + $index = 0; + $actions = []; + + /** @var RuleAction $entry */ + foreach ($rule->ruleActions as $entry) { + $count = ($index + 1); + $actions[] = view( + 'rules.partials.action', + [ + 'oldTrigger' => $entry->action_type, + 'oldValue' => $entry->action_value, + 'oldChecked' => $entry->stop_processing, + 'count' => $count, + ] + )->render(); + $index++; + } + + return $actions; + } + + /** + * @param Rule $rule + * + * @return array + */ + private function getCurrentTriggers(Rule $rule) + { + $index = 0; + $triggers = []; + + /** @var RuleTrigger $entry */ + foreach ($rule->ruleTriggers as $entry) { + if ($entry->trigger_type != 'user_action') { + $count = ($index + 1); + $triggers[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => $entry->trigger_type, + 'oldValue' => $entry->trigger_value, + 'oldChecked' => $entry->stop_processing, + 'count' => $count, + ] + )->render(); + $index++; + } + } + + return $triggers; + } + + /** + * @return array + */ + private function getPreviousActions() + { + $newIndex = 0; + $actions = []; + foreach (Input::old('rule-action') as $index => $entry) { + $count = ($newIndex + 1); + $checked = isset(Input::old('rule-action-stop')[$index]) ? true : false; + $actions[] = view( + 'rules.partials.action', + [ + 'oldTrigger' => $entry, + 'oldValue' => Input::old('rule-action-value')[$index], + 'oldChecked' => $checked, + 'count' => $count, + ] + )->render(); + $newIndex++; + } + + return $actions; + } + + /** + * @return array + */ + private function getPreviousTriggers() + { + $newIndex = 0; + $triggers = []; + foreach (Input::old('rule-trigger') as $index => $entry) { + $count = ($newIndex + 1); + $oldChecked = isset(Input::old('rule-trigger-stop')[$index]) ? true : false; + $triggers[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => $entry, + 'oldValue' => Input::old('rule-trigger-value')[$index], + 'oldChecked' => $oldChecked, + 'count' => $count, + ] + )->render(); + $newIndex++; + } + + return $triggers; + } + + +} diff --git a/app/Http/Controllers/RuleGroupController.php b/app/Http/Controllers/RuleGroupController.php new file mode 100644 index 0000000000..6df34944a1 --- /dev/null +++ b/app/Http/Controllers/RuleGroupController.php @@ -0,0 +1,207 @@ + $ruleGroup->title]); + + $ruleGroupList = Expandedform::makeSelectList($repository->get(), true); + unset($ruleGroupList[$ruleGroup->id]); + + // put previous url in session + Session::put('rules.rule-group.delete.url', URL::previous()); + Session::flash('gaEventCategory', 'rules'); + Session::flash('gaEventAction', 'delete-rule-group'); + + return view('rules.rule-group.delete', compact('ruleGroup', 'subTitle', 'ruleGroupList')); + } + + /** + * @param RuleGroupRepositoryInterface $repository + * + * @param RuleGroup $ruleGroup + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(RuleGroupRepositoryInterface $repository, RuleGroup $ruleGroup) + { + + $title = $ruleGroup->title; + $moveTo = Auth::user()->ruleGroups()->find(intval(Input::get('move_rules_before_delete'))); + + $repository->destroy($ruleGroup, $moveTo); + + + Session::flash('success', trans('firefly.deleted_rule_group', ['title' => $title])); + Preferences::mark(); + + + return redirect(Session::get('rules.rule-group.delete.url')); + } + + /** + * @param RuleGroupRepositoryInterface $repository + * @param RuleGroup $ruleGroup + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function down(RuleGroupRepositoryInterface $repository, RuleGroup $ruleGroup) + { + $repository->moveDown($ruleGroup); + + return redirect(route('rules.index')); + + } + + /** + * @param RuleGroup $ruleGroup + * + * @return View + */ + public function edit(RuleGroup $ruleGroup) + { + $subTitle = trans('firefly.edit_rule_group', ['title' => $ruleGroup->title]); + + // put previous url in session if not redirect from store (not "return_to_edit"). + if (Session::get('rules.rule-group.edit.fromUpdate') !== true) { + Session::put('rules.rule-group.edit.url', URL::previous()); + } + Session::forget('rules.rule-group.edit.fromUpdate'); + Session::flash('gaEventCategory', 'rules'); + Session::flash('gaEventAction', 'edit-rule-group'); + + return view('rules.rule-group.edit', compact('ruleGroup', 'subTitle')); + + } + + /** + * @param RuleGroupFormRequest $request + * @param RuleGroupRepositoryInterface $repository + * + * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function store(RuleGroupFormRequest $request, RuleGroupRepositoryInterface $repository) + { + $data = [ + 'title' => $request->input('title'), + 'description' => $request->input('description'), + 'user' => Auth::user()->id, + ]; + + $ruleGroup = $repository->store($data); + + Session::flash('success', trans('firefly.created_new_rule_group', ['title' => $ruleGroup->title])); + Preferences::mark(); + + if (intval(Input::get('create_another')) === 1) { + // set value so create routine will not overwrite URL: + Session::put('rules.rule-group.create.fromStore', true); + + return redirect(route('rules.rule-group.create'))->withInput(); + } + + // redirect to previous URL. + return redirect(Session::get('rules.rule-group.create.url')); + } + + /** + * @param RuleGroupRepositoryInterface $repository + * @param RuleGroup $ruleGroup + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function up(RuleGroupRepositoryInterface $repository, RuleGroup $ruleGroup) + { + $repository->moveUp($ruleGroup); + + return redirect(route('rules.index')); + + } + + /** + * @param RuleGroupFormRequest $request + * @param RuleGroupRepositoryInterface $repository + * @param RuleGroup $ruleGroup + * + * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function update(RuleGroupFormRequest $request, RuleGroupRepositoryInterface $repository, RuleGroup $ruleGroup) + { + $data = [ + 'title' => $request->input('title'), + 'description' => $request->input('description'), + 'active' => intval($request->input('active')) == 1, + ]; + + $repository->update($ruleGroup, $data); + + Session::flash('success', trans('firefly.updated_rule_group', ['title' => $ruleGroup->title])); + Preferences::mark(); + + if (intval(Input::get('return_to_edit')) === 1) { + // set value so edit routine will not overwrite URL: + Session::put('rules.rule-group.edit.fromUpdate', true); + + return redirect(route('rules.rule-group.edit', [$ruleGroup->id]))->withInput(['return_to_edit' => 1]); + } + + // redirect to previous URL. + return redirect(Session::get('rules.rule-group.edit.url')); + + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index ad3eb16b62..e9793687f3 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -10,6 +10,14 @@ use Input; */ class SearchController extends Controller { + /** + * SearchController constructor. + */ + public function __construct() + { + parent::__construct(); + } + /** * Results always come in the form of an array [results, count, fullCount] * diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index bf0baa0805..bdd0c6bab5 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -60,7 +60,7 @@ class TagController extends Controller $subTitleIcon = 'fa-tag'; $preFilled = [ - 'tagMode' => 'nothing' + 'tagMode' => 'nothing', ]; if (!Input::old('tagMode')) { Session::flash('preFilled', $preFilled); diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php index 54e9b5fc2b..41b0a4975f 100644 --- a/app/Http/Controllers/TransactionController.php +++ b/app/Http/Controllers/TransactionController.php @@ -5,8 +5,8 @@ use Auth; use Carbon\Carbon; use Config; use ExpandedForm; -use FireflyIII\Events\JournalCreated; -use FireflyIII\Events\JournalSaved; +use FireflyIII\Events\TransactionJournalStored; +use FireflyIII\Events\TransactionJournalUpdated; use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; use FireflyIII\Http\Requests\JournalFormRequest; use FireflyIII\Models\PiggyBank; @@ -18,6 +18,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use Illuminate\Support\Collection; use Input; +use Log; use Preferences; use Response; use Session; @@ -57,9 +58,7 @@ class TransactionController extends Controller $accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account'])); $budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get()); $budgets[0] = trans('form.noBudget'); - - // piggy bank list: - $piggyBanks = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get(); + $piggyBanks = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get(); /** @var PiggyBank $piggy */ foreach ($piggyBanks as $piggy) { $piggy->name = $piggy->name . ' (' . Amount::format($piggy->currentRelevantRep()->currentamount, false) . ')'; @@ -160,7 +159,7 @@ class TransactionController extends Controller 'date' => $journal->date->format('Y-m-d'), 'category' => '', 'budget_id' => 0, - 'piggy_bank_id' => 0 + 'piggy_bank_id' => 0, ]; // get tags: $preFilled['tags'] = join(',', $journal->tags->pluck('tag')->toArray()); @@ -294,7 +293,6 @@ class TransactionController extends Controller */ public function store(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att) { - $journalData = $request->getJournalData(); // if not withdrawal, unset budgetid. @@ -304,7 +302,6 @@ class TransactionController extends Controller $journal = $repository->store($journalData); - // save attachments: $att->saveAttachmentsForModel($journal); // flash errors @@ -315,13 +312,9 @@ class TransactionController extends Controller if (count($att->getMessages()->get('attachments')) > 0) { Session::flash('info', $att->getMessages()->get('attachments')); } + Log::debug('Before event. From account name is: ' . $journal->source_account->name); - // rescan journal, UpdateJournalConnection - event(new JournalSaved($journal)); - - if ($journal->isTransfer() && intval($request->get('piggy_bank_id')) > 0) { - event(new JournalCreated($journal, intval($request->get('piggy_bank_id')))); - } + event(new TransactionJournalStored($journal, intval($request->get('piggy_bank_id')))); Session::flash('success', 'New transaction "' . $journal->description . '" stored!'); Preferences::mark(); @@ -350,10 +343,6 @@ class TransactionController extends Controller public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att, TransactionJournal $journal) { - if ($journal->isOpeningBalance()) { - return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!'); - } - $journalData = $request->getJournalData(); $repository->update($journal, $journalData); @@ -369,7 +358,7 @@ class TransactionController extends Controller Session::flash('info', $att->getMessages()->get('attachments')); } - event(new JournalSaved($journal)); + event(new TransactionJournalUpdated($journal)); // update, get events by date and sort DESC Session::flash('success', 'Transaction "' . e($journalData['description']) . '" updated.'); diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php old mode 100644 new mode 100755 index 232b742f8f..3c1c958dec --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -1,6 +1,20 @@ - [ + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + ], + 'web-auth' => [ + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + Authenticate::class, + ], + 'web-auth-range' => [ + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + Authenticate::class, + Range::class, + Binder::class, + ], + + 'api' => [ + 'throttle:60,1', + ], ]; /** * The application's route middleware. * + * These middleware may be assigned to groups or used individually. + * * @var array */ protected $routeMiddleware = [ - 'auth' => 'FireflyIII\Http\Middleware\Authenticate', - 'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth', - 'guest' => 'FireflyIII\Http\Middleware\RedirectIfAuthenticated', - 'range' => 'FireflyIII\Http\Middleware\Range', - + 'auth' => Authenticate::class, + 'auth.basic' => AuthenticateWithBasicAuth::class, + 'guest' => RedirectIfAuthenticated::class, + 'throttle' => ThrottleRequests::class, + 'range' => Range::class, ]; - } diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php old mode 100644 new mode 100755 index 5cc1d665de..7032eb9bf2 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -1,78 +1,37 @@ -auth = $auth; - } - /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next + * @param string|null $guard * * @return mixed */ - public function handle(Request $request, Closure $next) + public function handle($request, Closure $next, $guard = null) { - - if ($this->auth->guest()) { + if (Auth::guard($guard)->guest()) { if ($request->ajax()) { return response('Unauthorized.', 401); } else { - return redirect()->guest('auth/login'); + + return redirect()->guest('login'); } } - /** @var User $user */ - $user = $this->auth->user(); - if ($user instanceof User && intval($user->blocked) == 1) { - Auth::logout(); - - return redirect()->route('index'); - } - - // if logged in, set user language: - $pref = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US')); - App::setLocale($pref->data); - Carbon::setLocale(substr($pref->data, 0, 2)); - $locale = explode(',', trans('config.locale')); - $locale = array_map('trim', $locale); - - setlocale(LC_TIME, $locale); - setlocale(LC_MONETARY, $locale); return $next($request); } - } diff --git a/app/Http/Middleware/Binder.php b/app/Http/Middleware/Binder.php new file mode 100644 index 0000000000..3a3ccb3c85 --- /dev/null +++ b/app/Http/Middleware/Binder.php @@ -0,0 +1,60 @@ +binders = Domain::getBindables(); + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * + * @return mixed + */ + public function handle($request, Closure $next) + { + foreach ($request->route()->parameters() as $key => $value) { + if (isset($this->binders[$key])) { + $boundObject = $this->performBinding($key, $value, $request->route()); + $request->route()->setParameter($key, $boundObject); + } + } + + return $next($request); + + //return $next($request); + } + + /** + * @param $key + * @param $value + * @param $route + * + * @return mixed + */ + private function performBinding($key, $value, $route) + { + $class = $this->binders[$key]; + + return $class::routeBinder($value, $route); + } +} diff --git a/app/Http/Middleware/EncryptCookies.php b/app/Http/Middleware/EncryptCookies.php new file mode 100755 index 0000000000..8784890ec9 --- /dev/null +++ b/app/Http/Middleware/EncryptCookies.php @@ -0,0 +1,23 @@ +auth->check()) { - + if (!Auth::guard($guard)->guest()) { // ignore preference. set the range to be the current month: if (!Session::has('start') && !Session::has('end')) { @@ -71,6 +73,10 @@ class Range Session::put('first', Carbon::now()->startOfYear()); } } + + // check "sum of everything". + + $current = Carbon::now()->formatLocalized('%B %Y'); $next = Carbon::now()->endOfMonth()->addDay()->formatLocalized('%B %Y'); $prev = Carbon::now()->startOfMonth()->subDay()->formatLocalized('%B %Y'); diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php old mode 100644 new mode 100755 index b5419be62c..1cf76e8aa8 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -1,52 +1,33 @@ -auth = $auth; - } - /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next + * @param string|null $guard * * @return mixed */ - public function handle(Request $request, Closure $next) + public function handle($request, Closure $next, $guard = null) { - if ($this->auth->check()) { - return new RedirectResponse(url('/')); + if (Auth::guard($guard)->check()) { + + return redirect('/'); } return $next($request); } - } diff --git a/app/Http/Middleware/ReplaceTestVars.php b/app/Http/Middleware/ReplaceTestVars.php deleted file mode 100644 index 5e90f0253c..0000000000 --- a/app/Http/Middleware/ReplaceTestVars.php +++ /dev/null @@ -1,57 +0,0 @@ -app = $app; - } - - /** - * Handle an incoming request. - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * - * @return mixed - */ - public function handle(Request $request, Closure $next) - { - if ('testing' === $this->app->environment() && $request->has('_token')) { - $input = $request->all(); - $input['_token'] = $request->session()->token(); - // we need to update _token value to make sure we get the POST / PUT tests passed. - Log::debug('Input token replaced (' . $input['_token'] . ').'); - $request->replace($input); - } - - return $next($request); - } - -} diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index 71dd254d3d..413dde74b3 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -1,27 +1,22 @@ - 'date', 'amount_currency_id_openingBalance' => 'exists:transaction_currencies,id', 'amount_currency_id_virtualBalance' => 'exists:transaction_currencies,id', - 'what' => 'in:' . $types + 'what' => 'in:' . $types, ]; } } diff --git a/app/Http/Requests/BudgetFormRequest.php b/app/Http/Requests/BudgetFormRequest.php index 11207e8037..8d99f5f52a 100644 --- a/app/Http/Requests/BudgetFormRequest.php +++ b/app/Http/Requests/BudgetFormRequest.php @@ -36,7 +36,7 @@ class BudgetFormRequest extends Request return [ 'name' => $nameRule, - 'active' => 'numeric|between:0,1' + 'active' => 'numeric|between:0,1', ]; } } diff --git a/app/Http/Requests/Request.php b/app/Http/Requests/Request.php old mode 100644 new mode 100755 index 73c38578b3..8f7d18805c --- a/app/Http/Requests/Request.php +++ b/app/Http/Requests/Request.php @@ -1,16 +1,15 @@ - $titleRule, + 'description' => 'between:1,5000', + 'stop_processing' => 'boolean', + 'rule_group_id' => 'required|belongsToUser:rule_groups', + 'trigger' => 'required|in:store-journal,update-journal', + 'rule-trigger.*' => 'required|in:' . join(',', $validTriggers), + 'rule-trigger-value.*' => 'required|min:1|ruleTriggerValue', + 'rule-action.*' => 'required|in:' . join(',', $validActions), + ]; + // since Laravel does not support this stuff yet, here's a trick. + for ($i = 0; $i < 10; $i++) { + $rules['rule-action-value.' . $i] = 'required_if:rule-action.' . $i . ',' . $contextActions . '|ruleActionValue'; + } + + return $rules; + } +} diff --git a/app/Http/Requests/RuleGroupFormRequest.php b/app/Http/Requests/RuleGroupFormRequest.php new file mode 100644 index 0000000000..112a1dcca6 --- /dev/null +++ b/app/Http/Requests/RuleGroupFormRequest.php @@ -0,0 +1,49 @@ + $titleRule, + 'description' => 'between:1,5000', + ]; + } +} diff --git a/app/Http/Requests/TagFormRequest.php b/app/Http/Requests/TagFormRequest.php index 28773c874c..a4f5da9021 100644 --- a/app/Http/Requests/TagFormRequest.php +++ b/app/Http/Requests/TagFormRequest.php @@ -42,7 +42,7 @@ class TagFormRequest extends Request 'latitude' => 'numeric|min:-90|max:90', 'longitude' => 'numeric|min:-90|max:90', 'zoomLevel' => 'numeric|min:0|max:80', - 'tagMode' => 'required|in:nothing,balancingAct,advancePayment' + 'tagMode' => 'required|in:nothing,balancingAct,advancePayment', ]; } } diff --git a/app/Http/breadcrumbs.php b/app/Http/breadcrumbs.php index cf3de22751..6ae979f176 100644 --- a/app/Http/breadcrumbs.php +++ b/app/Http/breadcrumbs.php @@ -361,6 +361,16 @@ Breadcrumbs::register( } ); +/** + * Rules + */ +Breadcrumbs::register( + 'rules.index', function (BreadCrumbGenerator $breadcrumbs) { + $breadcrumbs->parent('home'); + $breadcrumbs->push(trans('firefly.rules'), route('rules.index')); +} +); + // search Breadcrumbs::register( 'search', function (BreadCrumbGenerator $breadcrumbs, $query) { diff --git a/app/Http/routes.php b/app/Http/routes.php index 891e36424e..c1405e09c0 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -1,280 +1,33 @@ 'web'], function () { + + // Authentication Routes... + Route::get('/login', 'Auth\AuthController@showLoginForm'); + Route::post('/login', 'Auth\AuthController@login'); + Route::get('/logout', 'Auth\AuthController@logout'); + + // Registration Routes... + Route::get('/register', ['uses' => 'Auth\AuthController@showRegistrationForm', 'as' => 'register']); + Route::post('/register', 'Auth\AuthController@register'); + + Route::get('/password/reset', 'Auth\PasswordController@getReset'); + + // Password Reset Routes... + Route::get('/password/reset/{token?}', 'Auth\PasswordController@showResetForm'); + Route::post('/password/email', 'Auth\PasswordController@sendResetLinkEmail'); + Route::post('/password/reset', 'Auth\PasswordController@reset'); -// models -Route::bind( - 'account', - function ($value) { - if (Auth::check()) { - $object = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') - ->where('account_types.editable', 1) - ->where('accounts.id', $value) - ->where('user_id', Auth::user()->id) - ->first(['accounts.*']); - if ($object) { - return $object; - } - } - throw new NotFoundHttpException; - } -); -// accounts -Route::bind( - 'accountList', - function ($value) { - if (Auth::check()) { - $ids = explode(',', $value); - /** @var \Illuminate\Support\Collection $object */ - $object = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') - ->where('account_types.editable', 1) - ->whereIn('accounts.id', $ids) - ->where('user_id', Auth::user()->id) - ->get(['accounts.*']); - if ($object->count() > 0) { - return $object; - } - } - throw new NotFoundHttpException; - } -); -// budget list -Route::bind( - 'budgetList', - function ($value) { - if (Auth::check()) { - $ids = explode(',', $value); - /** @var \Illuminate\Support\Collection $object */ - $object = Budget::where('active', 1) - ->whereIn('id', $ids) - ->where('user_id', Auth::user()->id) - ->get(); - - // add empty budget if applicable. - if (in_array('0', $ids)) { - $object->push(new Budget); - } - - if ($object->count() > 0) { - return $object; - } - } - throw new NotFoundHttpException; - } -); - -// category list -Route::bind( - 'categoryList', - function ($value) { - if (Auth::check()) { - $ids = explode(',', $value); - /** @var \Illuminate\Support\Collection $object */ - $object = Category::whereIn('id', $ids) - ->where('user_id', Auth::user()->id) - ->get(); - - // add empty budget if applicable. - if (in_array('0', $ids)) { - $object->push(new Category); - } - - if ($object->count() > 0) { - return $object; - } - } - throw new NotFoundHttpException; - } -); - -// Date -Route::bind( - 'start_date', - function ($value) { - if (Auth::check()) { - - try { - $date = new Carbon($value); - } catch (Exception $e) { - Log::error('Could not parse date "' . $value . '" for user #' . Auth::user()->id); - throw new NotFoundHttpException; - } - - return $date; - } - throw new NotFoundHttpException; - } -); - -// Date -Route::bind( - 'end_date', - function ($value) { - if (Auth::check()) { - - try { - $date = new Carbon($value); - } catch (Exception $e) { - Log::error('Could not parse date "' . $value . '" for user #' . Auth::user()->id); - throw new NotFoundHttpException; - } - - return $date; - } - throw new NotFoundHttpException; - } -); - -Route::bind( - 'tj', function ($value) { - if (Auth::check()) { - $object = TransactionJournal::where('id', $value)->where('user_id', Auth::user()->id)->first(); - if ($object) { - return $object; - } - } - - throw new NotFoundHttpException; + //Route::get('/home', 'HomeController@index'); } ); -Route::bind( - 'attachment', function ($value) { - if (Auth::check()) { - $object = Attachment::where('id', $value)->where('user_id', Auth::user()->id)->first(); - if ($object) { - return $object; - } - } - - throw new NotFoundHttpException; -} -); - -Route::bind( - 'currency', function ($value) { - if (Auth::check()) { - $object = TransactionCurrency::find($value); - if ($object) { - return $object; - } - } - throw new NotFoundHttpException; -} -); - -Route::bind( - 'bill', function ($value) { - if (Auth::check()) { - $object = Bill::where('id', $value)->where('user_id', Auth::user()->id)->first(); - if ($object) { - return $object; - } - } - - throw new NotFoundHttpException; -} -); - -Route::bind( - 'budget', function ($value) { - if (Auth::check()) { - $object = Budget::where('id', $value)->where('user_id', Auth::user()->id)->first(); - if ($object) { - return $object; - } - } - - throw new NotFoundHttpException; -} -); - -Route::bind( - 'limitrepetition', function ($value) { - if (Auth::check()) { - $object = LimitRepetition::where('limit_repetitions.id', $value) - ->leftjoin('budget_limits', 'budget_limits.id', '=', 'limit_repetitions.budget_limit_id') - ->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') - ->where('budgets.user_id', Auth::user()->id) - ->first(['limit_repetitions.*']); - if ($object) { - return $object; - } - } - - throw new NotFoundHttpException; -} -); - -Route::bind( - 'piggyBank', function ($value) { - if (Auth::check()) { - $object = PiggyBank::where('piggy_banks.id', $value) - ->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') - ->where('accounts.user_id', Auth::user()->id) - ->first(['piggy_banks.*']); - if ($object) { - return $object; - } - } - - throw new NotFoundHttpException; -} -); - -Route::bind( - 'category', function ($value) { - if (Auth::check()) { - $object = Category::where('id', $value)->where('user_id', Auth::user()->id)->first(); - if ($object) { - return $object; - } - } - - throw new NotFoundHttpException; -} -); - -Route::bind( - 'tag', function ($value) { - if (Auth::check()) { - $object = Tag::where('id', $value)->where('user_id', Auth::user()->id)->first(); - if ($object) { - return $object; - } - } - - throw new NotFoundHttpException; -} -); - - -/** - * Auth\AuthController - */ -Route::get('/register', ['uses' => 'Auth\AuthController@getRegister', 'as' => 'register']); - -Route::controllers( - [ - 'auth' => 'Auth\AuthController', - 'password' => 'Auth\PasswordController', - ] -); - Route::group( - ['middleware' => ['auth', 'range']], function () { + ['middleware' => ['web-auth-range']], function () { /** * Home Controller @@ -449,6 +202,9 @@ Route::group( Route::get('/json/box/bills-paid', ['uses' => 'JsonController@boxBillsPaid', 'as' => 'json.box.unpaid']); Route::get('/json/transaction-journals/{what}', 'JsonController@transactionJournals'); + Route::get('/json/trigger', ['uses' => 'JsonController@trigger', 'as' => 'json.trigger']); + Route::get('/json/action', ['uses' => 'JsonController@action', 'as' => 'json.action']); + /** * New user Controller */ @@ -493,6 +249,39 @@ Route::group( Route::get('/reports', ['uses' => 'ReportController@index', 'as' => 'reports.index']); Route::get('/reports/report/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'ReportController@report', 'as' => 'reports.report']); + /** + * Rules Controller + */ + // index + Route::get('/rules', ['uses' => 'RuleController@index', 'as' => 'rules.index']); + + // rules GET: + Route::get('/rules/create/{ruleGroup}', ['uses' => 'RuleController@create', 'as' => 'rules.rule.create']); + Route::get('/rules/rules/up/{rule}', ['uses' => 'RuleController@up', 'as' => 'rules.rule.up']); + Route::get('/rules/rules/down/{rule}', ['uses' => 'RuleController@down', 'as' => 'rules.rule.down']); + Route::get('/rules/rules/edit/{rule}', ['uses' => 'RuleController@edit', 'as' => 'rules.rule.edit']); + Route::get('/rules/rules/delete/{rule}', ['uses' => 'RuleController@delete', 'as' => 'rules.rule.delete']); + + // rules POST: + Route::post('/rules/rules/trigger/reorder/{rule}', ['uses' => 'RuleController@reorderRuleTriggers']); + Route::post('/rules/rules/action/reorder/{rule}', ['uses' => 'RuleController@reorderRuleActions']); + Route::post('/rules/store/{ruleGroup}', ['uses' => 'RuleController@store', 'as' => 'rules.rule.store']); + Route::post('/rules/update/{rule}', ['uses' => 'RuleController@update', 'as' => 'rules.rule.update']); + Route::post('/rules/destroy/{rule}', ['uses' => 'RuleController@destroy', 'as' => 'rules.rule.destroy']); + + + // rule groups GET + Route::get('/rules/groups/create', ['uses' => 'RuleGroupController@create', 'as' => 'rules.rule-group.create']); + Route::get('/rules/groups/edit/{ruleGroup}', ['uses' => 'RuleGroupController@edit', 'as' => 'rules.rule-group.edit']); + Route::get('/rules/groups/delete/{ruleGroup}', ['uses' => 'RuleGroupController@delete', 'as' => 'rules.rule-group.delete']); + Route::get('/rules/groups/up/{ruleGroup}', ['uses' => 'RuleGroupController@up', 'as' => 'rules.rule-group.up']); + Route::get('/rules/groups/down/{ruleGroup}', ['uses' => 'RuleGroupController@down', 'as' => 'rules.rule-group.down']); + + // rule groups POST + Route::post('/rules/groups/store', ['uses' => 'RuleGroupController@store', 'as' => 'rules.rule-group.store']); + Route::post('/rules/groups/update/{ruleGroup}', ['uses' => 'RuleGroupController@update', 'as' => 'rules.rule-group.update']); + Route::post('/rules/groups/destroy/{ruleGroup}', ['uses' => 'RuleGroupController@destroy', 'as' => 'rules.rule-group.destroy']); + /** * Search Controller */ @@ -537,7 +326,7 @@ Route::group( /** * Auth\Auth Controller */ - Route::get('/logout', ['uses' => 'Auth\AuthController@getLogout', 'as' => 'logout']); + Route::get('/logout', ['uses' => 'Auth\AuthController@logout', 'as' => 'logout']); } diff --git a/app/Jobs/Job.php b/app/Jobs/Job.php new file mode 100755 index 0000000000..264fe0f180 --- /dev/null +++ b/app/Jobs/Job.php @@ -0,0 +1,26 @@ + 'required|exists:users,id', 'account_type_id' => 'required|exists:account_types,id', 'name' => 'required', - 'active' => 'required|boolean' + 'active' => 'required|boolean', ]; /** @@ -125,15 +127,6 @@ class Account extends Model return $this->belongsTo('FireflyIII\Models\AccountType'); } - /** - * @codeCoverageIgnore - * @return string[] - */ - public function getDates() - { - return ['created_at', 'updated_at', 'deleted_at']; - } - /** * @codeCoverageIgnore * @@ -292,4 +285,19 @@ class Account extends Model return $this->belongsTo('FireflyIII\User'); } + /** + * @param Account $value + * + * @return Account + */ + public static function routeBinder(Account $value) + { + + if (Auth::check()) { + if ($value->user_id == Auth::user()->id) { + return $value; + } + } + throw new NotFoundHttpException; + } } diff --git a/app/Models/AccountMeta.php b/app/Models/AccountMeta.php index aab45415f6..846ff8954b 100644 --- a/app/Models/AccountMeta.php +++ b/app/Models/AccountMeta.php @@ -2,7 +2,6 @@ use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; -use Watson\Validating\ValidatingTrait; /** * FireflyIII\Models\AccountMeta @@ -18,14 +17,8 @@ use Watson\Validating\ValidatingTrait; class AccountMeta extends Model { - use ValidatingTrait; + protected $dates = ['created_at', 'updated_at']; protected $fillable = ['account_id', 'name', 'data']; - protected $rules - = [ - 'account_id' => 'required|exists:accounts,id', - 'name' => 'required|between:1,100', - 'data' => 'required' - ]; protected $table = 'account_meta'; /** @@ -48,14 +41,6 @@ class AccountMeta extends Model return json_decode($value); } - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at']; - } - /** * @param $value */ diff --git a/app/Models/AccountType.php b/app/Models/AccountType.php index 55f1e1f720..817d488b14 100644 --- a/app/Models/AccountType.php +++ b/app/Models/AccountType.php @@ -17,6 +17,8 @@ use Illuminate\Database\Eloquent\Model; class AccountType extends Model { + protected $dates = ['created_at', 'updated_at']; + // /** * @return \Illuminate\Database\Eloquent\Relations\HasMany @@ -25,13 +27,4 @@ class AccountType extends Model { return $this->hasMany('FireflyIII\Models\Account'); } - - /** - * @return array - */ - /** @noinspection PhpMissingParentCallCommonInspection */ - public function getDates() - { - return ['created_at', 'updated_at']; - } } diff --git a/app/Models/Attachment.php b/app/Models/Attachment.php index c73424d76a..f57d1d31b5 100644 --- a/app/Models/Attachment.php +++ b/app/Models/Attachment.php @@ -2,11 +2,13 @@ namespace FireflyIII\Models; +use Auth; use Carbon\Carbon; use Crypt; use FireflyIII\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * FireflyIII\Models\Attachment @@ -173,4 +175,20 @@ class Attachment extends Model $this->attributes['notes'] = Crypt::encrypt($value); } + /** + * @param Attachment $value + * + * @return Attachment + */ + public static function routeBinder(Attachment $value) + { + if (Auth::check()) { + + if ($value->user_id == Auth::user()->id) { + return $value; + } + } + throw new NotFoundHttpException; + } + } diff --git a/app/Models/Bill.php b/app/Models/Bill.php index c148f88a10..d8ca9ef6dd 100644 --- a/app/Models/Bill.php +++ b/app/Models/Bill.php @@ -1,10 +1,12 @@ user_id == Auth::user()->id) { + return $value; + } + } + throw new NotFoundHttpException; + } + + } diff --git a/app/Models/Budget.php b/app/Models/Budget.php index 26f085a118..ed72b0b1e8 100644 --- a/app/Models/Budget.php +++ b/app/Models/Budget.php @@ -1,11 +1,13 @@ hasMany('FireflyIII\Models\BudgetLimit'); } - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'deleted_at', 'startdate', 'enddate']; - } - /** * @param $value * @@ -123,5 +120,20 @@ class Budget extends Model return $this->belongsTo('FireflyIII\User'); } + /** + * @param Budget $value + * + * @return Budget + */ + public static function routeBinder(Budget $value) + { + if (Auth::check()) { + if ($value->user_id == Auth::user()->id) { + return $value; + } + } + throw new NotFoundHttpException; + } + } diff --git a/app/Models/BudgetLimit.php b/app/Models/BudgetLimit.php index ba44ed72b0..0a05e24836 100644 --- a/app/Models/BudgetLimit.php +++ b/app/Models/BudgetLimit.php @@ -22,6 +22,7 @@ class BudgetLimit extends Model { protected $hidden = ['amount_encrypted']; + protected $dates = ['created_at', 'updated_at', 'startdate']; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo @@ -31,14 +32,6 @@ class BudgetLimit extends Model return $this->belongsTo('FireflyIII\Models\Budget'); } - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'startdate']; - } - /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ diff --git a/app/Models/Category.php b/app/Models/Category.php index 4ddb31a7a7..84e79ae404 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -1,11 +1,13 @@ $value) { $query->where($name, $value); - } $set = $query->get(['categories.*']); /** @var Category $category */ @@ -56,15 +59,6 @@ class Category extends Model } - /** - * @codeCoverageIgnore - * @return string[] - */ - public function getDates() - { - return ['created_at', 'updated_at', 'deleted_at']; - } - /** * @codeCoverageIgnore * @@ -111,4 +105,19 @@ class Category extends Model return $this->belongsTo('FireflyIII\User'); } + /** + * @param Category $value + * + * @return Category + */ + public static function routeBinder(Category $value) + { + if (Auth::check()) { + if ($value->user_id == Auth::user()->id) { + return $value; + } + } + throw new NotFoundHttpException; + } + } diff --git a/app/Models/Component.php b/app/Models/Component.php index 82ffc02f1c..3cdf904b4f 100644 --- a/app/Models/Component.php +++ b/app/Models/Component.php @@ -1,24 +1,14 @@ belongsTo('FireflyIII\Models\BudgetLimit'); } - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'startdate', 'enddate']; - } - /** * @param $value */ @@ -44,4 +39,25 @@ class LimitRepetition extends Model $this->attributes['amount'] = strval(round($value, 2)); } + + /** + * @param $value + * + * @return mixed + */ + public static function routeBinder($value) + { + if (Auth::check()) { + $object = LimitRepetition::where('limit_repetitions.id', $value) + ->leftjoin('budget_limits', 'budget_limits.id', '=', 'limit_repetitions.budget_limit_id') + ->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') + ->where('budgets.user_id', Auth::user()->id) + ->first(['limit_repetitions.*']); + if ($object) { + return $object; + } + } + throw new NotFoundHttpException; + } + } diff --git a/app/Models/PiggyBank.php b/app/Models/PiggyBank.php index d4e9e7c44b..73c1ab74db 100644 --- a/app/Models/PiggyBank.php +++ b/app/Models/PiggyBank.php @@ -1,10 +1,12 @@ hasMany('FireflyIII\Models\PiggyBankRepetition'); } - /** - * @return string[] - */ - public function getDates() - { - return ['created_at', 'updated_at', 'deleted_at', 'startdate', 'targetdate']; - } - /** * * @param $value @@ -118,4 +114,19 @@ class PiggyBank extends Model { $this->attributes['targetamount'] = strval(round($value, 2)); } + + /** + * @param PiggyBank $value + * + * @return PiggyBank + */ + public static function routeBinder(PiggyBank $value) + { + if (Auth::check()) { + if ($value->account->user_id == Auth::user()->id) { + return $value; + } + } + throw new NotFoundHttpException; + } } diff --git a/app/Models/PiggyBankEvent.php b/app/Models/PiggyBankEvent.php index e373ab93a1..1710da1617 100644 --- a/app/Models/PiggyBankEvent.php +++ b/app/Models/PiggyBankEvent.php @@ -19,18 +19,10 @@ use Illuminate\Database\Eloquent\Model; class PiggyBankEvent extends Model { + protected $dates = ['created_at', 'updated_at', 'date']; protected $fillable = ['piggy_bank_id', 'transaction_journal_id', 'date', 'amount']; protected $hidden = ['amount_encrypted']; - /** - * @return array - */ - /** @noinspection PhpMissingParentCallCommonInspection */ - public function getDates() - { - return ['created_at', 'updated_at', 'date']; - } - /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/app/Models/PiggyBankRepetition.php b/app/Models/PiggyBankRepetition.php index 25ada5c27b..b8fb7eec61 100644 --- a/app/Models/PiggyBankRepetition.php +++ b/app/Models/PiggyBankRepetition.php @@ -24,14 +24,7 @@ class PiggyBankRepetition extends Model protected $fillable = ['piggy_bank_id', 'startdate', 'targetdate', 'currentamount']; protected $hidden = ['currentamount_encrypted']; - - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'startdate', 'targetdate']; - } + protected $dates = ['created_at', 'updated_at', 'startdate', 'targetdate']; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo diff --git a/app/Models/Preference.php b/app/Models/Preference.php index d66b36476e..641054e3f4 100644 --- a/app/Models/Preference.php +++ b/app/Models/Preference.php @@ -23,6 +23,7 @@ class Preference extends Model protected $fillable = ['user_id', 'data', 'name']; protected $hidden = ['data_encrypted', 'name_encrypted']; + protected $dates = ['created_at', 'updated_at']; /** * @param $value @@ -39,14 +40,6 @@ class Preference extends Model return json_decode($data); } - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at']; - } - /** * @param $value */ diff --git a/app/Models/Role.php b/app/Models/Role.php index 47af6ddcf2..6eaa81e92b 100644 --- a/app/Models/Role.php +++ b/app/Models/Role.php @@ -20,4 +20,5 @@ use Zizaco\Entrust\EntrustRole; */ class Role extends EntrustRole { + } diff --git a/app/Models/Rule.php b/app/Models/Rule.php new file mode 100644 index 0000000000..faf2110825 --- /dev/null +++ b/app/Models/Rule.php @@ -0,0 +1,88 @@ +belongsTo('FireflyIII\User'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function ruleGroup() + { + return $this->belongsTo('FireflyIII\Models\RuleGroup'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function ruleActions() + { + return $this->hasMany('FireflyIII\Models\RuleAction'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function ruleTriggers() + { + return $this->hasMany('FireflyIII\Models\RuleTrigger'); + } + + /** + * @param Rule $value + * + * @return Rule + */ + public static function routeBinder(Rule $value) + { + if (Auth::check()) { + if ($value->user_id == Auth::user()->id) { + return $value; + } + } + throw new NotFoundHttpException; + } + +} diff --git a/app/Models/RuleAction.php b/app/Models/RuleAction.php new file mode 100644 index 0000000000..fd65f781d5 --- /dev/null +++ b/app/Models/RuleAction.php @@ -0,0 +1,38 @@ +belongsTo('FireflyIII\Models\Rule'); + } +} diff --git a/app/Models/RuleGroup.php b/app/Models/RuleGroup.php new file mode 100644 index 0000000000..88c3733836 --- /dev/null +++ b/app/Models/RuleGroup.php @@ -0,0 +1,70 @@ +belongsTo('FireflyIII\User'); + } + + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function rules() + { + return $this->hasMany('FireflyIII\Models\Rule'); + } + + /** + * @param RuleGroup $value + * + * @return Rule + */ + public static function routeBinder(RuleGroup $value) + { + if (Auth::check()) { + if ($value->user_id == Auth::user()->id) { + return $value; + } + } + throw new NotFoundHttpException; + } +} diff --git a/app/Models/RuleTrigger.php b/app/Models/RuleTrigger.php new file mode 100644 index 0000000000..fb504433a8 --- /dev/null +++ b/app/Models/RuleTrigger.php @@ -0,0 +1,38 @@ +belongsTo('FireflyIII\Models\Rule'); + } +} diff --git a/app/Models/Tag.php b/app/Models/Tag.php index d1bd328143..f9894ef980 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -2,12 +2,13 @@ namespace FireflyIII\Models; +use Auth; use Carbon\Carbon; use Crypt; use FireflyIII\User; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; -use Watson\Validating\ValidatingTrait; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * FireflyIII\Models\Tag @@ -29,18 +30,8 @@ use Watson\Validating\ValidatingTrait; */ class Tag extends Model { - use ValidatingTrait; - protected $fillable = ['user_id', 'tag', 'date', 'description', 'longitude', 'latitude', 'zoomLevel', 'tagMode']; - protected $rules - = [ - 'tag' => 'required|min:1', - 'description' => 'min:1', - 'date' => 'date', - 'latitude' => 'numeric|min:-90|max:90', - 'longitude' => 'numeric|min:-90|max:90', - 'tagMode' => 'required|in:nothing,balancingAct,advancePayment' - ]; + protected $dates = ['created_at', 'updated_at', 'date']; /** * @param array $fields @@ -74,15 +65,6 @@ class Tag extends Model } - /** - * @codeCoverageIgnore - * @return string[] - */ - public function getDates() - { - return ['created_at', 'updated_at', 'date']; - } - /** * Save the model to the database. * @@ -166,4 +148,22 @@ class Tag extends Model { return $this->belongsTo('FireflyIII\User'); } + + + /** + * @param Tag $value + * + * @return Tag + */ + public static function routeBinder(Tag $value) + { + if (Auth::check()) { + if ($value->user_id == Auth::user()->id) { + return $value; + } + } + throw new NotFoundHttpException; + } + + } diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index 1bdd1148a1..2357277d52 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -33,8 +33,10 @@ class Transaction extends Model 'account_id' => 'required|exists:accounts,id', 'transaction_journal_id' => 'required|exists:transaction_journals,id', 'description' => 'between:1,255', - 'amount' => 'required|numeric' + 'amount' => 'required|numeric', ]; + protected $dates = ['created_at', 'updated_at', 'deleted_at']; + use SoftDeletes, ValidatingTrait; /** @@ -55,14 +57,6 @@ class Transaction extends Model return $value; } - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'deleted_at']; - } - /** * @param EloquentBuilder $query * @param Carbon $date diff --git a/app/Models/TransactionCurrency.php b/app/Models/TransactionCurrency.php index bd9b6db6ad..1ed3691164 100644 --- a/app/Models/TransactionCurrency.php +++ b/app/Models/TransactionCurrency.php @@ -1,9 +1,11 @@ hasMany('FireflyIII\Models\TransactionJournal'); } + + /** + * @param TransactionCurrency $currency + * + * @return TransactionCurrency + */ + public static function routeBinder(TransactionCurrency $currency) + { + if (Auth::check()) { + return $currency; + } + throw new NotFoundHttpException; + } } diff --git a/app/Models/TransactionGroup.php b/app/Models/TransactionGroup.php index 5d2830778d..51275cf773 100644 --- a/app/Models/TransactionGroup.php +++ b/app/Models/TransactionGroup.php @@ -22,13 +22,7 @@ class TransactionGroup extends Model { use SoftDeletes; - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'deleted_at']; - } + protected $dates = ['created_at', 'updated_at', 'deleted_at']; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany diff --git a/app/Models/TransactionJournal.php b/app/Models/TransactionJournal.php index ab4ed569ec..c69f4c02b7 100644 --- a/app/Models/TransactionJournal.php +++ b/app/Models/TransactionJournal.php @@ -1,5 +1,6 @@ 'required|exists:users,id', @@ -68,7 +71,7 @@ class TransactionJournal extends Model 'description' => 'required|between:1,1024', 'completed' => 'required|boolean', 'date' => 'required|date', - 'encrypted' => 'required|boolean' + 'encrypted' => 'required|boolean', ]; /** @@ -138,72 +141,6 @@ class TransactionJournal extends Model } - /** - * @param Tag $tag - * @param $amount - * - * @return string - */ - protected function amountByTagAdvancePayment(Tag $tag, $amount) - { - if ($this->isWithdrawal()) { - $others = $tag->transactionJournals()->transactionTypes([TransactionType::DEPOSIT])->get(); - foreach ($others as $other) { - $amount = bcsub($amount, $other->amount_positive); - } - - return $amount; - } - if ($this->isDeposit()) { - return '0'; - } - - return $amount; - } - - /** - * @param $tag - * @param $amount - * - * @return string - */ - protected function amountByTagBalancingAct($tag, $amount) - { - if ($this->isWithdrawal()) { - $transfer = $tag->transactionJournals()->transactionTypes([TransactionType::TRANSFER])->first(); - if ($transfer) { - $amount = bcsub($amount, $transfer->amount_positive); - - return $amount; - } - } - - return $amount; - } - - /** - * Assuming the journal has only one tag. Parameter amount is used as fallback. - * - * @param Tag $tag - * @param string $amount - * - * @return string - */ - protected function amountByTag(Tag $tag, $amount) - { - if ($tag->tagMode == 'advancePayment') { - return $this->amountByTagAdvancePayment($tag, $amount); - } - - if ($tag->tagMode == 'balancingAct') { - return $this->amountByTagBalancingAct($tag, $amount); - - } - - return $amount; - - } - /** * @codeCoverageIgnore * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany @@ -213,27 +150,6 @@ class TransactionJournal extends Model return $this->belongsToMany('FireflyIII\Models\Tag'); } - /** - * @param string $amount - * - * @return string - */ - public function amountByTags($amount) - { - $firstBalancingAct = $this->tags()->where('tagMode', 'balancingAct')->first(); - if ($firstBalancingAct) { - return $this->amountByTag($firstBalancingAct, $amount); - } - - $firstAdvancePayment = $this->tags()->where('tagMode', 'advancePayment')->first(); - if ($firstAdvancePayment) { - return $this->amountByTag($firstAdvancePayment, $amount); - } - - return $amount; - } - - /** * @codeCoverageIgnore * @return \Illuminate\Database\Eloquent\Relations\HasMany @@ -243,15 +159,6 @@ class TransactionJournal extends Model return $this->hasMany('FireflyIII\Models\Transaction'); } - /** - * @codeCoverageIgnore - * @return string[] - */ - public function getDates() - { - return ['created_at', 'updated_at', 'date', 'deleted_at']; - } - /** * Save the model to the database. * @@ -288,15 +195,7 @@ class TransactionJournal extends Model */ public function getDestinationAccountAttribute() { - $cache = new CacheProperties; - $cache->addProperty($this->id); - $cache->addProperty('destinationAccount'); - - if ($cache->has()) { - return $cache->get(); // @codeCoverageIgnore - } $account = $this->transactions()->where('amount', '>', 0)->first()->account; - $cache->store($account); return $account; } @@ -306,16 +205,8 @@ class TransactionJournal extends Model */ public function getSourceAccountAttribute() { - $cache = new CacheProperties; - $cache->addProperty($this->id); - $cache->addProperty('sourceAccount'); - if ($cache->has()) { - return $cache->get(); // @codeCoverageIgnore - } $account = $this->transactions()->where('amount', '<', 0)->first()->account; - $cache->store($account); - return $account; } @@ -328,21 +219,6 @@ class TransactionJournal extends Model return $this->hasMany('FireflyIII\Models\PiggyBankEvent'); } - /** - * @codeCoverageIgnore - * - * @param EloquentBuilder $query - * @param Account $account - */ - public function scopeAccountIs(EloquentBuilder $query, Account $account) - { - if (!isset($this->joinedTransactions)) { - $query->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id'); - $this->joinedTransactions = true; - } - $query->where('transactions.account_id', $account->id); - } - /** * @codeCoverageIgnore * @@ -369,19 +245,6 @@ class TransactionJournal extends Model return $query->where('transaction_journals.date', '<=', $date->format('Y-m-d 00:00:00')); } - /** - * @codeCoverageIgnore - * - * @param EloquentBuilder $query - * @param Carbon $date - * - * @return EloquentBuilder - */ - public function scopeOnDate(EloquentBuilder $query, Carbon $date) - { - return $query->where('date', '=', $date->format('Y-m-d')); - } - /** * @codeCoverageIgnore * @@ -525,4 +388,26 @@ class TransactionJournal extends Model return $this->transactionType->isOpeningBalance(); } + + /** + * @param $value + * + * @return mixed + * @throws NotFoundHttpException + */ + public static function routeBinder($value) + { + if (Auth::check()) { + $validTypes = [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER]; + $object = TransactionJournal::where('transaction_journals.id', $value) + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->whereIn('transaction_types.type', $validTypes) + ->where('user_id', Auth::user()->id)->first(['transaction_journals.*']); + if ($object) { + return $object; + } + } + + throw new NotFoundHttpException; + } } diff --git a/app/Models/TransactionType.php b/app/Models/TransactionType.php index 6df752b214..f3201469c1 100644 --- a/app/Models/TransactionType.php +++ b/app/Models/TransactionType.php @@ -24,13 +24,7 @@ class TransactionType extends Model const TRANSFER = 'Transfer'; const OPENING_BALANCE = 'Opening balance'; - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'deleted_at']; - } + protected $dates = ['created_at', 'updated_at', 'deleted_at']; /** * @return bool @@ -65,6 +59,8 @@ class TransactionType extends Model } /** + * @codeCoverageIgnore + * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function transactionJournals() diff --git a/app/Handlers/Events/.gitkeep b/app/Policies/.gitkeep old mode 100644 new mode 100755 similarity index 100% rename from app/Handlers/Events/.gitkeep rename to app/Policies/.gitkeep diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php old mode 100644 new mode 100755 index 68afc940c3..ca50e9b7ee --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -1,4 +1,6 @@ -app->bind( - 'Illuminate\Contracts\Auth\Registrar', - 'FireflyIII\Services\Registrar' - ); - + // } - } diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php new file mode 100755 index 0000000000..7d3f4d2b73 --- /dev/null +++ b/app/Providers/AuthServiceProvider.php @@ -0,0 +1,38 @@ + 'FireflyIII\Policies\ModelPolicy', + ]; + + /** + * Register any application authentication / authorization services. + * + * @param \Illuminate\Contracts\Auth\Access\Gate $gate + * + * @return void + */ + public function boot(GateContract $gate) + { + $this->registerPolicies($gate); + + // + } +} diff --git a/app/Providers/BusServiceProvider.php b/app/Providers/BusServiceProvider.php deleted file mode 100644 index dc2e86ac21..0000000000 --- a/app/Providers/BusServiceProvider.php +++ /dev/null @@ -1,44 +0,0 @@ -mapUsing( - function ($command) { - return Dispatcher::simpleMapping( - $command, 'FireflyIII\Commands', 'FireflyIII\Handlers\Commands' - ); - } - ); - } - - /** - * Register any application services. - * - * @return void - */ - public function register() - { - // - } - -} diff --git a/app/Providers/ConfigServiceProvider.php b/app/Providers/ConfigServiceProvider.php deleted file mode 100644 index 7ee3b11047..0000000000 --- a/app/Providers/ConfigServiceProvider.php +++ /dev/null @@ -1,30 +0,0 @@ - [ - 'FireflyIII\Handlers\Events\RescanJournal', + 'FireflyIII\Events\TransactionJournalUpdated' => [ + 'FireflyIII\Handlers\Events\ScanForBillsAfterUpdate', + 'FireflyIII\Handlers\Events\UpdateJournalConnection', + 'FireflyIII\Handlers\Events\FireRulesForUpdate', ], - 'FireflyIII\Events\JournalCreated' => [ + 'FireflyIII\Events\TransactionJournalStored' => [ + 'FireflyIII\Handlers\Events\ScanForBillsAfterStore', + 'FireflyIII\Handlers\Events\ConnectJournalToPiggyBank', - ] + 'FireflyIII\Handlers\Events\FireRulesForStore', + ], ]; + /** * Register any other events for your application. * @@ -82,6 +89,7 @@ class EventServiceProvider extends ServiceProvider ); + // } /** diff --git a/app/Providers/FireflyServiceProvider.php b/app/Providers/FireflyServiceProvider.php index 81df15ccac..e14c051aae 100644 --- a/app/Providers/FireflyServiceProvider.php +++ b/app/Providers/FireflyServiceProvider.php @@ -11,6 +11,7 @@ use FireflyIII\Support\Twig\Budget; use FireflyIII\Support\Twig\General; use FireflyIII\Support\Twig\Journal; use FireflyIII\Support\Twig\PiggyBank; +use FireflyIII\Support\Twig\Rule; use FireflyIII\Support\Twig\Translation; use FireflyIII\Validation\FireflyValidator; use Illuminate\Support\ServiceProvider; @@ -44,6 +45,7 @@ class FireflyServiceProvider extends ServiceProvider Twig::addExtension(new Journal); Twig::addExtension(new Budget); Twig::addExtension(new Translation); + Twig::addExtension(new Rule); } /** @@ -52,7 +54,6 @@ class FireflyServiceProvider extends ServiceProvider public function register() { - $this->app->bind( 'preferences', function () { return new Preferences; @@ -90,6 +91,8 @@ class FireflyServiceProvider extends ServiceProvider $this->app->bind('FireflyIII\Repositories\Currency\CurrencyRepositoryInterface', 'FireflyIII\Repositories\Currency\CurrencyRepository'); $this->app->bind('FireflyIII\Repositories\Tag\TagRepositoryInterface', 'FireflyIII\Repositories\Tag\TagRepository'); $this->app->bind('FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface', 'FireflyIII\Repositories\Attachment\AttachmentRepository'); + $this->app->bind('FireflyIII\Repositories\Rule\RuleRepositoryInterface', 'FireflyIII\Repositories\Rule\RuleRepository'); + $this->app->bind('FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface', 'FireflyIII\Repositories\RuleGroup\RuleGroupRepository'); $this->app->bind('FireflyIII\Support\Search\SearchInterface', 'FireflyIII\Support\Search\Search'); // CSV import diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php old mode 100644 new mode 100755 index f946ad464e..6e583159bf --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -1,4 +1,6 @@ -group( ['namespace' => $this->namespace], function ($router) { - /** @noinspection PhpIncludeInspection */ require app_path('Http/routes.php'); } ); } - } diff --git a/app/Providers/TestingServiceProvider.php b/app/Providers/TestingServiceProvider.php deleted file mode 100644 index a548521e04..0000000000 --- a/app/Providers/TestingServiceProvider.php +++ /dev/null @@ -1,29 +0,0 @@ -app->environment() == 'testing') { - $this->app['config']['session.driver'] = 'native'; - } - } - -} diff --git a/app/Repositories/Account/AccountRepository.php b/app/Repositories/Account/AccountRepository.php index a034e4534f..996ba8ca59 100644 --- a/app/Repositories/Account/AccountRepository.php +++ b/app/Repositories/Account/AccountRepository.php @@ -61,6 +61,18 @@ class AccountRepository implements AccountRepositoryInterface return true; } + /** + * @deprecated + * + * @param $accountId + * + * @return Account + */ + public function find($accountId) + { + return Auth::user()->accounts()->findOrNew($accountId); + } + /** * @param array $types * @@ -80,10 +92,10 @@ class AccountRepository implements AccountRepositoryInterface return strtolower($account->name); } ); + return $result; } - /** * This method returns the users credit cards, along with some basic information about the * balance they have on their CC. To be used in the JSON boxes on the front page that say @@ -110,9 +122,10 @@ class AccountRepository implements AccountRepositoryInterface 'accounts.*', 'ccType.data as ccType', 'accountRole.data as accountRole', - DB::Raw('SUM(`transactions`.`amount`) AS `balance`') + DB::Raw('SUM(`transactions`.`amount`) AS `balance`'), ] ); + return $set; } @@ -143,6 +156,7 @@ class AccountRepository implements AccountRepositoryInterface } $result = $query->get(['accounts.*']); + return $result; } @@ -173,6 +187,7 @@ class AccountRepository implements AccountRepositoryInterface ->orderBy('transaction_journals.id', 'DESC') ->take(10) ->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']); + return $set; } @@ -319,7 +334,8 @@ class AccountRepository implements AccountRepositoryInterface { $journal = TransactionJournal ::orderBy('transaction_journals.date', 'ASC') - ->accountIs($account) + ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->where('transactions.account_id', $account->id) ->transactionTypes([TransactionType::OPENING_BALANCE]) ->orderBy('created_at', 'ASC') ->first(['transaction_journals.*']); @@ -373,6 +389,8 @@ class AccountRepository implements AccountRepositoryInterface * @param Account $account * @param array $data * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) // need the complexity. + * * @return Account */ public function update(Account $account, array $data) @@ -386,15 +404,10 @@ class AccountRepository implements AccountRepositoryInterface $this->updateMetadata($account, $data); $openingBalance = $this->openingBalanceTransaction($account); - - // if has openingbalance? if ($data['openingBalance'] != 0) { - // if opening balance, do an update: if ($openingBalance) { - // update existing opening balance. $this->updateInitialBalance($account, $openingBalance, $data); } else { - // create new opening balance. $type = $data['openingBalance'] < 0 ? 'expense' : 'revenue'; $opposingData = [ 'user' => $data['user'], @@ -463,29 +476,6 @@ class AccountRepository implements AccountRepositoryInterface return $newAccount; } - /** - * @param Account $account - * @param array $data - */ - protected function storeMetadata(Account $account, array $data) - { - $validFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType']; - foreach ($validFields as $field) { - if (isset($data[$field])) { - $metaData = new AccountMeta( - [ - 'account_id' => $account->id, - 'name' => $field, - 'data' => $data[$field] - ] - ); - $metaData->save(); - } - - - } - } - /** * @param Account $account * @param Account $opposing @@ -505,7 +495,7 @@ class AccountRepository implements AccountRepositoryInterface 'description' => 'Initial balance for "' . $account->name . '"', 'completed' => true, 'date' => $data['openingBalanceDate'], - 'encrypted' => true + 'encrypted' => true, ] ); @@ -534,33 +524,24 @@ class AccountRepository implements AccountRepositoryInterface /** * @param Account $account * @param array $data - * */ - protected function updateMetadata(Account $account, array $data) + protected function storeMetadata(Account $account, array $data) { $validFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType']; - foreach ($validFields as $field) { - $entry = $account->accountMeta()->where('name', $field)->first(); - - // update if new data is present: - if ($entry && isset($data[$field])) { - $entry->data = $data[$field]; - $entry->save(); - } - // no entry but data present? - if (!$entry && isset($data[$field])) { + if (isset($data[$field])) { $metaData = new AccountMeta( [ 'account_id' => $account->id, 'name' => $field, - 'data' => $data[$field] + 'data' => $data[$field], ] ); $metaData->save(); } - } + + } } /** @@ -573,7 +554,8 @@ class AccountRepository implements AccountRepositoryInterface protected function updateInitialBalance(Account $account, TransactionJournal $journal, array $data) { $journal->date = $data['openingBalanceDate']; - + $journal->save(); + /** @var Transaction $transaction */ foreach ($journal->transactions()->get() as $transaction) { if ($account->id == $transaction->account_id) { @@ -590,14 +572,34 @@ class AccountRepository implements AccountRepositoryInterface } /** - * @deprecated + * @param Account $account + * @param array $data * - * @param $accountId - * - * @return Account */ - public function find($accountId) + protected function updateMetadata(Account $account, array $data) { - return Auth::user()->accounts()->findOrNew($accountId); + $validFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType']; + + foreach ($validFields as $field) { + $entry = $account->accountMeta()->where('name', $field)->first(); + + if (isset($data[$field])) { + // update if new data is present: + if (!is_null($entry)) { + $entry->data = $data[$field]; + $entry->save(); + } else { + $metaData = new AccountMeta( + [ + 'account_id' => $account->id, + 'name' => $field, + 'data' => $data[$field], + ] + ); + $metaData->save(); + } + } + } + } } diff --git a/app/Repositories/Account/AccountRepositoryInterface.php b/app/Repositories/Account/AccountRepositoryInterface.php index b18ffb2807..628aca2d15 100644 --- a/app/Repositories/Account/AccountRepositoryInterface.php +++ b/app/Repositories/Account/AccountRepositoryInterface.php @@ -24,6 +24,14 @@ interface AccountRepositoryInterface */ public function countAccounts(array $types); + /** + * @param Account $account + * @param Account $moveTo + * + * @return boolean + */ + public function destroy(Account $account, Account $moveTo = null); + /** * @param $accountId * @@ -33,14 +41,6 @@ interface AccountRepositoryInterface */ public function find($accountId); - /** - * @param Account $account - * @param Account $moveTo - * - * @return boolean - */ - public function destroy(Account $account, Account $moveTo = null); - /** * @param array $types * @@ -48,14 +48,6 @@ interface AccountRepositoryInterface */ public function getAccounts(array $types); - /** - * @param TransactionJournal $journal - * @param Account $account - * - * @return Transaction - */ - public function getFirstTransaction(TransactionJournal $journal, Account $account); - /** * This method returns the users credit cards, along with some basic information about the * balance they have on their CC. To be used in the JSON boxes on the front page that say @@ -70,11 +62,12 @@ interface AccountRepositoryInterface public function getCreditCards(Carbon $date); /** - * Get the accounts of a user that have piggy banks connected to them. + * @param TransactionJournal $journal + * @param Account $account * - * @return Collection + * @return Transaction */ - public function getPiggyBankAccounts(); + public function getFirstTransaction(TransactionJournal $journal, Account $account); /** * @param Preference $preference @@ -101,9 +94,11 @@ interface AccountRepositoryInterface public function getJournals(Account $account, $page); /** - * @return string + * Get the accounts of a user that have piggy banks connected to them. + * + * @return Collection */ - public function sumOfEverything(); + public function getPiggyBankAccounts(); /** * Get savings accounts and the balance difference in the period. @@ -134,6 +129,11 @@ interface AccountRepositoryInterface */ public function store(array $data); + /** + * @return string + */ + public function sumOfEverything(); + /** * @param Account $account * @param array $data diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php index b07a37f45a..075065b77f 100644 --- a/app/Repositories/Bill/BillRepository.php +++ b/app/Repositories/Bill/BillRepository.php @@ -34,6 +34,24 @@ class BillRepository implements BillRepositoryInterface return $bill->delete(); } + /** + * @return Collection + */ + public function getActiveBills() + { + /** @var Collection $set */ + $set = Auth::user()->bills() + ->where('active', 1) + ->get( + [ + 'bills.*', + DB::Raw('(`bills`.`amount_min` + `bills`.`amount_max` / 2) as `expectedAmount`'), + ] + )->sortBy('name'); + + return $set; + } + /** * Returns all journals connected to these bills in the given range. Amount paid * is stored in "journalAmount" as a negative number. @@ -61,14 +79,13 @@ class BillRepository implements BillRepositoryInterface ->get( [ 'transaction_journals.bill_id', - DB::Raw('SUM(`transactions`.`amount`) as `journalAmount`') + DB::Raw('SUM(`transactions`.`amount`) as `journalAmount`'), ] ); return $set; } - /** * @return Collection */ @@ -125,6 +142,127 @@ class BillRepository implements BillRepositoryInterface return $set; } + /** + * Get the total amount of money paid for the users active bills in the date range given. + * This amount will be negative (they're expenses). + * + * @param Carbon $start + * @param Carbon $end + * + * @return string + */ + public function getBillsPaidInRange(Carbon $start, Carbon $end) + { + $amount = '0'; + $bills = $this->getActiveBills(); + + /** @var Bill $bill */ + foreach ($bills as $bill) { + $ranges = $this->getRanges($bill, $start, $end); + + foreach ($ranges as $range) { + $paid = $bill->transactionjournals() + ->before($range['end']) + ->after($range['start']) + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); + } + ) + ->first([DB::Raw('SUM(`transactions`.`amount`) as `sum_amount`')]); + $amount = bcadd($amount, $paid->sum_amount); + } + } + + return $amount; + } + + /** + * Get the total amount of money due for the users active bills in the date range given. This amount will be positive. + * + * @param Carbon $start + * @param Carbon $end + * + * @return string + */ + public function getBillsUnpaidInRange(Carbon $start, Carbon $end) + { + $amount = '0'; + $bills = $this->getActiveBills(); + + /** @var Bill $bill */ + foreach ($bills as $bill) { + $ranges = $this->getRanges($bill, $start, $end); + $paidBill = '0'; + foreach ($ranges as $range) { + $paid = $bill->transactionjournals() + ->before($range['end']) + ->after($range['start']) + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '>', 0); + } + ) + ->first([DB::Raw('SUM(`transactions`.`amount`) as `sum_amount`')]); + $paidBill = bcadd($paid->sum_amount, $paidBill); + } + if ($paidBill == 0) { + $amount = bcadd($amount, $bill->expectedAmount); + } + } + + return $amount; + } + + /** + * This method will tell you if you still have a CC bill to pay. Amount will be positive if the amount + * has been paid, otherwise it will be negative. + * + * @param Carbon $start + * @param Carbon $end + * + * @return string + */ + public function getCreditCardBill(Carbon $start, Carbon $end) + { + + /** @var AccountRepositoryInterface $accountRepository */ + $accountRepository = app('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $amount = '0'; + $creditCards = $accountRepository->getCreditCards($end); // Find credit card accounts and possibly unpaid credit card bills. + /** @var Account $creditCard */ + foreach ($creditCards as $creditCard) { + if ($creditCard->balance == 0) { + // find a transfer TO the credit card which should account for anything paid. If not, the CC is not yet used. + $set = TransactionJournal::whereIn( + 'transaction_journals.id', function (Builder $q) use ($creditCard, $start, $end) { + $q->select('transaction_journals.id') + ->from('transactions') + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->where('transactions.account_id', $creditCard->id) + ->where('transactions.amount', '>', 0)// this makes the filter unnecessary. + ->where('transaction_journals.user_id', Auth::user()->id) + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->where('transaction_types.type', TransactionType::TRANSFER); + } + )->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '>', 0); + } + )->first([DB::Raw('SUM(`transactions`.`amount`) as `sum_amount`')]); + + $amount = bcadd($amount, $set->sum_amount); + } else { + $amount = bcadd($amount, $creditCard->balance); + } + } + + return $amount; + + } + /** * This method also returns the amount of the journal in "journalAmount" * for easy access. @@ -146,6 +284,7 @@ class BillRepository implements BillRepositoryInterface ->orderBy('transaction_journals.order', 'ASC') ->orderBy('transaction_journals.id', 'DESC') ->get(['transaction_journals.*', 'transactions.amount as journalAmount']); + return $set; } @@ -172,8 +311,9 @@ class BillRepository implements BillRepositoryInterface */ public function getPossiblyRelatedJournals(Bill $bill) { - $set = DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)->get( - ['transaction_journal_id'] + $set = new Collection( + DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max) + ->get(['transaction_journal_id']) ); $ids = $set->pluck('transaction_journal_id')->toArray(); @@ -391,6 +531,22 @@ class BillRepository implements BillRepositoryInterface return $bill; } + /** + * @param float $amount + * @param float $min + * @param float $max + * + * @return bool + */ + protected function doAmountMatch($amount, $min, $max) + { + if ($amount >= $min && $amount <= $max) { + return true; + } + + return false; + } + /** * @param array $matches * @param $description @@ -412,159 +568,4 @@ class BillRepository implements BillRepositoryInterface return $wordMatch; } - - /** - * @param float $amount - * @param float $min - * @param float $max - * - * @return bool - */ - protected function doAmountMatch($amount, $min, $max) - { - if ($amount >= $min && $amount <= $max) { - return true; - } - - return false; - } - - /** - * Get the total amount of money paid for the users active bills in the date range given. - * This amount will be negative (they're expenses). - * - * @param Carbon $start - * @param Carbon $end - * - * @return string - */ - public function getBillsPaidInRange(Carbon $start, Carbon $end) - { - $amount = '0'; - $bills = $this->getActiveBills(); - - /** @var Bill $bill */ - foreach ($bills as $bill) { - $ranges = $this->getRanges($bill, $start, $end); - - foreach ($ranges as $range) { - $paid = $bill->transactionjournals() - ->before($range['end']) - ->after($range['start']) - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); - } - ) - ->first([DB::Raw('SUM(`transactions`.`amount`) as `sum_amount`')]); - $amount = bcadd($amount, $paid->sum_amount); - } - } - return $amount; - } - - /** - * @return Collection - */ - public function getActiveBills() - { - /** @var Collection $set */ - $set = Auth::user()->bills() - ->where('active', 1) - ->get( - [ - 'bills.*', - DB::Raw('(`bills`.`amount_min` + `bills`.`amount_max` / 2) as `expectedAmount`') - ] - )->sortBy('name'); - - return $set; - } - - - /** - * Get the total amount of money due for the users active bills in the date range given. This amount will be positive. - * - * @param Carbon $start - * @param Carbon $end - * - * @return string - */ - public function getBillsUnpaidInRange(Carbon $start, Carbon $end) - { - $amount = '0'; - $bills = $this->getActiveBills(); - - /** @var Bill $bill */ - foreach ($bills as $bill) { - $ranges = $this->getRanges($bill, $start, $end); - $paidBill = '0'; - foreach ($ranges as $range) { - $paid = $bill->transactionjournals() - ->before($range['end']) - ->after($range['start']) - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '>', 0); - } - ) - ->first([DB::Raw('SUM(`transactions`.`amount`) as `sum_amount`')]); - $paidBill = bcadd($paid->sum_amount, $paidBill); - } - if ($paidBill == 0) { - $amount = bcadd($amount, $bill->expectedAmount); - } - } - return $amount; - } - - /** - * This method will tell you if you still have a CC bill to pay. Amount will be positive if the amount - * has been paid, otherwise it will be negative. - * - * @param Carbon $start - * @param Carbon $end - * - * @return string - */ - public function getCreditCardBill(Carbon $start, Carbon $end) - { - - /** @var AccountRepositoryInterface $accountRepository */ - $accountRepository = app('FireflyIII\Repositories\Account\AccountRepositoryInterface'); - $amount = '0'; - $creditCards = $accountRepository->getCreditCards($end); // Find credit card accounts and possibly unpaid credit card bills. - /** @var Account $creditCard */ - foreach ($creditCards as $creditCard) { - if ($creditCard->balance == 0) { - // find a transfer TO the credit card which should account for - // anything paid. If not, the CC is not yet used. - $set = TransactionJournal::whereIn( - 'transaction_journals.id', function (Builder $q) use ($creditCard, $start, $end) { - $q->select('transaction_journals.id') - ->from('transactions') - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->where('transactions.account_id', $creditCard->id) - ->where('transactions.amount', '>', 0)// this makes the filter unnecessary. - ->where('transaction_journals.user_id', Auth::user()->id) - ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) - ->where('transaction_types.type', TransactionType::TRANSFER); - } - )->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '>', 0); - } - )->first([DB::Raw('SUM(`transactions`.`amount`) as `sum_amount`')]); - - $amount = bcadd($amount, $set->sum_amount); - } else { - $amount = bcadd($amount, $creditCard->balance); - } - } - - return $amount; - - } } diff --git a/app/Repositories/Bill/BillRepositoryInterface.php b/app/Repositories/Bill/BillRepositoryInterface.php index 0cf52754bf..0cefc960c8 100644 --- a/app/Repositories/Bill/BillRepositoryInterface.php +++ b/app/Repositories/Bill/BillRepositoryInterface.php @@ -16,15 +16,42 @@ interface BillRepositoryInterface { /** - * This method will tell you if you still have a CC bill to pay. Amount will be negative if the amount - * has been paid + * @param Bill $bill * - * @param Carbon $start - * @param Carbon $end - * - * @return string + * @return mixed */ - public function getCreditCardBill(Carbon $start, Carbon $end); + public function destroy(Bill $bill); + + /** + * @return Collection + */ + public function getActiveBills(); + + /** + * Returns all journals connected to these bills in the given range. Amount paid + * is stored in "journalAmount" as a negative number. + * + * @param Collection $bills + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getAllJournalsInRange(Collection $bills, Carbon $start, Carbon $end); + + /** + * @return Collection + */ + public function getBills(); + + /** + * Gets the bills which have some kind of relevance to the accounts mentioned. + * + * @param Collection $accounts + * + * @return Collection + */ + public function getBillsForAccounts(Collection $accounts); /** * Get the total amount of money paid for the users active bills in the date range given. @@ -47,44 +74,15 @@ interface BillRepositoryInterface public function getBillsUnpaidInRange(Carbon $start, Carbon $end); /** - * @return Collection - */ - public function getActiveBills(); - - - /** - * @param Bill $bill + * This method will tell you if you still have a CC bill to pay. Amount will be negative if the amount + * has been paid * - * @return mixed - */ - public function destroy(Bill $bill); - - /** - * Returns all journals connected to these bills in the given range. Amount paid - * is stored in "journalAmount" as a negative number. + * @param Carbon $start + * @param Carbon $end * - * @param Collection $bills - * @param Carbon $start - * @param Carbon $end - * - * @return Collection + * @return string */ - public function getAllJournalsInRange(Collection $bills, Carbon $start, Carbon $end); - - - /** - * @return Collection - */ - public function getBills(); - - /** - * Gets the bills which have some kind of relevance to the accounts mentioned. - * - * @param Collection $accounts - * - * @return Collection - */ - public function getBillsForAccounts(Collection $accounts); + public function getCreditCardBill(Carbon $start, Carbon $end); /** * @param Bill $bill diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 2750dcfe6a..dbf9d47c31 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -25,6 +25,19 @@ use Input; class BudgetRepository extends ComponentRepository implements BudgetRepositoryInterface { + /** + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * @param Collection $accounts + * + * @return string + */ + public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, Collection $accounts) + { + return $this->commonBalanceInPeriod($budget, $start, $end, $accounts); + } + /** * @return void */ @@ -35,6 +48,299 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn } + /** + * @param Budget $budget + * + * @return boolean + */ + public function destroy(Budget $budget) + { + $budget->delete(); + + return true; + } + + /** + * @param Budget $budget + * + * @return Carbon + */ + public function firstActivity(Budget $budget) + { + $first = $budget->transactionjournals()->orderBy('date', 'ASC')->first(); + if ($first) { + return $first->date; + } + + return new Carbon; + } + + /** + * @return Collection + */ + public function getActiveBudgets() + { + /** @var Collection $set */ + $set = Auth::user()->budgets()->where('active', 1)->get(); + + $set = $set->sortBy( + function (Budget $budget) { + return strtolower($budget->name); + } + ); + + return $set; + } + + /** + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end) + { + /** @var Collection $repetitions */ + return LimitRepetition:: + leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') + ->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') + ->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00')) + ->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00')) + ->where('budgets.user_id', Auth::user()->id) + ->get(['limit_repetitions.*', 'budget_limits.budget_id']); + } + + /** + * Get the budgeted amounts for each budgets in each year. + * + * @param Collection $budgets + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getBudgetedPerYear(Collection $budgets, Carbon $start, Carbon $end) + { + $budgetIds = $budgets->pluck('id')->toArray(); + + $set = Auth::user()->budgets() + ->leftJoin('budget_limits', 'budgets.id', '=', 'budget_limits.budget_id') + ->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') + ->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d')) + ->where('limit_repetitions.enddate', '<=', $end->format('Y-m-d')) + ->groupBy('budgets.id') + ->groupBy('dateFormatted') + ->whereIn('budgets.id', $budgetIds) + ->get( + [ + 'budgets.*', + DB::Raw('DATE_FORMAT(`limit_repetitions`.`startdate`,"%Y") as `dateFormatted`'), + DB::Raw('SUM(`limit_repetitions`.`amount`) as `budgeted`'), + ] + ); + + return $set; + } + + /** + * @return Collection + */ + public function getBudgets() + { + /** @var Collection $set */ + $set = Auth::user()->budgets()->get(); + + $set = $set->sortBy( + function (Budget $budget) { + return strtolower($budget->name); + } + ); + + return $set; + } + + /** + * Returns an array with every budget in it and the expenses for each budget + * per month. + * + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function getBudgetsAndExpensesPerMonth(Collection $accounts, Carbon $start, Carbon $end) + { + $ids = $accounts->pluck('id')->toArray(); + + /** @var Collection $set */ + $set = Auth::user()->budgets() + ->leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id') + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id') + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); + } + ) + ->groupBy('budgets.id') + ->groupBy('dateFormatted') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->whereIn('transactions.account_id', $ids) + ->get( + [ + 'budgets.*', + DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y-%m") AS `dateFormatted`'), + DB::Raw('SUM(`transactions`.`amount`) AS `sumAmount`'), + ] + ); + + $set = $set->sortBy( + function (Budget $budget) { + return strtolower($budget->name); + } + ); + + $return = []; + foreach ($set as $budget) { + $id = $budget->id; + if (!isset($return[$id])) { + $return[$id] = [ + 'budget' => $budget, + 'entries' => [], + ]; + } + // store each entry: + $return[$id]['entries'][$budget->dateFormatted] = $budget->sumAmount; + } + + return $return; + } + + /** + * Returns an array with every budget in it and the expenses for each budget + * per year for. + * + * @param Collection $budgets + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) // it's a query. + * + * @return array + */ + public function getBudgetsAndExpensesPerYear(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end) + { + $ids = $accounts->pluck('id')->toArray(); + $budgetIds = $budgets->pluck('id')->toArray(); + + /** @var Collection $set */ + $set = Auth::user()->budgets() + ->leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id') + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id') + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); + } + ) + ->groupBy('budgets.id') + ->groupBy('dateFormatted') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->whereIn('transactions.account_id', $ids) + ->whereIn('budgets.id', $budgetIds) + ->get( + [ + 'budgets.*', + DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y") AS `dateFormatted`'), + DB::Raw('SUM(`transactions`.`amount`) AS `sumAmount`'), + ] + ); + + $set = $set->sortBy( + function (Budget $budget) { + return strtolower($budget->name); + } + ); + + $return = []; + foreach ($set as $budget) { + $id = $budget->id; + if (!isset($return[$id])) { + $return[$id] = [ + 'budget' => $budget, + 'entries' => [], + ]; + } + // store each entry: + $return[$id]['entries'][$budget->dateFormatted] = $budget->sumAmount; + } + + return $return; + } + + /** + * Returns a list of budgets, budget limits and limit repetitions + * (doubling any of them in a left join) + * + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getBudgetsAndLimitsInRange(Carbon $start, Carbon $end) + { + /** @var Collection $set */ + $set = Auth::user() + ->budgets() + ->leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id') + ->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') + ->where( + function (Builder $query) use ($start, $end) { + $query->where( + function (Builder $query) use ($start, $end) { + $query->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d')); + $query->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d')); + } + ); + $query->orWhere( + function (Builder $query) { + $query->whereNull('limit_repetitions.startdate'); + $query->whereNull('limit_repetitions.enddate'); + } + ); + } + ) + ->get(['budgets.*', 'limit_repetitions.startdate', 'limit_repetitions.enddate', 'limit_repetitions.amount']); + + $set = $set->sortBy( + function (Budget $budget) { + return strtolower($budget->name); + } + ); + + return $set; + + } + + /** + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * + * @return LimitRepetition|null + */ + public function getCurrentRepetition(Budget $budget, Carbon $start, Carbon $end) + { + $data = $budget->limitrepetitions() + ->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00')) + ->where('limit_repetitions.enddate', $end->format('Y-m-d 00:00:00')) + ->first(['limit_repetitions.*']); + + return $data; + } + /** * Returns the expenses for this budget grouped per day, with the date * in "date" (a string, not a Carbon) and the amount in "dailyAmount". @@ -89,185 +395,13 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn ->get( [ DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y-%m") AS `dateFormatted`'), - DB::Raw('SUM(`transactions`.`amount`) as `monthlyAmount`') + DB::Raw('SUM(`transactions`.`amount`) as `monthlyAmount`'), ] ); return $set; } - /** - * @param Budget $budget - * - * @return boolean - */ - public function destroy(Budget $budget) - { - $budget->delete(); - - return true; - } - - /** - * @return Collection - */ - public function getActiveBudgets() - { - /** @var Collection $set */ - $set = Auth::user()->budgets()->where('active', 1)->get(); - - $set = $set->sortBy( - function (Budget $budget) { - return strtolower($budget->name); - } - ); - - return $set; - } - - /** - * Returns a list of budgets, budget limits and limit repetitions - * (doubling any of them in a left join) - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function getBudgetsAndLimitsInRange(Carbon $start, Carbon $end) - { - /** @var Collection $set */ - $set = Auth::user() - ->budgets() - ->leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id') - ->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') - ->where( - function (Builder $query) use ($start, $end) { - $query->where( - function (Builder $query) use ($start, $end) { - $query->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d')); - $query->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d')); - } - ); - $query->orWhere( - function (Builder $query) { - $query->whereNull('limit_repetitions.startdate'); - $query->whereNull('limit_repetitions.enddate'); - } - ); - } - ) - ->get(['budgets.*', 'limit_repetitions.startdate', 'limit_repetitions.enddate', 'limit_repetitions.amount']); - - $set = $set->sortBy( - function (Budget $budget) { - return strtolower($budget->name); - } - ); - - return $set; - - } - - /** - * @param Budget $budget - * - * @return Carbon - */ - public function firstActivity(Budget $budget) - { - $first = $budget->transactionjournals()->orderBy('date', 'ASC')->first(); - if ($first) { - return $first->date; - } - - return new Carbon; - } - - /** - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end) - { - /** @var Collection $repetitions */ - return LimitRepetition:: - leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') - ->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') - ->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00')) - ->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00')) - ->where('budgets.user_id', Auth::user()->id) - ->get(['limit_repetitions.*', 'budget_limits.budget_id']); - } - - /** - * Returns an array with the following key:value pairs: - * - * yyyy-mm-dd: - * - * Where yyyy-mm-dd is the date and is the money spent using DEPOSITS in the $budget - * from all the users accounts. - * - * @param Budget $budget - * @param Carbon $start - * @param Carbon $end - * - * @return array - */ - public function spentPerDay(Budget $budget, Carbon $start, Carbon $end) - { - /** @var Collection $query */ - $query = $budget->transactionJournals() - ->transactionTypes([TransactionType::WITHDRAWAL]) - ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') - ->where('transactions.amount', '<', 0) - ->before($end) - ->after($start) - ->groupBy('dateFormatted')->get(['transaction_journals.date as dateFormatted', DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]); - - $return = []; - foreach ($query->toArray() as $entry) { - $return[$entry['dateFormatted']] = $entry['sum']; - } - - return $return; - } - - /** - * @return Collection - */ - public function getBudgets() - { - /** @var Collection $set */ - $set = Auth::user()->budgets()->get(); - - $set = $set->sortBy( - function (Budget $budget) { - return strtolower($budget->name); - } - ); - - return $set; - } - - /** - * @param Budget $budget - * @param Carbon $start - * @param Carbon $end - * - * @return LimitRepetition|null - */ - public function getCurrentRepetition(Budget $budget, Carbon $start, Carbon $end) - { - $data = $budget->limitrepetitions() - ->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00')) - ->where('limit_repetitions.enddate', $end->format('Y-m-d 00:00:00')) - ->first(['limit_repetitions.*']); - return $data; - } - /** * @param Budget $budget * @@ -283,64 +417,6 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn return Carbon::now()->startOfYear(); } - /** - * Returns an array with every budget in it and the expenses for each budget - * per month. - * - * @param Collection $accounts - * @param Carbon $start - * @param Carbon $end - * - * @return array - */ - public function getBudgetsAndExpensesPerMonth(Collection $accounts, Carbon $start, Carbon $end) - { - $ids = $accounts->pluck('id')->toArray(); - - /** @var Collection $set */ - $set = Auth::user()->budgets() - ->leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id') - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id') - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); - } - ) - ->groupBy('budgets.id') - ->groupBy('dateFormatted') - ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) - ->whereIn('transactions.account_id', $ids) - ->get( - [ - 'budgets.*', - DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y-%m") AS `dateFormatted`'), - DB::Raw('SUM(`transactions`.`amount`) AS `sumAmount`') - ] - ); - - $set = $set->sortBy( - function (Budget $budget) { - return strtolower($budget->name); - } - ); - - $return = []; - foreach ($set as $budget) { - $id = $budget->id; - if (!isset($return[$id])) { - $return[$id] = [ - 'budget' => $budget, - 'entries' => [], - ]; - } - // store each entry: - $return[$id]['entries'][$budget->dateFormatted] = $budget->sumAmount; - } - - return $return; - } - /** * @return Collection */ @@ -402,6 +478,7 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn { return Auth::user() ->transactionjournals() + ->transactionTypes([TransactionType::WITHDRAWAL]) ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') ->whereNull('budget_transaction_journal.id') ->before($end) @@ -446,185 +523,6 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn return $entry->journalAmount; } - /** - * @param Budget $budget - * @param Carbon $start - * @param Carbon $end - * @param Collection $accounts - * - * @return string - */ - public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, Collection $accounts) - { - return $this->commonBalanceInPeriod($budget, $start, $end, $accounts); - } - - /** - * @param array $data - * - * @return Budget - */ - public function store(array $data) - { - $newBudget = new Budget( - [ - 'user_id' => $data['user'], - 'name' => $data['name'], - ] - ); - $newBudget->save(); - - return $newBudget; - } - - - /** - * @param Budget $budget - * @param array $data - * - * @return Budget - */ - public function update(Budget $budget, array $data) - { - // update the account: - $budget->name = $data['name']; - $budget->active = $data['active']; - $budget->save(); - - return $budget; - } - - /** - * @param Budget $budget - * @param Carbon $date - * @param $amount - * - * @return BudgetLimit - */ - public function updateLimitAmount(Budget $budget, Carbon $date, $amount) - { - // there should be a budget limit for this startdate: - /** @var BudgetLimit $limit */ - $limit = $budget->budgetlimits()->where('budget_limits.startdate', $date)->first(['budget_limits.*']); - - if (!$limit) { - // if not, create one! - $limit = new BudgetLimit; - $limit->budget()->associate($budget); - $limit->startdate = $date; - $limit->amount = $amount; - $limit->repeat_freq = 'monthly'; - $limit->repeats = 0; - $limit->save(); - - // likewise, there should be a limit repetition to match the end date - // (which is always the end of the month) but that is caught by an event. - - } else { - if ($amount > 0) { - $limit->amount = $amount; - $limit->save(); - } else { - $limit->delete(); - } - } - - return $limit; - } - - /** - * Get the budgeted amounts for each budgets in each year. - * - * @param Collection $budgets - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function getBudgetedPerYear(Collection $budgets, Carbon $start, Carbon $end) - { - $budgetIds = $budgets->pluck('id')->toArray(); - - $set = Auth::user()->budgets() - ->leftJoin('budget_limits', 'budgets.id', '=', 'budget_limits.budget_id') - ->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') - ->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d')) - ->where('limit_repetitions.enddate', '<=', $end->format('Y-m-d')) - ->groupBy('budgets.id') - ->groupBy('dateFormatted') - ->whereIn('budgets.id', $budgetIds) - ->get( - [ - 'budgets.*', - DB::Raw('DATE_FORMAT(`limit_repetitions`.`startdate`,"%Y") as `dateFormatted`'), - DB::Raw('SUM(`limit_repetitions`.`amount`) as `budgeted`') - ] - ); - - return $set; - } - - /** - * Returns an array with every budget in it and the expenses for each budget - * per year for. - * - * @param Collection $budgets - * @param Collection $accounts - * @param Carbon $start - * @param Carbon $end - * - * @return array - */ - public function getBudgetsAndExpensesPerYear(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end) - { - $ids = $accounts->pluck('id')->toArray(); - $budgetIds = $budgets->pluck('id')->toArray(); - - /** @var Collection $set */ - $set = Auth::user()->budgets() - ->leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id') - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id') - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); - } - ) - ->groupBy('budgets.id') - ->groupBy('dateFormatted') - ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) - ->whereIn('transactions.account_id', $ids) - ->whereIn('budgets.id', $budgetIds) - ->get( - [ - 'budgets.*', - DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y") AS `dateFormatted`'), - DB::Raw('SUM(`transactions`.`amount`) AS `sumAmount`') - ] - ); - - $set = $set->sortBy( - function (Budget $budget) { - return strtolower($budget->name); - } - ); - - $return = []; - foreach ($set as $budget) { - $id = $budget->id; - if (!isset($return[$id])) { - $return[$id] = [ - 'budget' => $budget, - 'entries' => [], - ]; - } - // store each entry: - $return[$id]['entries'][$budget->dateFormatted] = $budget->sumAmount; - } - - return $return; - } - /** * Returns an array with the following key:value pairs: * @@ -716,11 +614,116 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn ->get( [ 't_from.account_id', 'budget_transaction_journal.budget_id', - DB::Raw('SUM(`t_from`.`amount`) AS `spent`') + DB::Raw('SUM(`t_from`.`amount`) AS `spent`'), ] ); return $set; } + + /** + * Returns an array with the following key:value pairs: + * + * yyyy-mm-dd: + * + * Where yyyy-mm-dd is the date and is the money spent using DEPOSITS in the $budget + * from all the users accounts. + * + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function spentPerDay(Budget $budget, Carbon $start, Carbon $end) + { + /** @var Collection $query */ + $query = $budget->transactionJournals() + ->transactionTypes([TransactionType::WITHDRAWAL]) + ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->where('transactions.amount', '<', 0) + ->before($end) + ->after($start) + ->groupBy('dateFormatted')->get(['transaction_journals.date as dateFormatted', DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]); + + $return = []; + foreach ($query->toArray() as $entry) { + $return[$entry['dateFormatted']] = $entry['sum']; + } + + return $return; + } + + /** + * @param array $data + * + * @return Budget + */ + public function store(array $data) + { + $newBudget = new Budget( + [ + 'user_id' => $data['user'], + 'name' => $data['name'], + ] + ); + $newBudget->save(); + + return $newBudget; + } + + /** + * @param Budget $budget + * @param array $data + * + * @return Budget + */ + public function update(Budget $budget, array $data) + { + // update the account: + $budget->name = $data['name']; + $budget->active = $data['active']; + $budget->save(); + + return $budget; + } + + /** + * @param Budget $budget + * @param Carbon $date + * @param $amount + * + * @return BudgetLimit + */ + public function updateLimitAmount(Budget $budget, Carbon $date, $amount) + { + // there should be a budget limit for this startdate: + /** @var BudgetLimit $limit */ + $limit = $budget->budgetlimits()->where('budget_limits.startdate', $date)->first(['budget_limits.*']); + + if (!$limit) { + // if not, create one! + $limit = new BudgetLimit; + $limit->budget()->associate($budget); + $limit->startdate = $date; + $limit->amount = $amount; + $limit->repeat_freq = 'monthly'; + $limit->repeats = 0; + $limit->save(); + + // likewise, there should be a limit repetition to match the end date + // (which is always the end of the month) but that is caught by an event. + + } else { + if ($amount > 0) { + $limit->amount = $amount; + $limit->save(); + } else { + $limit->delete(); + } + } + + return $limit; + } } diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index c9c9d8bc40..0aec8c451a 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -17,22 +17,30 @@ interface BudgetRepositoryInterface { + /** + * + * Same as ::spentInPeriod but corrects journals for a set of accounts + * + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * @param Collection $accounts + * + * @return string + */ + public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, Collection $accounts); + /** * @return void */ public function cleanupBudgets(); /** - * Returns the expenses for this budget grouped per day, with the date - * in "date" (a string, not a Carbon) and the amount in "dailyAmount". - * * @param Budget $budget - * @param Carbon $start - * @param Carbon $end * - * @return Collection + * @return boolean */ - public function getExpensesPerDay(Budget $budget, Carbon $start, Carbon $end); + public function destroy(Budget $budget); /** * @param Budget $budget @@ -42,72 +50,33 @@ interface BudgetRepositoryInterface public function firstActivity(Budget $budget); /** - * Returns the expenses for this budget grouped per month, with the date - * in "date" (a string, not a Carbon) and the amount in "dailyAmount". - * - * @param Budget $budget + * @return Collection + */ + public function getActiveBudgets(); + + /** * @param Carbon $start * @param Carbon $end * * @return Collection */ - public function getExpensesPerMonth(Budget $budget, Carbon $start, Carbon $end); - + public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end); /** - * Returns a list of expenses (in the field "spent", grouped per budget per account. + * Get the budgeted amounts for each budgets in each year. * * @param Collection $budgets - * @param Collection $accounts * @param Carbon $start * @param Carbon $end * * @return Collection */ - public function spentPerBudgetPerAccount(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end); + public function getBudgetedPerYear(Collection $budgets, Carbon $start, Carbon $end); /** - * Returns an array with the following key:value pairs: - * - * yyyy-mm-dd: - * - * Where yyyy-mm-dd is the date and is the money spent using WITHDRAWALS in the $budget - * from all the users accounts. - * - * @param Budget $budget - * @param Carbon $start - * @param Carbon $end - * - * @return array + * @return Collection */ - public function spentPerDay(Budget $budget, Carbon $start, Carbon $end); - - /** - * Returns an array with the following key:value pairs: - * - * yyyy-mm-dd: - * - * That array contains: - * - * budgetid: - * - * Where yyyy-mm-dd is the date and is the money spent using WITHDRAWALS in the $budget - * from the given users accounts.. - * - * @param Collection $accounts - * @param Carbon $start - * @param Carbon $end - * - * @return array - */ - public function spentAllPerDayForAccounts(Collection $accounts, Carbon $start, Carbon $end); - - /** - * @param Budget $budget - * - * @return boolean - */ - public function destroy(Budget $budget); + public function getBudgets(); /** * Returns an array with every budget in it and the expenses for each budget @@ -134,35 +103,6 @@ interface BudgetRepositoryInterface */ public function getBudgetsAndExpensesPerYear(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end); - /** - * @return Collection - */ - public function getActiveBudgets(); - - /** - * Get the budgeted amounts for each budgets in each year. - * - * @param Collection $budgets - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function getBudgetedPerYear(Collection $budgets, Carbon $start, Carbon $end); - - /** - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end); - - /** - * @return Collection - */ - public function getBudgets(); - /** * Returns a list of budgets, budget limits and limit repetitions * (doubling any of them in a left join) @@ -183,6 +123,30 @@ interface BudgetRepositoryInterface */ public function getCurrentRepetition(Budget $budget, Carbon $start, Carbon $end); + /** + * Returns the expenses for this budget grouped per day, with the date + * in "date" (a string, not a Carbon) and the amount in "dailyAmount". + * + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getExpensesPerDay(Budget $budget, Carbon $start, Carbon $end); + + /** + * Returns the expenses for this budget grouped per month, with the date + * in "date" (a string, not a Carbon) and the amount in "dailyAmount". + * + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getExpensesPerMonth(Budget $budget, Carbon $start, Carbon $end); + /** * @param Budget $budget * @@ -223,17 +187,52 @@ interface BudgetRepositoryInterface public function getWithoutBudgetSum(Carbon $start, Carbon $end); /** + * Returns an array with the following key:value pairs: * - * Same as ::spentInPeriod but corrects journals for a set of accounts + * yyyy-mm-dd: * - * @param Budget $budget + * That array contains: + * + * budgetid: + * + * Where yyyy-mm-dd is the date and is the money spent using WITHDRAWALS in the $budget + * from the given users accounts.. + * + * @param Collection $accounts * @param Carbon $start * @param Carbon $end - * @param Collection $accounts * - * @return string + * @return array */ - public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, Collection $accounts); + public function spentAllPerDayForAccounts(Collection $accounts, Carbon $start, Carbon $end); + + /** + * Returns a list of expenses (in the field "spent", grouped per budget per account. + * + * @param Collection $budgets + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function spentPerBudgetPerAccount(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end); + + /** + * Returns an array with the following key:value pairs: + * + * yyyy-mm-dd: + * + * Where yyyy-mm-dd is the date and is the money spent using WITHDRAWALS in the $budget + * from all the users accounts. + * + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function spentPerDay(Budget $budget, Carbon $start, Carbon $end); /** * @param array $data diff --git a/app/Repositories/Category/CategoryRepository.php b/app/Repositories/Category/CategoryRepository.php index 534188bace..f821c52a85 100644 --- a/app/Repositories/Category/CategoryRepository.php +++ b/app/Repositories/Category/CategoryRepository.php @@ -19,104 +19,6 @@ use Illuminate\Support\Collection; class CategoryRepository implements CategoryRepositoryInterface { - /** - * Returns a list of all the categories belonging to a user. - * - * @return Collection - */ - public function listCategories() - { - /** @var Collection $set */ - $set = Auth::user()->categories()->orderBy('name', 'ASC')->get(); - $set = $set->sortBy( - function (Category $category) { - return strtolower($category->name); - } - ); - - return $set; - } - - /** - * Returns a list of transaction journals in the range (all types, all accounts) that have no category - * associated to them. - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function listNoCategory(Carbon $start, Carbon $end) - { - return Auth::user() - ->transactionjournals() - ->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->whereNull('category_transaction_journal.id') - ->before($end) - ->after($start) - ->orderBy('transaction_journals.date', 'DESC') - ->orderBy('transaction_journals.order', 'ASC') - ->orderBy('transaction_journals.id', 'DESC') - ->get(['transaction_journals.*']); - } - - /** - * This method returns a very special collection for each category: - * - * category, year, expense/earned, amount - * - * categories can be duplicated. - * - * @param Collection $categories - * @param Collection $accounts - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function listMultiYear(Collection $categories, Collection $accounts, Carbon $start, Carbon $end) - { - /* - * select categories.id, DATE_FORMAT(transaction_journals.date,"%Y") as dateFormatted, transaction_types.type, SUM(amount) as sum from categories - -left join category_transaction_journal ON category_transaction_journal.category_id = categories.id -left join transaction_journals ON transaction_journals.id = category_transaction_journal.transaction_journal_id -left join transaction_types ON transaction_types.id = transaction_journals.transaction_type_id -left join transactions ON transactions.transaction_journal_id = transaction_journals.id - - -where -categories.user_id =1 -and transaction_types.type in ("Withdrawal","Deposit") -and transactions.account_id IN (2,4,6,10,11,610,725,879,1248) - -group by categories.id, transaction_types.type, dateFormatted - */ - $set = Auth::user()->categories() - ->leftJoin('category_transaction_journal', 'category_transaction_journal.category_id', '=', 'categories.id') - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'category_transaction_journal.transaction_journal_id') - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') - ->whereIn('transaction_types.type', [TransactionType::DEPOSIT, TransactionType::WITHDRAWAL]) - ->whereIn('transactions.account_id', $accounts->pluck('id')->toArray()) - ->whereIn('categories.id', $categories->pluck('id')->toArray()) - ->groupBy('categories.id') - ->groupBy('transaction_types.type') - ->groupBy('dateFormatted') - ->get( - [ - 'categories.*', - DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y") as `dateFormatted`'), - 'transaction_types.type', - DB::Raw('SUM(`amount`) as `sum`') - ] - ); - - return $set; - - } - - /** * Returns a collection of Categories appended with the amount of money that has been earned * in these categories, based on the $accounts involved, in period X, grouped per month. @@ -158,7 +60,7 @@ group by categories.id, transaction_types.type, dateFormatted [ 'categories.*', DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") as `dateFormatted`'), - DB::Raw('SUM(`t_dest`.`amount`) AS `earned`') + DB::Raw('SUM(`t_dest`.`amount`) AS `earned`'), ] ); @@ -167,6 +69,90 @@ group by categories.id, transaction_types.type, dateFormatted } + /** + * Returns a list of all the categories belonging to a user. + * + * @return Collection + */ + public function listCategories() + { + /** @var Collection $set */ + $set = Auth::user()->categories()->orderBy('name', 'ASC')->get(); + $set = $set->sortBy( + function (Category $category) { + return strtolower($category->name); + } + ); + + return $set; + } + + /** + * This method returns a very special collection for each category: + * + * category, year, expense/earned, amount + * + * categories can be duplicated. + * + * @param Collection $categories + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function listMultiYear(Collection $categories, Collection $accounts, Carbon $start, Carbon $end) + { + + $set = Auth::user()->categories() + ->leftJoin('category_transaction_journal', 'category_transaction_journal.category_id', '=', 'categories.id') + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'category_transaction_journal.transaction_journal_id') + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->whereIn('transaction_types.type', [TransactionType::DEPOSIT, TransactionType::WITHDRAWAL]) + ->whereIn('transactions.account_id', $accounts->pluck('id')->toArray()) + ->whereIn('categories.id', $categories->pluck('id')->toArray()) + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->groupBy('categories.id') + ->groupBy('transaction_types.type') + ->groupBy('dateFormatted') + ->get( + [ + 'categories.*', + DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y") as `dateFormatted`'), + 'transaction_types.type', + DB::Raw('SUM(`amount`) as `sum`'), + ] + ); + + return $set; + + } + + /** + * Returns a list of transaction journals in the range (all types, all accounts) that have no category + * associated to them. + * + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function listNoCategory(Carbon $start, Carbon $end) + { + return Auth::user() + ->transactionjournals() + ->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') + ->whereNull('category_transaction_journal.id') + ->before($end) + ->after($start) + ->orderBy('transaction_journals.date', 'DESC') + ->orderBy('transaction_journals.order', 'ASC') + ->orderBy('transaction_journals.id', 'DESC') + ->get(['transaction_journals.*']); + } + /** * Returns a collection of Categories appended with the amount of money that has been spent * in these categories, based on the $accounts involved, in period X, grouped per month. @@ -212,29 +198,13 @@ group by categories.id, transaction_types.type, dateFormatted [ 'categories.*', DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") as `dateFormatted`'), - DB::Raw('SUM(`t_src`.`amount`) AS `spent`') + DB::Raw('SUM(`t_src`.`amount`) AS `spent`'), ] ); return $collection; } - - /** - * Returns the total amount of money related to transactions without any category connected to - * it. Returns either the spent amount. - * - * @param Collection $accounts - * @param Carbon $start - * @param Carbon $end - * - * @return string - */ - public function sumSpentNoCategory(Collection $accounts, Carbon $start, Carbon $end) - { - return $this->sumNoCategory($accounts, $start, $end, Query::SPENT); - } - /** * Returns the total amount of money related to transactions without any category connected to * it. Returns either the earned amount. @@ -250,6 +220,21 @@ group by categories.id, transaction_types.type, dateFormatted return $this->sumNoCategory($accounts, $start, $end, Query::EARNED); } + /** + * Returns the total amount of money related to transactions without any category connected to + * it. Returns either the spent amount. + * + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return string + */ + public function sumSpentNoCategory(Collection $accounts, Carbon $start, Carbon $end) + { + return $this->sumNoCategory($accounts, $start, $end, Query::SPENT); + } + /** * Returns the total amount of money related to transactions without any category connected to * it. Returns either the earned or the spent amount. @@ -286,7 +271,7 @@ group by categories.id, transaction_types.type, dateFormatted $single = $query->first( [ - DB::Raw('SUM(`transactions`.`amount`) as `sum`') + DB::Raw('SUM(`transactions`.`amount`) as `sum`'), ] ); if (!is_null($single)) { diff --git a/app/Repositories/Category/SingleCategoryRepository.php b/app/Repositories/Category/SingleCategoryRepository.php index 320c78e7f0..95c41a26fa 100644 --- a/app/Repositories/Category/SingleCategoryRepository.php +++ b/app/Repositories/Category/SingleCategoryRepository.php @@ -25,7 +25,7 @@ class SingleCategoryRepository extends ComponentRepository implements SingleCate */ public function countJournals(Category $category) { - return $category->transactionJournals()->count(); + return $category->transactionjournals()->count(); } @@ -39,7 +39,7 @@ class SingleCategoryRepository extends ComponentRepository implements SingleCate */ public function countJournalsInRange(Category $category, Carbon $start, Carbon $end) { - return $category->transactionJournals()->before($end)->after($start)->count(); + return $category->transactionjournals()->before($end)->after($start)->count(); } /** @@ -235,4 +235,4 @@ class SingleCategoryRepository extends ComponentRepository implements SingleCate } -} \ No newline at end of file +} diff --git a/app/Repositories/Category/SingleCategoryRepositoryInterface.php b/app/Repositories/Category/SingleCategoryRepositoryInterface.php index 6e6b4b76c2..cae94328d4 100644 --- a/app/Repositories/Category/SingleCategoryRepositoryInterface.php +++ b/app/Repositories/Category/SingleCategoryRepositoryInterface.php @@ -119,4 +119,4 @@ interface SingleCategoryRepositoryInterface * @return Category */ public function update(Category $category, array $data); -} \ No newline at end of file +} diff --git a/app/Repositories/Journal/JournalRepository.php b/app/Repositories/Journal/JournalRepository.php index c3d4d08c5e..ba3b4200e3 100644 --- a/app/Repositories/Journal/JournalRepository.php +++ b/app/Repositories/Journal/JournalRepository.php @@ -196,14 +196,14 @@ class JournalRepository implements JournalRepositoryInterface [ 'account_id' => $fromAccount->id, 'transaction_journal_id' => $journal->id, - 'amount' => $data['amount'] * -1 + 'amount' => $data['amount'] * -1, ] ); Transaction::create( // second transaction. [ 'account_id' => $toAccount->id, 'transaction_journal_id' => $journal->id, - 'amount' => $data['amount'] + 'amount' => $data['amount'], ] ); $journal->completed = 1; @@ -323,6 +323,8 @@ class JournalRepository implements JournalRepositoryInterface * @param array $data * * @return array + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function storeAccounts(TransactionType $type, array $data) { @@ -362,30 +364,6 @@ class JournalRepository implements JournalRepositoryInterface return [$fromAccount, $toAccount]; } - /** - * @param array $data - * - * @return array - */ - protected function storeWithdrawalAccounts(array $data) - { - $fromAccount = Account::find($data['account_id']); - - if (strlen($data['expense_account']) > 0) { - $toType = AccountType::where('type', 'Expense account')->first(); - $toAccount = Account::firstOrCreateEncrypted( - ['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => $data['expense_account'], 'active' => 1] - ); - } else { - $toType = AccountType::where('type', 'Cash account')->first(); - $toAccount = Account::firstOrCreateEncrypted( - ['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => 'Cash account', 'active' => 1] - ); - } - - return [$fromAccount, $toAccount]; - } - /** * @param array $data * @@ -409,4 +387,28 @@ class JournalRepository implements JournalRepositoryInterface return [$fromAccount, $toAccount]; } + + /** + * @param array $data + * + * @return array + */ + protected function storeWithdrawalAccounts(array $data) + { + $fromAccount = Account::find($data['account_id']); + + if (strlen($data['expense_account']) > 0) { + $toType = AccountType::where('type', 'Expense account')->first(); + $toAccount = Account::firstOrCreateEncrypted( + ['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => $data['expense_account'], 'active' => 1] + ); + } else { + $toType = AccountType::where('type', 'Cash account')->first(); + $toAccount = Account::firstOrCreateEncrypted( + ['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => 'Cash account', 'active' => 1] + ); + } + + return [$fromAccount, $toAccount]; + } } diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php index 77b63a35eb..8d49f3c74f 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepository.php +++ b/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -60,6 +60,14 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface return $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get(); } + /** + * @return int + */ + public function getMaxOrder() + { + return intval(Auth::user()->piggyBanks()->max('order')); + } + /** * @return Collection */ diff --git a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php index 3bf29f36d6..8d0f81b654 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php +++ b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php @@ -42,6 +42,11 @@ interface PiggyBankRepositoryInterface */ public function getEvents(PiggyBank $piggyBank); + /** + * @return int + */ + public function getMaxOrder(); + /** * @return Collection */ diff --git a/app/Repositories/Rule/RuleRepository.php b/app/Repositories/Rule/RuleRepository.php new file mode 100644 index 0000000000..b21536aa76 --- /dev/null +++ b/app/Repositories/Rule/RuleRepository.php @@ -0,0 +1,362 @@ +rules()->count(); + } + + /** + * @param Rule $rule + * + * @return bool + */ + public function destroy(Rule $rule) + { + foreach ($rule->ruleTriggers as $trigger) { + $trigger->delete(); + } + foreach ($rule->ruleActions as $action) { + $action->delete(); + } + $rule->delete(); + + return true; + } + + /** + * @return RuleGroup + */ + public function getFirstRuleGroup() + { + return Auth::user()->ruleGroups()->first(); + } + + /** + * @param RuleGroup $ruleGroup + * + * @return int + */ + public function getHighestOrderInRuleGroup(RuleGroup $ruleGroup) + { + return intval($ruleGroup->rules()->max('order')); + } + + /** + * @param Rule $rule + * + * @return bool + */ + public function moveDown(Rule $rule) + { + $order = $rule->order; + + // find the rule with order+1 and give it order-1 + $other = $rule->ruleGroup->rules()->where('order', ($order + 1))->first(); + if ($other) { + $other->order = $other->order - 1; + $other->save(); + } + + + $rule->order = ($rule->order + 1); + $rule->save(); + $this->resetRulesInGroupOrder($rule->ruleGroup); + } + + /** + * @param Rule $rule + * + * @return bool + */ + public function moveUp(Rule $rule) + { + $order = $rule->order; + + // find the rule with order-1 and give it order+1 + $other = $rule->ruleGroup->rules()->where('order', ($order - 1))->first(); + if ($other) { + $other->order = ($other->order + 1); + $other->save(); + } + + $rule->order = ($rule->order - 1); + $rule->save(); + $this->resetRulesInGroupOrder($rule->ruleGroup); + } + + /** + * @param Rule $rule + * @param array $ids + * + * @return bool + */ + public function reorderRuleActions(Rule $rule, array $ids) + { + $order = 1; + foreach ($ids as $actionId) { + /** @var RuleTrigger $trigger */ + $action = $rule->ruleActions()->find($actionId); + if (!is_null($action)) { + $action->order = $order; + $action->save(); + $order++; + } + } + + return true; + } + + /** + * @param Rule $rule + * @param array $ids + * + * @return bool + */ + public function reorderRuleTriggers(Rule $rule, array $ids) + { + $order = 1; + foreach ($ids as $triggerId) { + /** @var RuleTrigger $trigger */ + $trigger = $rule->ruleTriggers()->find($triggerId); + if (!is_null($trigger)) { + $trigger->order = $order; + $trigger->save(); + $order++; + } + } + + return true; + } + + /** + * @param RuleGroup $ruleGroup + * + * @return bool + */ + public function resetRulesInGroupOrder(RuleGroup $ruleGroup) + { + $ruleGroup->rules()->whereNotNull('deleted_at')->update(['order' => 0]); + + $set = $ruleGroup->rules() + ->orderBy('order', 'ASC') + ->orderBy('updated_at', 'DESC') + ->get(); + $count = 1; + /** @var Rule $entry */ + foreach ($set as $entry) { + $entry->order = $count; + $entry->save(); + $count++; + } + + return true; + + } + + /** + * @param array $data + * + * @return Rule + */ + public function store(array $data) + { + /** @var RuleGroup $ruleGroup */ + $ruleGroup = Auth::user()->ruleGroups()->find($data['rule_group_id']); + + // get max order: + $order = $this->getHighestOrderInRuleGroup($ruleGroup); + + // start by creating a new rule: + $rule = new Rule; + $rule->user()->associate(Auth::user()); // TODO must be $data['user'] + + $rule->rule_group_id = $data['rule_group_id']; + $rule->order = ($order + 1); + $rule->active = 1; + $rule->stop_processing = intval($data['stop_processing']) == 1; + $rule->title = $data['title']; + $rule->description = strlen($data['description']) > 0 ? $data['description'] : null; + + $rule->save(); + + // start storing triggers: + $order = 1; + $stopProcessing = false; + + $triggerValues = [ + 'action' => 'user_action', + 'value' => $data['trigger'], + 'stopProcessing' => $stopProcessing, + 'order' => $order, + ]; + + $this->storeTrigger($rule, $triggerValues); + foreach ($data['rule-triggers'] as $index => $trigger) { + $value = $data['rule-trigger-values'][$index]; + $stopProcessing = isset($data['rule-trigger-stop'][$index]) ? true : false; + + $triggerValues = [ + 'action' => $trigger, + 'value' => $value, + 'stopProcessing' => $stopProcessing, + 'order' => $order, + ]; + + $this->storeTrigger($rule, $triggerValues); + $order++; + } + + // same for actions. + $order = 1; + foreach ($data['rule-actions'] as $index => $action) { + $value = $data['rule-action-values'][$index]; + $stopProcessing = isset($data['rule-action-stop'][$index]) ? true : false; + + $actionValues = [ + 'action' => $action, + 'value' => $value, + 'stopProcessing' => $stopProcessing, + 'order' => $order, + ]; + + $this->storeAction($rule, $actionValues); + } + + return $rule; + } + + /** + * @param Rule $rule + * @param array $values + * + * @return RuleAction + */ + public function storeAction(Rule $rule, array $values) + { + $ruleAction = new RuleAction; + $ruleAction->rule()->associate($rule); + $ruleAction->order = $values['order']; + $ruleAction->active = 1; + $ruleAction->stop_processing = $values['stopProcessing']; + $ruleAction->action_type = $values['action']; + $ruleAction->action_value = $values['value']; + $ruleAction->save(); + + + return $ruleAction; + } + + /** + * @param Rule $rule + * @param array $values + * + * @return RuleTrigger + */ + public function storeTrigger(Rule $rule, array $values) + { + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = $values['order']; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = $values['stopProcessing']; + $ruleTrigger->trigger_type = $values['action']; + $ruleTrigger->trigger_value = $values['value']; + $ruleTrigger->save(); + + return $ruleTrigger; + } + + /** + * @param Rule $rule + * @param array $data + * + * @return Rule + */ + public function update(Rule $rule, array $data) + { + // update rule: + $rule->active = $data['active']; + $rule->stop_processing = $data['stop_processing']; + $rule->title = $data['title']; + $rule->description = $data['description']; + $rule->save(); + + // delete triggers: + $rule->ruleTriggers()->delete(); + + // delete actions: + $rule->ruleActions()->delete(); + + // recreate triggers: + $order = 1; + $stopProcessing = false; + + $triggerValues = [ + 'action' => 'user_action', + 'value' => $data['trigger'], + 'stopProcessing' => $stopProcessing, + 'order' => $order, + ]; + + $this->storeTrigger($rule, $triggerValues); + foreach ($data['rule-triggers'] as $index => $trigger) { + $value = $data['rule-trigger-values'][$index]; + $stopProcessing = isset($data['rule-trigger-stop'][$index]) ? true : false; + + $triggerValues = [ + 'action' => $trigger, + 'value' => $value, + 'stopProcessing' => $stopProcessing, + 'order' => $order, + ]; + + $this->storeTrigger($rule, $triggerValues); + $order++; + } + + // recreate actions: + $order = 1; + foreach ($data['rule-actions'] as $index => $action) { + $value = $data['rule-action-values'][$index]; + $stopProcessing = isset($data['rule-action-stop'][$index]) ? true : false; + + $actionValues = [ + 'action' => $action, + 'value' => $value, + 'stopProcessing' => $stopProcessing, + 'order' => $order, + ]; + + $this->storeAction($rule, $actionValues); + } + + + return $rule; + } +} diff --git a/app/Repositories/Rule/RuleRepositoryInterface.php b/app/Repositories/Rule/RuleRepositoryInterface.php new file mode 100644 index 0000000000..21f554ff48 --- /dev/null +++ b/app/Repositories/Rule/RuleRepositoryInterface.php @@ -0,0 +1,116 @@ +ruleGroups()->count(); + } + + /** + * @param RuleGroup $ruleGroup + * @param RuleGroup $moveTo + * + * @return boolean + */ + public function destroy(RuleGroup $ruleGroup, RuleGroup $moveTo = null) + { + /** @var Rule $rule */ + foreach ($ruleGroup->rules as $rule) { + + if (is_null($moveTo)) { + + $rule->delete(); + } else { + // move + $rule->ruleGroup()->associate($moveTo); + $rule->save(); + } + } + + $ruleGroup->delete(); + + $this->resetRuleGroupOrder(); + if (!is_null($moveTo)) { + $this->resetRulesInGroupOrder($moveTo); + } + + return true; + } + + /** + * @return Collection + */ + public function get() + { + return Auth::user()->ruleGroups()->orderBy('order', 'ASC')->get(); + } + + /** + * @return int + */ + public function getHighestOrderRuleGroup() + { + $entry = Auth::user()->ruleGroups()->max('order'); + + return intval($entry); + } + + /** + * @param RuleGroup $ruleGroup + * + * @return bool + */ + public function moveDown(RuleGroup $ruleGroup) + { + $order = $ruleGroup->order; + + // find the rule with order+1 and give it order-1 + $other = Auth::user()->ruleGroups()->where('order', ($order + 1))->first(); + if ($other) { + $other->order = ($other->order - 1); + $other->save(); + } + + $ruleGroup->order = ($ruleGroup->order + 1); + $ruleGroup->save(); + $this->resetRuleGroupOrder(); + } + + /** + * @param RuleGroup $ruleGroup + * + * @return bool + */ + public function moveUp(RuleGroup $ruleGroup) + { + $order = $ruleGroup->order; + + // find the rule with order-1 and give it order+1 + $other = Auth::user()->ruleGroups()->where('order', ($order - 1))->first(); + if ($other) { + $other->order = ($other->order + 1); + $other->save(); + } + + $ruleGroup->order = ($ruleGroup->order - 1); + $ruleGroup->save(); + $this->resetRuleGroupOrder(); + } + + /** + * @return bool + */ + public function resetRuleGroupOrder() + { + Auth::user()->ruleGroups()->whereNotNull('deleted_at')->update(['order' => 0]); + + $set = Auth::user()->ruleGroups()->where('active', 1)->orderBy('order', 'ASC')->get(); + $count = 1; + /** @var RuleGroup $entry */ + foreach ($set as $entry) { + $entry->order = $count; + $entry->save(); + $count++; + } + + + return true; + } + + /** + * @param RuleGroup $ruleGroup + * + * @return bool + */ + public function resetRulesInGroupOrder(RuleGroup $ruleGroup) + { + $ruleGroup->rules()->whereNotNull('deleted_at')->update(['order' => 0]); + + $set = $ruleGroup->rules() + ->orderBy('order', 'ASC') + ->orderBy('updated_at', 'DESC') + ->get(); + $count = 1; + /** @var Rule $entry */ + foreach ($set as $entry) { + $entry->order = $count; + $entry->save(); + $count++; + } + + return true; + + } + + /** + * @param array $data + * + * @return RuleGroup + */ + public function store(array $data) + { + $order = $this->getHighestOrderRuleGroup(); + + $newRuleGroup = new RuleGroup( + [ + 'user_id' => $data['user'], + 'title' => $data['title'], + 'description' => $data['description'], + 'order' => ($order + 1), + 'active' => 1, + + + ] + ); + $newRuleGroup->save(); + $this->resetRuleGroupOrder(); + + return $newRuleGroup; + } + + /** + * @param RuleGroup $ruleGroup + * @param array $data + * + * @return RuleGroup + */ + public function update(RuleGroup $ruleGroup, array $data) + { + // update the account: + $ruleGroup->title = $data['title']; + $ruleGroup->description = $data['description']; + $ruleGroup->active = $data['active']; + $ruleGroup->save(); + $this->resetRuleGroupOrder(); + + return $ruleGroup; + } + +} \ No newline at end of file diff --git a/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php b/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php new file mode 100644 index 0000000000..8c6b72f398 --- /dev/null +++ b/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php @@ -0,0 +1,81 @@ +leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') ->whereIn('accounts.id', $ids) ->after($start) - ->first([DB::Raw('SUM(`transactions`.`amount`) as `journalAmount`')]); + ->first([DB::raw('SUM(`transactions`.`amount`) as `journalAmount`')]); $amount = $entry->journalAmount; return $amount; diff --git a/app/Repositories/Tag/TagRepository.php b/app/Repositories/Tag/TagRepository.php index ccdb2d9dae..952090e750 100644 --- a/app/Repositories/Tag/TagRepository.php +++ b/app/Repositories/Tag/TagRepository.php @@ -22,11 +22,55 @@ class TagRepository implements TagRepositoryInterface { + /** + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function allCoveredByBalancingActs(Collection $accounts, Carbon $start, Carbon $end) + { + $ids = $accounts->pluck('id')->toArray(); + $set = Auth::user()->tags() + ->leftJoin('tag_transaction_journal', 'tag_transaction_journal.tag_id', '=', 'tags.id') + ->leftJoin('transaction_journals', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') + ->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id') + ->leftJoin( + 'transactions AS t_from', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 't_from.transaction_journal_id')->where('t_from.amount', '<', 0); + } + ) + ->leftJoin( + 'transactions AS t_to', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 't_to.transaction_journal_id')->where('t_to.amount', '>', 0); + } + ) + ->where('tags.tagMode', 'balancingAct') + ->where('transaction_types.type', TransactionType::TRANSFER) + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->whereNull('transaction_journals.deleted_at') + ->whereIn('t_from.account_id', $ids) + ->whereIn('t_to.account_id', $ids) + ->groupBy('t_to.account_id') + ->get( + [ + 't_to.account_id', + DB::Raw('SUM(`t_to`.`amount`) as `sum`'), + ] + ); + + return $set; + } + /** * * @param TransactionJournal $journal * @param Tag $tag * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly 5. + * * @return boolean */ public function connect(TransactionJournal $journal, Tag $tag) @@ -93,49 +137,6 @@ class TagRepository implements TagRepositoryInterface return $amount; } - - /** - * @param Collection $accounts - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function allCoveredByBalancingActs(Collection $accounts, Carbon $start, Carbon $end) - { - $ids = $accounts->pluck('id')->toArray(); - $set = Auth::user()->tags() - ->leftJoin('tag_transaction_journal', 'tag_transaction_journal.tag_id', '=', 'tags.id') - ->leftJoin('transaction_journals', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id') - ->leftJoin( - 'transactions AS t_from', function (JoinClause $join) { - $join->on('transaction_journals.id', '=', 't_from.transaction_journal_id')->where('t_from.amount', '<', 0); - } - ) - ->leftJoin( - 'transactions AS t_to', function (JoinClause $join) { - $join->on('transaction_journals.id', '=', 't_to.transaction_journal_id')->where('t_to.amount', '>', 0); - } - ) - ->where('tags.tagMode', 'balancingAct') - ->where('transaction_types.type', TransactionType::TRANSFER) - ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) - ->whereNull('transaction_journals.deleted_at') - ->whereIn('t_from.account_id', $ids) - ->whereIn('t_to.account_id', $ids) - ->groupBy('t_to.account_id') - ->get( - [ - 't_to.account_id', - DB::Raw('SUM(`t_to`.`amount`) as `sum`') - ] - ); - - return $set; - } - /** * @param Tag $tag * @@ -276,6 +277,53 @@ class TagRepository implements TagRepositoryInterface return $tag; } + /** + * @param TransactionJournal $journal + * @param Tag $tag + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * + * @return boolean + */ + protected function connectAdvancePayment(TransactionJournal $journal, Tag $tag) + { + /** @var TransactionType $transfer */ + $transfer = TransactionType::whereType(TransactionType::TRANSFER)->first(); + /** @var TransactionType $withdrawal */ + $withdrawal = TransactionType::whereType(TransactionType::WITHDRAWAL)->first(); + /** @var TransactionType $deposit */ + $deposit = TransactionType::whereType(TransactionType::DEPOSIT)->first(); + + $withdrawals = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->count(); + $deposits = $tag->transactionjournals()->where('transaction_type_id', $deposit->id)->count(); + + if ($journal->transaction_type_id == $transfer->id) { // advance payments cannot accept transfers: + return false; + } + + // the first transaction to be attached to this tag is attached just like that: + if ($withdrawals < 1 && $deposits < 1) { + $journal->tags()->save($tag); + $journal->save(); + + return true; + } + + // if withdrawal and already has a withdrawal, return false: + if ($journal->transaction_type_id == $withdrawal->id && $withdrawals == 1) { + return false; + } + + // if already has transaction journals, must match ALL asset account id's: + if ($deposits > 0 || $withdrawals == 1) { + return $this->matchAll($journal, $tag); + } + + // this statement is unreachable. + return false; // @codeCoverageIgnore + + } + /** * @param TransactionJournal $journal * @param Tag $tag @@ -316,52 +364,7 @@ class TagRepository implements TagRepositoryInterface * @param TransactionJournal $journal * @param Tag $tag * - * @return boolean - */ - protected function connectAdvancePayment(TransactionJournal $journal, Tag $tag) - { - /** @var TransactionType $transfer */ - $transfer = TransactionType::whereType(TransactionType::TRANSFER)->first(); - /** @var TransactionType $withdrawal */ - $withdrawal = TransactionType::whereType(TransactionType::WITHDRAWAL)->first(); - /** @var TransactionType $deposit */ - $deposit = TransactionType::whereType(TransactionType::DEPOSIT)->first(); - - $withdrawals = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->count(); - $deposits = $tag->transactionjournals()->where('transaction_type_id', $deposit->id)->count(); - - // advance payments cannot accept transfers: - if ($journal->transaction_type_id == $transfer->id) { - return false; - } - - // the first transaction to be attached to this - // tag is attached just like that: - if ($withdrawals < 1 && $deposits < 1) { - $journal->tags()->save($tag); - $journal->save(); - - return true; - } - - // if withdrawal and already has a withdrawal, return false: - if ($journal->transaction_type_id == $withdrawal->id && $withdrawals == 1) { - return false; - } - - // if already has transaction journals, must match ALL asset account id's: - if ($deposits > 0 || $withdrawals == 1) { - return $this->matchAll($journal, $tag); - } - - // this statement is unreachable. - return false; // @codeCoverageIgnore - - } - - /** - * @param TransactionJournal $journal - * @param Tag $tag + * @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's complex but nothing can be done. * * @return bool */ diff --git a/app/Rules/Actions/ActionInterface.php b/app/Rules/Actions/ActionInterface.php new file mode 100644 index 0000000000..91cbec46c7 --- /dev/null +++ b/app/Rules/Actions/ActionInterface.php @@ -0,0 +1,34 @@ +action = $action; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function act() + { + // journal has this tag maybe? + $tag = Tag::firstOrCreateEncrypted(['tag' => $this->action->action_value, 'user_id' => Auth::user()->id]); + + $count = $this->journal->tags()->where('id', $tag->id)->count(); + if ($count == 0) { + $this->journal->tags()->save($tag); + } + + return true; + } +} \ No newline at end of file diff --git a/app/Rules/Actions/AppendDescription.php b/app/Rules/Actions/AppendDescription.php new file mode 100644 index 0000000000..42254dc86b --- /dev/null +++ b/app/Rules/Actions/AppendDescription.php @@ -0,0 +1,48 @@ +action = $action; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function act() + { + $this->journal->description = $this->journal->description . $this->action->action_value; + $this->journal->save(); + + return true; + } +} \ No newline at end of file diff --git a/app/Rules/Actions/ClearBudget.php b/app/Rules/Actions/ClearBudget.php new file mode 100644 index 0000000000..e1558afdcd --- /dev/null +++ b/app/Rules/Actions/ClearBudget.php @@ -0,0 +1,48 @@ +action = $action; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function act() + { + $this->journal->budgets()->detach(); + + return true; + } +} \ No newline at end of file diff --git a/app/Rules/Actions/ClearCategory.php b/app/Rules/Actions/ClearCategory.php new file mode 100644 index 0000000000..76569523b8 --- /dev/null +++ b/app/Rules/Actions/ClearCategory.php @@ -0,0 +1,48 @@ +action = $action; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function act() + { + $this->journal->categories()->detach(); + + return true; + } +} \ No newline at end of file diff --git a/app/Rules/Actions/PrependDescription.php b/app/Rules/Actions/PrependDescription.php new file mode 100644 index 0000000000..d452125002 --- /dev/null +++ b/app/Rules/Actions/PrependDescription.php @@ -0,0 +1,48 @@ +action = $action; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function act() + { + $this->journal->description = $this->action->action_value . $this->journal->description; + $this->journal->save(); + + return true; + } +} \ No newline at end of file diff --git a/app/Rules/Actions/RemoveAllTags.php b/app/Rules/Actions/RemoveAllTags.php new file mode 100644 index 0000000000..868acee3cd --- /dev/null +++ b/app/Rules/Actions/RemoveAllTags.php @@ -0,0 +1,48 @@ +action = $action; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function act() + { + $this->journal->tags()->detach(); + + return true; + + } +} \ No newline at end of file diff --git a/app/Rules/Actions/RemoveTag.php b/app/Rules/Actions/RemoveTag.php new file mode 100644 index 0000000000..e6c427d0bb --- /dev/null +++ b/app/Rules/Actions/RemoveTag.php @@ -0,0 +1,61 @@ +action = $action; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function act() + { + // if tag does not exist, no need to continue: + $name = $this->action->action_value; + /** @var Tag $tag */ + $tag = Auth::user()->tags()->get()->filter( + function (Tag $tag) use ($name) { + return $tag->tag == $name; + } + )->first(); + + if (!is_null($tag)) { + $this->journal->tags()->detach([$tag->id]); + } + + return true; + } +} \ No newline at end of file diff --git a/app/Rules/Actions/SetBudget.php b/app/Rules/Actions/SetBudget.php new file mode 100644 index 0000000000..42d6d23638 --- /dev/null +++ b/app/Rules/Actions/SetBudget.php @@ -0,0 +1,65 @@ +action = $action; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function act() + { + /** @var BudgetRepositoryInterface $repository */ + $repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $search = $this->action->action_value; + $budgets = $repository->getActiveBudgets(); + $budget = $budgets->filter( + function (Budget $current) use ($search) { + return $current->name == $search; + } + )->first(); + if (!is_null($budget)) { + Log::debug('Will set budget "' . $search . '" (#' . $budget->id . ') on journal #' . $this->journal->id . '.'); + $this->journal->budgets()->sync([$budget->id]); + } else { + Log::debug('Could not find budget "' . $search . '". Failed.'); + } + + return true; + } +} \ No newline at end of file diff --git a/app/Rules/Actions/SetCategory.php b/app/Rules/Actions/SetCategory.php new file mode 100644 index 0000000000..545040e24a --- /dev/null +++ b/app/Rules/Actions/SetCategory.php @@ -0,0 +1,54 @@ +action = $action; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function act() + { + $name = $this->action->action_value; + $category = Category::firstOrCreateEncrypted(['name' => $name, 'user_id' => Auth::user()->id]); + Log::debug('Will set category "' . $name . '" (#' . $category->id . ') on journal #' . $this->journal->id . '.'); + $this->journal->categories()->sync([$category->id]); + + return true; + } +} \ No newline at end of file diff --git a/app/Rules/Actions/SetDescription.php b/app/Rules/Actions/SetDescription.php new file mode 100644 index 0000000000..1b3ee0422f --- /dev/null +++ b/app/Rules/Actions/SetDescription.php @@ -0,0 +1,48 @@ +action = $action; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function act() + { + $this->journal->description = $this->action->action_value; + $this->journal->save(); + + return true; + } +} \ No newline at end of file diff --git a/app/Rules/Processor.php b/app/Rules/Processor.php new file mode 100644 index 0000000000..54125bfcac --- /dev/null +++ b/app/Rules/Processor.php @@ -0,0 +1,162 @@ +rule = $rule; + $this->journal = $journal; + $this->triggerTypes = Domain::getRuleTriggers(); + $this->actionTypes = Domain::getRuleActions(); + } + + /** + * @return TransactionJournal + */ + public function getJournal() + { + return $this->journal; + } + + /** + * @param TransactionJournal $journal + */ + public function setJournal($journal) + { + $this->journal = $journal; + } + + /** + * @return Rule + */ + public function getRule() + { + return $this->rule; + } + + /** + * @param Rule $rule + */ + public function setRule($rule) + { + $this->rule = $rule; + } + + public function handle() + { + // get all triggers: + $triggered = $this->triggered(); + if ($triggered) { + Log::debug('Rule #' . $this->rule->id . ' was triggered. Now process each action.'); + $this->actions(); + } + + } + + /** + * @return bool + */ + protected function actions() + { + /** + * @var int $index + * @var RuleAction $action + */ + foreach ($this->rule->ruleActions()->orderBy('order', 'ASC')->get() as $action) { + $type = $action->action_type; + $class = $this->actionTypes[$type]; + Log::debug('Action #' . $action->id . ' for rule #' . $action->rule_id . ' (' . $type . ')'); + if (!class_exists($class)) { + abort(500, 'Could not instantiate class for rule action type "' . $type . '" (' . $class . ').'); + } + /** @var ActionInterface $actionClass */ + $actionClass = new $class($action, $this->journal); + $actionClass->act(); + if ($action->stop_processing) { + break; + } + + } + + return true; + } + + /** + * TODO stop when stop_processing is present. + * + * @return bool + */ + protected function triggered() + { + $foundTriggers = 0; + $hitTriggers = 0; + /** @var RuleTrigger $trigger */ + foreach ($this->rule->ruleTriggers()->orderBy('order', 'ASC')->get() as $trigger) { + $foundTriggers++; + $type = $trigger->trigger_type; + + if (!isset($this->triggerTypes[$type])) { + abort(500, 'No such trigger exists ("' . $type . '").'); + } + + $class = $this->triggerTypes[$type]; + Log::debug('Trigger #' . $trigger->id . ' for rule #' . $trigger->rule_id . ' (' . $type . ')'); + if (!class_exists($class)) { + abort(500, 'Could not instantiate class for rule trigger type "' . $type . '" (' . $class . ').'); + } + /** @var TriggerInterface $triggerClass */ + $triggerClass = new $class($trigger, $this->journal); + if ($triggerClass->triggered()) { + $hitTriggers++; + } + if ($trigger->stop_processing) { + break; + } + + } + Log::debug('Total: ' . $foundTriggers . ' found triggers. ' . $hitTriggers . ' triggers were hit.'); + + return ($hitTriggers == $foundTriggers); + + } + + +} \ No newline at end of file diff --git a/app/Rules/Triggers/AmountExactly.php b/app/Rules/Triggers/AmountExactly.php new file mode 100644 index 0000000000..908ad31a6f --- /dev/null +++ b/app/Rules/Triggers/AmountExactly.php @@ -0,0 +1,64 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $amount = $this->journal->amount_positive; + $compare = $this->trigger->trigger_value; + $result = bccomp($amount, $compare, 4); + if ($result === 0) { + // found something + Log::debug($amount . ' is exactly ' . $compare . '. Return true.'); + + return true; + } + + // found nothing. + Log::debug($amount . ' is not exactly ' . $compare . '. Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/AmountLess.php b/app/Rules/Triggers/AmountLess.php new file mode 100644 index 0000000000..4c659db944 --- /dev/null +++ b/app/Rules/Triggers/AmountLess.php @@ -0,0 +1,64 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $amount = $this->journal->amount_positive; + $compare = $this->trigger->trigger_value; + $result = bccomp($amount, $compare, 4); + if ($result === -1) { + // found something + Log::debug($amount . ' is less than ' . $compare . '. Return true.'); + + return true; + } + + // found nothing. + Log::debug($amount . ' is not less than ' . $compare . '. Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/AmountMore.php b/app/Rules/Triggers/AmountMore.php new file mode 100644 index 0000000000..a3470ffd13 --- /dev/null +++ b/app/Rules/Triggers/AmountMore.php @@ -0,0 +1,64 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $amount = $this->journal->amount_positive; + $compare = $this->trigger->trigger_value; + $result = bccomp($amount, $compare, 4); + if ($result === 1) { + // found something + Log::debug($amount . ' is more than ' . $compare . '. Return true.'); + + return true; + } + + // found nothing. + Log::debug($amount . ' is not more than ' . $compare . '. Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/DescriptionContains.php b/app/Rules/Triggers/DescriptionContains.php new file mode 100644 index 0000000000..e55b850d15 --- /dev/null +++ b/app/Rules/Triggers/DescriptionContains.php @@ -0,0 +1,65 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $search = strtolower($this->trigger->trigger_value); + $source = strtolower($this->journal->description); + + $strpos = strpos($source, $search); + if (!($strpos === false)) { + // found something + Log::debug('"' . $source . '" contains the text "' . $search . '". Return true.'); + + return true; + } + + // found nothing. + Log::debug('"' . $source . '" does not contain the text "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/DescriptionEnds.php b/app/Rules/Triggers/DescriptionEnds.php new file mode 100644 index 0000000000..ef21b8aa4c --- /dev/null +++ b/app/Rules/Triggers/DescriptionEnds.php @@ -0,0 +1,74 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $description = strtolower($this->journal->description); + $descriptionLength = strlen($description); + $search = strtolower($this->trigger->trigger_value); + $searchLength = strlen($search); + + // if the string to search for is longer than the description, + // shorten the search string. + if ($searchLength > $descriptionLength) { + Log::debug('Search string "' . $search . '" (' . $searchLength . ') is longer than "' . $description . '" (' . $descriptionLength . '). '); + $search = substr($search, ($descriptionLength * -1)); + $searchLength = strlen($search); + Log::debug('Search string is now "' . $search . '" (' . $searchLength . ') instead.'); + } + + + $part = substr($description, $searchLength * -1); + + if ($part == $search) { + Log::debug('"' . $description . '" ends with "' . $search . '". Return true.'); + + return true; + } + Log::debug('"' . $description . '" does not end with "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/DescriptionIs.php b/app/Rules/Triggers/DescriptionIs.php new file mode 100644 index 0000000000..f7199f0103 --- /dev/null +++ b/app/Rules/Triggers/DescriptionIs.php @@ -0,0 +1,60 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $description = strtolower($this->journal->description); + $search = strtolower($this->trigger->trigger_value); + + if ($description == $search) { + Log::debug('"' . $description . '" equals "' . $search . '" exactly. Return true.'); + + return true; + } + Log::debug('"' . $description . '" does not equal "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/DescriptionStarts.php b/app/Rules/Triggers/DescriptionStarts.php new file mode 100644 index 0000000000..8475f99fda --- /dev/null +++ b/app/Rules/Triggers/DescriptionStarts.php @@ -0,0 +1,62 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $description = strtolower($this->journal->description); + $search = strtolower($this->trigger->trigger_value); + + $part = substr($description, 0, strlen($search)); + + if ($part == $search) { + Log::debug('"' . $description . '" starts with "' . $search . '". Return true.'); + + return true; + } + Log::debug('"' . $description . '" does not start with "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/FromAccountContains.php b/app/Rules/Triggers/FromAccountContains.php new file mode 100644 index 0000000000..5e1e990cb6 --- /dev/null +++ b/app/Rules/Triggers/FromAccountContains.php @@ -0,0 +1,64 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $fromAccountName = strtolower($this->journal->source_account->name); + $search = strtolower($this->trigger->trigger_value); + $strpos = strpos($fromAccountName, $search); + + if (!($strpos === false)) { + // found something + Log::debug('"' . $fromAccountName . '" contains the text "' . $search . '". Return true.'); + + return true; + } + + // found nothing. + Log::debug('"' . $fromAccountName . '" does not contain the text "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/FromAccountEnds.php b/app/Rules/Triggers/FromAccountEnds.php new file mode 100644 index 0000000000..57f686a063 --- /dev/null +++ b/app/Rules/Triggers/FromAccountEnds.php @@ -0,0 +1,74 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $name = strtolower($this->journal->source_account->name); + $nameLength = strlen($name); + $search = strtolower($this->trigger->trigger_value); + $searchLength = strlen($search); + + // if the string to search for is longer than the account name, + // shorten the search string. + if ($searchLength > $nameLength) { + Log::debug('Search string "' . $search . '" (' . $searchLength . ') is longer than "' . $name . '" (' . $nameLength . '). '); + $search = substr($search, ($nameLength * -1)); + $searchLength = strlen($search); + Log::debug('Search string is now "' . $search . '" (' . $searchLength . ') instead.'); + } + + + $part = substr($name, $searchLength * -1); + + if ($part == $search) { + Log::debug('"' . $name . '" ends with "' . $search . '". Return true.'); + + return true; + } + Log::debug('"' . $name . '" does not end with "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/FromAccountIs.php b/app/Rules/Triggers/FromAccountIs.php new file mode 100644 index 0000000000..27de26653d --- /dev/null +++ b/app/Rules/Triggers/FromAccountIs.php @@ -0,0 +1,60 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $fromAccountName = strtolower($this->journal->source_account->name); + $search = strtolower($this->trigger->trigger_value); + + if ($fromAccountName == $search) { + Log::debug('"' . $fromAccountName . '" equals "' . $search . '" exactly. Return true.'); + + return true; + } + Log::debug('"' . $fromAccountName . '" does not equal "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/FromAccountStarts.php b/app/Rules/Triggers/FromAccountStarts.php new file mode 100644 index 0000000000..a5206026ea --- /dev/null +++ b/app/Rules/Triggers/FromAccountStarts.php @@ -0,0 +1,62 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $fromAccountName = strtolower($this->journal->source_account->name); + $search = strtolower($this->trigger->trigger_value); + + $part = substr($fromAccountName, 0, strlen($search)); + + if ($part == $search) { + Log::debug('"' . $fromAccountName . '" starts with "' . $search . '". Return true.'); + + return true; + } + Log::debug('"' . $fromAccountName . '" does not start with "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/ToAccountContains.php b/app/Rules/Triggers/ToAccountContains.php new file mode 100644 index 0000000000..5e06383f04 --- /dev/null +++ b/app/Rules/Triggers/ToAccountContains.php @@ -0,0 +1,64 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $toAccountName = strtolower($this->journal->destination_account->name); + $search = strtolower($this->trigger->trigger_value); + $strpos = strpos($toAccountName, $search); + + if (!($strpos === false)) { + // found something + Log::debug('"' . $toAccountName . '" contains the text "' . $search . '". Return true.'); + + return true; + } + + // found nothing. + Log::debug('"' . $toAccountName . '" does not contain the text "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/ToAccountEnds.php b/app/Rules/Triggers/ToAccountEnds.php new file mode 100644 index 0000000000..7c1984ea2a --- /dev/null +++ b/app/Rules/Triggers/ToAccountEnds.php @@ -0,0 +1,74 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $toAccountName = strtolower($this->journal->destination_account->name); + $toAccountNameLength = strlen($toAccountName); + $search = strtolower($this->trigger->trigger_value); + $searchLength = strlen($search); + + // if the string to search for is longer than the account name, + // shorten the search string. + if ($searchLength > $toAccountNameLength) { + Log::debug('Search string "' . $search . '" (' . $searchLength . ') is longer than "' . $toAccountName . '" (' . $toAccountNameLength . '). '); + $search = substr($search, ($toAccountNameLength * -1)); + $searchLength = strlen($search); + Log::debug('Search string is now "' . $search . '" (' . $searchLength . ') instead.'); + } + + + $part = substr($toAccountName, $searchLength * -1); + + if ($part == $search) { + Log::debug('"' . $toAccountName . '" ends with "' . $search . '". Return true.'); + + return true; + } + Log::debug('"' . $toAccountName . '" does not end with "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/ToAccountIs.php b/app/Rules/Triggers/ToAccountIs.php new file mode 100644 index 0000000000..09f4c66f6a --- /dev/null +++ b/app/Rules/Triggers/ToAccountIs.php @@ -0,0 +1,60 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $toAccountName = strtolower($this->journal->destination_account->name); + $search = strtolower($this->trigger->trigger_value); + + if ($toAccountName == $search) { + Log::debug('"' . $toAccountName . '" equals "' . $search . '" exactly. Return true.'); + + return true; + } + Log::debug('"' . $toAccountName . '" does not equal "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/ToAccountStarts.php b/app/Rules/Triggers/ToAccountStarts.php new file mode 100644 index 0000000000..0af5fc4491 --- /dev/null +++ b/app/Rules/Triggers/ToAccountStarts.php @@ -0,0 +1,62 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $toAccountName = strtolower($this->journal->destination_account->name); + $search = strtolower($this->trigger->trigger_value); + + $part = substr($toAccountName, 0, strlen($search)); + + if ($part == $search) { + Log::debug('"' . $toAccountName . '" starts with "' . $search . '". Return true.'); + + return true; + } + Log::debug('"' . $toAccountName . '" does not start with "' . $search . '". Return false.'); + + return false; + + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/TransactionType.php b/app/Rules/Triggers/TransactionType.php new file mode 100644 index 0000000000..9bba776f42 --- /dev/null +++ b/app/Rules/Triggers/TransactionType.php @@ -0,0 +1,59 @@ +trigger = $trigger; + $this->journal = $journal; + } + + /** + * @return bool + */ + public function triggered() + { + $type = strtolower($this->journal->transactionType->type); + $search = strtolower($this->trigger->trigger_value); + + if ($type == $search) { + Log::debug('Journal is of type "' . $type . '" which matches with "' . $search . '". Return true'); + + return true; + } + Log::debug('Journal is of type "' . $type . '" which does not match with "' . $search . '". Return false'); + + return false; + } +} \ No newline at end of file diff --git a/app/Rules/Triggers/TriggerInterface.php b/app/Rules/Triggers/TriggerInterface.php new file mode 100644 index 0000000000..094ee0f234 --- /dev/null +++ b/app/Rules/Triggers/TriggerInterface.php @@ -0,0 +1,34 @@ +trigger = $trigger; + $this->journal = $journal; + + } + + /** + * This trigger is always triggered, because the rule that it is a part of has been pre-selected on this condition. + * + * @return bool + */ + public function triggered() + { + Log::debug('user_action always returns true.'); + + return true; + } + +} \ No newline at end of file diff --git a/app/Services/Registrar.php b/app/Services/Registrar.php deleted file mode 100644 index 5f69c7ba24..0000000000 --- a/app/Services/Registrar.php +++ /dev/null @@ -1,50 +0,0 @@ - $data['email'], - 'password' => $data['password'], - ] - ); - } - - /** - * Get a validator for an incoming registration request. - * - * @param array $data - * - * @return \Illuminate\Contracts\Validation\Validator - */ - public function validator(array $data) - { - return Validator::make( - $data, [ - 'email' => 'required|email|max:255|unique:users', - 'password' => 'required|confirmed|min:6', - ] - ); - } - -} diff --git a/app/Sql/Query.php b/app/Sql/Query.php index b0989a82d7..8abf2376e1 100644 --- a/app/Sql/Query.php +++ b/app/Sql/Query.php @@ -14,4 +14,4 @@ class Query const SPENT = 1; const EARNED = 2; -} \ No newline at end of file +} diff --git a/app/Support/Amount.php b/app/Support/Amount.php index bd0624f002..be465b5872 100644 --- a/app/Support/Amount.php +++ b/app/Support/Amount.php @@ -6,6 +6,7 @@ use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionJournal; use Illuminate\Support\Collection; +use NumberFormatter; use Preferences as Prefs; /** @@ -15,6 +16,7 @@ use Preferences as Prefs; */ class Amount { + /** * @param $amount * @param bool $coloured @@ -23,57 +25,38 @@ class Amount */ public function format($amount, $coloured = true) { - $currencySymbol = $this->getCurrencySymbol(); - - return $this->formatWithSymbol($currencySymbol, $amount, $coloured); - - + return $this->formatAnything($this->getDefaultCurrency(), $amount, $coloured); } /** - * @return string - */ - public function getCurrencySymbol() - { - $cache = new CacheProperties; - $cache->addProperty('getCurrencySymbol'); - if ($cache->has()) { - return $cache->get(); - } else { - $currencyPreference = Prefs::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR')); - $currency = TransactionCurrency::whereCode($currencyPreference->data)->first(); - - $cache->store($currency->symbol); - - return $currency->symbol; - } - } - - /** - * @param string $symbol - * @param float $amount - * @param bool $coloured + * This method will properly format the given number, in color or "black and white", + * as a currency, given two things: the currency required and the current locale. + * + * @param TransactionCurrency $format + * @param $amount + * @param bool $coloured * * @return string */ - public function formatWithSymbol($symbol, $amount, $coloured = true) + public function formatAnything(TransactionCurrency $format, $amount, $coloured = true) { - $amount = floatval($amount); - $amount = round($amount, 2); - $string = money_format('%!.2n', $amount); + $locale = setlocale(LC_MONETARY, 0); + $formatter = new NumberFormatter($locale, NumberFormatter::CURRENCY); + $result = $formatter->formatCurrency($amount, $format->code); if ($coloured === true) { - if ($amount === 0.0) { - return '' . $symbol . ' ' . $string . ''; + if ($amount == 0) { + return '' . $result . ''; } if ($amount > 0) { - return '' . $symbol . ' ' . $string . ''; + return '' . $result . ''; } - return '' . $symbol . ' ' . $string . ''; + return '' . $result . ''; + } - return $symbol . ' ' . $string; + return $result; } /** @@ -93,27 +76,20 @@ class Amount return $cache->get(); // @codeCoverageIgnore } - - if (is_null($journal->symbol)) { - $symbol = $journal->transactionCurrency->symbol; - } else { - $symbol = $journal->symbol; - } - if ($journal->isTransfer() && $coloured) { - $txt = '' . $this->formatWithSymbol($symbol, $journal->amount_positive, false) . ''; + $txt = '' . $this->formatAnything($journal->transactionCurrency, $journal->amount_positive, false) . '';; $cache->store($txt); return $txt; } if ($journal->isTransfer() && !$coloured) { - $txt = $this->formatWithSymbol($symbol, $journal->amount_positive, false); + $txt = $this->formatAnything($journal->transactionCurrency, $journal->amount_positive, false); $cache->store($txt); return $txt; } - $txt = $this->formatWithSymbol($symbol, $journal->amount, $coloured); + $txt = $this->formatAnything($journal->transactionCurrency, $journal->amount, $coloured); $cache->store($txt); return $txt; @@ -127,10 +103,21 @@ class Amount */ public function formatTransaction(Transaction $transaction, $coloured = true) { - $symbol = $transaction->transactionJournal->transactionCurrency->symbol; - $amount = floatval($transaction->amount); + $currency = $transaction->transactionJournal->transactionCurrency; - return $this->formatWithSymbol($symbol, $amount, $coloured); + return $this->formatAnything($currency, $transaction->amount, $coloured); + } + + /** + * @param string $symbol + * @param float $amount + * @param bool $coloured + * + * @return string + */ + public function formatWithSymbol($symbol, $amount, $coloured = true) + { + return $this->formatAnything($this->getDefaultCurrency(), $amount, $coloured); } /** @@ -168,7 +155,26 @@ class Amount } /** - * @return mixed|static + * @return string + */ + public function getCurrencySymbol() + { + $cache = new CacheProperties; + $cache->addProperty('getCurrencySymbol'); + if ($cache->has()) { + return $cache->get(); + } else { + $currencyPreference = Prefs::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR')); + $currency = TransactionCurrency::whereCode($currencyPreference->data)->first(); + + $cache->store($currency->symbol); + + return $currency->symbol; + } + } + + /** + * @return TransactionCurrency */ public function getDefaultCurrency() { diff --git a/app/Support/Binder/AccountList.php b/app/Support/Binder/AccountList.php new file mode 100644 index 0000000000..59de12db74 --- /dev/null +++ b/app/Support/Binder/AccountList.php @@ -0,0 +1,50 @@ +where('account_types.editable', 1) + ->whereIn('accounts.id', $ids) + ->where('user_id', Auth::user()->id) + ->get(['accounts.*']); + if ($object->count() > 0) { + return $object; + } + } + throw new NotFoundHttpException; + } +} \ No newline at end of file diff --git a/app/Support/Binder/BinderInterface.php b/app/Support/Binder/BinderInterface.php new file mode 100644 index 0000000000..aba12d6455 --- /dev/null +++ b/app/Support/Binder/BinderInterface.php @@ -0,0 +1,27 @@ +whereIn('id', $ids) + ->where('user_id', Auth::user()->id) + ->get(); + + // add empty budget if applicable. + if (in_array('0', $ids)) { + $object->push(new Budget); + } + + if ($object->count() > 0) { + return $object; + } + } + throw new NotFoundHttpException; + } +} \ No newline at end of file diff --git a/app/Support/Binder/CategoryList.php b/app/Support/Binder/CategoryList.php new file mode 100644 index 0000000000..4f39ca6e2f --- /dev/null +++ b/app/Support/Binder/CategoryList.php @@ -0,0 +1,50 @@ +where('user_id', Auth::user()->id) + ->get(); + + // add empty budget if applicable. + if (in_array('0', $ids)) { + $object->push(new Category); + } + + if ($object->count() > 0) { + return $object; + } + } + throw new NotFoundHttpException; + } +} \ No newline at end of file diff --git a/app/Support/Binder/Date.php b/app/Support/Binder/Date.php new file mode 100644 index 0000000000..e03a3238f9 --- /dev/null +++ b/app/Support/Binder/Date.php @@ -0,0 +1,56 @@ +id); + throw new NotFoundHttpException; + } + + return $date; + case 'currentMonthStart': + return Carbon::now()->startOfMonth(); + case 'currentMonthEnd': + return Carbon::now()->endOfMonth(); + case 'currentYearStart': + return Carbon::now()->startOfYear(); + case 'currentYearEnd': + return Carbon::now()->endOfYear(); + + } + } +} diff --git a/app/Support/CacheProperties.php b/app/Support/CacheProperties.php index ba2d654b3d..ed0c1f3302 100644 --- a/app/Support/CacheProperties.php +++ b/app/Support/CacheProperties.php @@ -71,6 +71,14 @@ class CacheProperties return Cache::has($this->md5); } + /** + * @param $data + */ + public function store($data) + { + Cache::forever($this->md5, $data); + } + /** * @return void */ @@ -95,12 +103,4 @@ class CacheProperties $this->md5 = md5($this->md5); } - - /** - * @param $data - */ - public function store($data) - { - Cache::forever($this->md5, $data); - } } diff --git a/app/Support/Domain.php b/app/Support/Domain.php new file mode 100644 index 0000000000..8506fcc998 --- /dev/null +++ b/app/Support/Domain.php @@ -0,0 +1,45 @@ +label($name, $options); - $options = $this->expandOptionArray($name, $label, $options); - $classes = $this->getHolderClasses($name); - $value = $this->fillFieldValue($name, $value); - $html = view('form.static', compact('classes', 'name', 'label', 'value', 'options'))->render(); - - return $html; - - } - /** * @param $name * @param null $value @@ -63,86 +44,6 @@ class ExpandedForm } - /** - * @param $name - * @param $options - * - * @return mixed - */ - protected function label($name, $options) - { - if (isset($options['label'])) { - return $options['label']; - } - - return trans('form.' . $name); - - } - - /** - * @param $name - * @param $label - * @param array $options - * - * @return array - */ - protected function expandOptionArray($name, $label, array $options) - { - $options['class'] = 'form-control'; - $options['id'] = 'ffInput_' . $name; - $options['autocomplete'] = 'off'; - $options['placeholder'] = ucfirst($label); - - return $options; - } - - /** - * @param $name - * - * @return string - */ - protected function getHolderClasses($name) - { - /* - * Get errors from session: - */ - /** @var MessageBag $errors */ - $errors = Session::get('errors'); - $classes = 'form-group'; - - if (!is_null($errors) && $errors->has($name)) { - $classes = 'form-group has-error has-feedback'; - } - - return $classes; - } - - /** - * @param $name - * @param $value - * - * @return mixed - */ - protected function fillFieldValue($name, $value) - { - if (Session::has('preFilled')) { - $preFilled = Session::get('preFilled'); - $value = isset($preFilled[$name]) && is_null($value) ? $preFilled[$name] : $value; - } - // @codeCoverageIgnoreStart - try { - if (!is_null(Input::old($name))) { - $value = Input::old($name); - } - } catch (RuntimeException $e) { - // don't care about session errors. - } - - // @codeCoverageIgnoreEnd - - return $value; - } - /** * @param $name * @param null $value @@ -208,6 +109,23 @@ class ExpandedForm return $html; } + /** + * @param $name + * @param array $options + * + * @return string + */ + public function file($name, array $options = []) + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $html = view('form.file', compact('classes', 'name', 'label', 'options'))->render(); + + return $html; + + } + /** * @param $name * @param null $value @@ -269,7 +187,7 @@ class ExpandedForm $title = null; foreach ($fields as $field) { - if (isset($entry->$field)) { + if (isset($entry->$field) && is_null($title)) { $title = $entry->$field; } } @@ -366,6 +284,25 @@ class ExpandedForm return $html; } + /** + * @param $name + * @param null $value + * @param array $options + * + * @return string + */ + public function staticText($name, $value, array $options = []) + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $html = view('form.static', compact('classes', 'name', 'label', 'value', 'options'))->render(); + + return $html; + + } + /** * @param $name * @param null $value @@ -385,23 +322,6 @@ class ExpandedForm return $html; } - /** - * @param $name - * @param array $options - * - * @return string - */ - public function file($name, array $options = []) - { - $label = $this->label($name, $options); - $options = $this->expandOptionArray($name, $label, $options); - $classes = $this->getHolderClasses($name); - $html = view('form.file', compact('classes', 'name', 'label', 'options'))->render(); - - return $html; - - } - /** * @param $name * @param null $value @@ -440,4 +360,84 @@ class ExpandedForm return $html; } + + /** + * @param $name + * @param $label + * @param array $options + * + * @return array + */ + protected function expandOptionArray($name, $label, array $options) + { + $options['class'] = 'form-control'; + $options['id'] = 'ffInput_' . $name; + $options['autocomplete'] = 'off'; + $options['placeholder'] = ucfirst($label); + + return $options; + } + + /** + * @param $name + * @param $value + * + * @return mixed + */ + protected function fillFieldValue($name, $value) + { + if (Session::has('preFilled')) { + $preFilled = Session::get('preFilled'); + $value = isset($preFilled[$name]) && is_null($value) ? $preFilled[$name] : $value; + } + // @codeCoverageIgnoreStart + try { + if (!is_null(Input::old($name))) { + $value = Input::old($name); + } + } catch (RuntimeException $e) { + // don't care about session errors. + } + + // @codeCoverageIgnoreEnd + + return $value; + } + + /** + * @param $name + * + * @return string + */ + protected function getHolderClasses($name) + { + /* + * Get errors from session: + */ + /** @var MessageBag $errors */ + $errors = Session::get('errors'); + $classes = 'form-group'; + + if (!is_null($errors) && $errors->has($name)) { + $classes = 'form-group has-error has-feedback'; + } + + return $classes; + } + + /** + * @param $name + * @param $options + * + * @return mixed + */ + protected function label($name, $options) + { + if (isset($options['label'])) { + return $options['label']; + } + + return trans('form.' . $name); + + } } diff --git a/app/Support/Preferences.php b/app/Support/Preferences.php index e705f9cb55..531eb3e0ad 100644 --- a/app/Support/Preferences.php +++ b/app/Support/Preferences.php @@ -13,16 +13,6 @@ use FireflyIII\Models\Preference; */ class Preferences { - /** - * @return string - */ - public function lastActivity() - { - $preference = $this->get('lastActivity', microtime())->data; - - return md5($preference); - } - /** * @param string $name * @param string $default @@ -53,6 +43,26 @@ class Preferences } + /** + * @return string + */ + public function lastActivity() + { + $preference = $this->get('lastActivity', microtime())->data; + + return md5($preference); + } + + /** + * @return bool + */ + public function mark() + { + $this->set('lastActivity', microtime()); + + return true; + } + /** * @param $name * @param string $value @@ -80,14 +90,4 @@ class Preferences return $pref; } - - /** - * @return bool - */ - public function mark() - { - $this->set('lastActivity', microtime()); - - return true; - } } diff --git a/app/Support/Steam.php b/app/Support/Steam.php index 216d5528e4..0358e07abd 100644 --- a/app/Support/Steam.php +++ b/app/Support/Steam.php @@ -16,27 +16,6 @@ use FireflyIII\Models\Transaction; class Steam { - /** - * @param array $accounts - * - * @return array - */ - public function getLastActivities(array $accounts) - { - $list = []; - - $set = Auth::user()->transactions() - ->whereIn('account_id', $accounts) - ->groupBy('account_id') - ->get(['transactions.account_id', DB::Raw('MAX(`transaction_journals`.`date`) as `max_date`')]); - - foreach ($set as $entry) { - $list[intval($entry->account_id)] = new Carbon($entry->max_date); - } - - return $list; - } - /** * * @param \FireflyIII\Models\Account $account @@ -163,7 +142,29 @@ class Steam return $result; } + /** + * @param array $accounts + * + * @return array + */ + public function getLastActivities(array $accounts) + { + $list = []; + + $set = Auth::user()->transactions() + ->whereIn('account_id', $accounts) + ->groupBy('account_id') + ->get(['transactions.account_id', DB::raw('MAX(`transaction_journals`.`date`) as `max_date`')]); + + foreach ($set as $entry) { + $list[intval($entry->account_id)] = new Carbon($entry->max_date); + } + + return $list; + } + // parse PHP size: + /** * @param $string * diff --git a/app/Support/Twig/Journal.php b/app/Support/Twig/Journal.php index 628745d1f8..29b9c2d31f 100644 --- a/app/Support/Twig/Journal.php +++ b/app/Support/Twig/Journal.php @@ -37,7 +37,7 @@ class Journal extends Twig_Extension { $functions = [ $this->invalidJournal(), - $this->relevantTags() + $this->relevantTags(), ]; return $functions; diff --git a/app/Support/Twig/Rule.php b/app/Support/Twig/Rule.php new file mode 100644 index 0000000000..6b0a9e181d --- /dev/null +++ b/app/Support/Twig/Rule.php @@ -0,0 +1,97 @@ + trans('firefly.rule_trigger_store_journal'), + 'update-journal' => trans('firefly.rule_trigger_update_journal'), + ]; + } + ); + } + + /** + * @return Twig_SimpleFunction + */ + public function allRuleTriggers() + { + return new Twig_SimpleFunction( + 'allRuleTriggers', function () { + $ruleTriggers = array_keys(Config::get('firefly.rule-triggers')); + $possibleTriggers = []; + foreach ($ruleTriggers as $key) { + if ($key != 'user_action') { + $possibleTriggers[$key] = trans('firefly.rule_trigger_' . $key . '_choice'); + } + } + unset($key, $ruleTriggers); + + return $possibleTriggers; + } + + ); + + } + + /** + * @return Twig_SimpleFunction + */ + public function allActionTriggers() + { + return new Twig_SimpleFunction( + 'allRuleActions', function () { + // array of valid values for actions + $ruleActions = array_keys(Config::get('firefly.rule-actions')); + $possibleActions = []; + foreach ($ruleActions as $key) { + $possibleActions[$key] = trans('firefly.rule_action_' . $key . '_choice'); + } + unset($key, $ruleActions); + + return $possibleActions; + } + ); + } + + /** + * @return array + */ + public function getFunctions() + { + return [ + $this->allJournalTriggers(), + $this->allRuleTriggers(), + $this->allActionTriggers(), + ]; + + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'FireflyIII\Support\Twig\Rule'; + } +} \ No newline at end of file diff --git a/app/User.php b/app/User.php old mode 100644 new mode 100755 index d1924bbccc..b274e6d9dc --- a/app/User.php +++ b/app/User.php @@ -1,60 +1,36 @@ -hasMany('FireflyIII\Models\Attachment'); } - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function tags() - { - return $this->hasMany('FireflyIII\Models\Tag'); - } - /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ @@ -131,14 +103,6 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon return $this->hasManyThrough('FireflyIII\Models\PiggyBank', 'FireflyIII\Models\Account'); } - /** - * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough - */ - public function transactions() - { - return $this->hasManyThrough('FireflyIII\Models\Transaction', 'FireflyIII\Models\TransactionJournal'); - } - /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ @@ -147,6 +111,30 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon return $this->hasMany('FireflyIII\Models\Preference'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function ruleGroups() + { + return $this->hasMany('FireflyIII\Models\RuleGroup'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function rules() + { + return $this->hasMany('FireflyIII\Models\Rule'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function tags() + { + return $this->hasMany('FireflyIII\Models\Tag'); + } + /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ @@ -155,4 +143,12 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon return $this->hasMany('FireflyIII\Models\TransactionJournal'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough + */ + public function transactions() + { + return $this->hasManyThrough('FireflyIII\Models\Transaction', 'FireflyIII\Models\TransactionJournal'); + } + } diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php index 1503518a1d..8fd6befc1f 100644 --- a/app/Validation/FireflyValidator.php +++ b/app/Validation/FireflyValidator.php @@ -8,10 +8,14 @@ use Crypt; use DB; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; +use FireflyIII\Models\Budget; use FireflyIII\Models\PiggyBank; +use FireflyIII\Models\TransactionType; +use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\User; use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Validation\Validator; +use Log; use Symfony\Component\Translation\TranslatorInterface; /** @@ -28,6 +32,8 @@ class FireflyValidator extends Validator * @param array $rules * @param array $messages * @param array $customAttributes + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) // inherited from Laravel. */ public function __construct(TranslatorInterface $translator, array $data, array $rules, array $messages = [], array $customAttributes = []) { @@ -39,8 +45,6 @@ class FireflyValidator extends Validator * @param $value * @param $parameters * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * * @return bool */ public function validateBelongsToUser($attribute, $value, $parameters) @@ -85,6 +89,82 @@ class FireflyValidator extends Validator return (intval($checksum) === 1); } + /** + * @param $attribute + * + * @return bool + */ + public function validateRuleActionValue($attribute) + { + // get the index from a string like "rule-action-value.2". + $parts = explode('.', $attribute); + $index = $parts[count($parts) - 1]; + // loop all rule-actions. + // check if rule-action-value matches the thing. + + if (is_array($this->data['rule-action'])) { + $name = isset($this->data['rule-action'][$index]) ? $this->data['rule-action'][$index] : 'invalid'; + $value = isset($this->data['rule-action-value'][$index]) ? $this->data['rule-action-value'][$index] : false; + switch ($name) { + default: + Log::debug(' (' . $attribute . ') (index:' . $index . ') Name is "' . $name . '" so no action is taken.'); + + return true; + case 'set_budget': + /** @var BudgetRepositoryInterface $repository */ + $repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $budgets = $repository->getBudgets(); + // count budgets, should have at least one + $count = $budgets->filter( + function (Budget $budget) use ($value) { + return $budget->name == $value; + } + )->count(); + + return ($count === 1); + case 'invalid': + return false; + + } + } + + return false; + } + + /** + * @param $attribute + * + * @return bool + */ + public function validateRuleTriggerValue($attribute) + { + // get the index from a string like "rule-trigger-value.2". + $parts = explode('.', $attribute); + $index = $parts[count($parts) - 1]; + + // loop all rule-triggers. + // check if rule-value matches the thing. + if (is_array($this->data['rule-trigger'])) { + $name = $this->getRuleTriggerName($index); + $value = $this->getRuleTriggerValue($index); + switch ($name) { + default: + return true; + case 'amount_less': + return is_numeric($value); + break; + case 'transaction_type': + $count = TransactionType::where('type', $value)->count(); + + return $count === 1; + break; + case 'invalid': + return false; + break; + } + } + } + /** * @param $attribute * @param $value @@ -116,122 +196,6 @@ class FireflyValidator extends Validator return false; } - /** - * @return bool - */ - protected function validateAccountAnonymously() - { - if (!isset($this->data['user_id'])) { - return false; - } - - $user = User::find($this->data['user_id']); - $type = AccountType::find($this->data['account_type_id'])->first(); - $value = $this->tryDecrypt($this->data['name']); - - - $set = $user->accounts()->where('account_type_id', $type->id)->get(); - /** @var Account $entry */ - foreach ($set as $entry) { - if ($entry->name == $value) { - return false; - } - } - - return true; - } - - /** - * @param $value - * - * @return mixed - */ - protected function tryDecrypt($value) - { - try { - $value = Crypt::decrypt($value); - } catch (DecryptException $e) { - // do not care. - } - - return $value; - } - - /** - * @param $value - * @param $parameters - * - * @return bool - */ - protected function validateByAccountTypeString($value, $parameters) - { - $search = Config::get('firefly.accountTypeByIdentifier.' . $this->data['what']); - $type = AccountType::whereType($search)->first(); - $ignore = isset($parameters[0]) ? intval($parameters[0]) : 0; - - $set = Auth::user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)->get(); - /** @var Account $entry */ - foreach ($set as $entry) { - if ($entry->name == $value) { - return false; - } - } - - return true; - } - - /** - * @param $value - * @param $parameters - * - * @return bool - */ - protected function validateByAccountTypeId($value, $parameters) - { - $type = AccountType::find($this->data['account_type_id'])->first(); - $ignore = isset($parameters[0]) ? intval($parameters[0]) : 0; - $value = $this->tryDecrypt($value); - - $set = Auth::user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)->get(); - /** @var Account $entry */ - foreach ($set as $entry) { - if ($entry->name == $value) { - return false; - } - } - - return true; - - } - - /** - * @param $value - * - * @return bool - * @internal param $parameters - * - */ - protected function validateByAccountId($value) - { - /** @var Account $existingAccount */ - $existingAccount = Account::find($this->data['id']); - - $type = $existingAccount->accountType; - $ignore = $existingAccount->id; - $value = $this->tryDecrypt($value); - - $set = Auth::user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)->get(); - /** @var Account $entry */ - foreach ($set as $entry) { - if ($entry->name == $value) { - return false; - } - } - - return true; - - } - /** * @param $attribute * @param $value @@ -300,17 +264,16 @@ class FireflyValidator extends Validator * @param $value * @param $parameters * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) // cant remove it + * @SuppressWarnings(PHPMD.CyclomaticComplexity) // its as simple as I can get it. * * @return bool */ public function validateUniquePiggyBankForUser($attribute, $value, $parameters) { $exclude = isset($parameters[0]) ? $parameters[0] : null; - $query = DB::table('piggy_banks'); - $query->whereNull('piggy_banks.deleted_at'); - $query->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id'); - $query->where('accounts.user_id', Auth::user()->id); + $query = DB::table('piggy_banks')->whereNull('piggy_banks.deleted_at') + ->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')->where('accounts.user_id', Auth::user()->id); if (!is_null($exclude)) { $query->where('piggy_banks.id', '!=', $exclude); } @@ -325,7 +288,143 @@ class FireflyValidator extends Validator } return true; + } + /** + * @param $value + * + * @return mixed + */ + protected function tryDecrypt($value) + { + try { + $value = Crypt::decrypt($value); + } catch (DecryptException $e) { + // do not care. + } + + return $value; + } + + /** + * @return bool + */ + protected function validateAccountAnonymously() + { + if (!isset($this->data['user_id'])) { + return false; + } + + $user = User::find($this->data['user_id']); + $type = AccountType::find($this->data['account_type_id'])->first(); + $value = $this->tryDecrypt($this->data['name']); + + + $set = $user->accounts()->where('account_type_id', $type->id)->get(); + /** @var Account $entry */ + foreach ($set as $entry) { + if ($entry->name == $value) { + return false; + } + } + + return true; + } + + /** + * @param $value + * + * @return bool + * @internal param $parameters + * + */ + protected function validateByAccountId($value) + { + /** @var Account $existingAccount */ + $existingAccount = Account::find($this->data['id']); + + $type = $existingAccount->accountType; + $ignore = $existingAccount->id; + $value = $this->tryDecrypt($value); + + $set = Auth::user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)->get(); + /** @var Account $entry */ + foreach ($set as $entry) { + if ($entry->name == $value) { + return false; + } + } + + return true; + + } + + /** + * @param $value + * @param $parameters + * + * @return bool + */ + protected function validateByAccountTypeId($value, $parameters) + { + $type = AccountType::find($this->data['account_type_id'])->first(); + $ignore = isset($parameters[0]) ? intval($parameters[0]) : 0; + $value = $this->tryDecrypt($value); + + $set = Auth::user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)->get(); + /** @var Account $entry */ + foreach ($set as $entry) { + if ($entry->name == $value) { + return false; + } + } + + return true; + + } + + /** + * @param $value + * @param $parameters + * + * @return bool + */ + protected function validateByAccountTypeString($value, $parameters) + { + $search = Config::get('firefly.accountTypeByIdentifier.' . $this->data['what']); + $type = AccountType::whereType($search)->first(); + $ignore = isset($parameters[0]) ? intval($parameters[0]) : 0; + + $set = Auth::user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)->get(); + /** @var Account $entry */ + foreach ($set as $entry) { + if ($entry->name == $value) { + return false; + } + } + + return true; + } + + /** + * @param int $index + * + * @return string + */ + private function getRuleTriggerName($index) + { + return isset($this->data['rule-trigger'][$index]) ? $this->data['rule-trigger'][$index] : 'invalid'; + + } + + /** + * @param int $index + * + * @return string + */ + private function getRuleTriggerValue($index) + { + return isset($this->data['rule-trigger-value'][$index]) ? $this->data['rule-trigger-value'][$index] : ''; } } diff --git a/artisan b/artisan old mode 100644 new mode 100755 index eb5e2bb62d..df630d0d6d --- a/artisan +++ b/artisan @@ -28,11 +28,11 @@ $app = require_once __DIR__.'/bootstrap/app.php'; | */ -$kernel = $app->make('Illuminate\Contracts\Console\Kernel'); +$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class); $status = $kernel->handle( - $input = new Symfony\Component\Console\Input\ArgvInput, - new Symfony\Component\Console\Output\ConsoleOutput + $input = new Symfony\Component\Console\Input\ArgvInput, + new Symfony\Component\Console\Output\ConsoleOutput ); /* diff --git a/bootstrap/app.php b/bootstrap/app.php old mode 100644 new mode 100755 index 3eef0b49d7..ebd712abe1 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -11,9 +11,8 @@ | */ - $app = new Illuminate\Foundation\Application( - realpath(__DIR__ . '/../') + realpath(__DIR__.'/../') ); /* @@ -27,23 +26,21 @@ $app = new Illuminate\Foundation\Application( | */ - $app->singleton( - 'Illuminate\Contracts\Http\Kernel', - 'FireflyIII\Http\Kernel' + Illuminate\Contracts\Http\Kernel::class, + FireflyIII\Http\Kernel::class ); $app->singleton( - 'Illuminate\Contracts\Console\Kernel', - 'FireflyIII\Console\Kernel' + Illuminate\Contracts\Console\Kernel::class, + FireflyIII\Console\Kernel::class ); $app->singleton( - 'Illuminate\Contracts\Debug\ExceptionHandler', - 'FireflyIII\Exceptions\Handler' + Illuminate\Contracts\Debug\ExceptionHandler::class, + FireflyIII\Exceptions\Handler::class ); - /* |-------------------------------------------------------------------------- | Return The Application diff --git a/bootstrap/autoload.php b/bootstrap/autoload.php old mode 100644 new mode 100755 index 0f75195105..383013796f --- a/bootstrap/autoload.php +++ b/bootstrap/autoload.php @@ -14,7 +14,7 @@ define('LARAVEL_START', microtime(true)); | */ -require __DIR__ . '/../vendor/autoload.php'; +require __DIR__.'/../vendor/autoload.php'; /* |-------------------------------------------------------------------------- @@ -27,7 +27,7 @@ require __DIR__ . '/../vendor/autoload.php'; | */ -$compiledPath = __DIR__ . '/cache/compiled.php'; +$compiledPath = __DIR__.'/cache/compiled.php'; if (file_exists($compiledPath)) { require $compiledPath; diff --git a/bootstrap/cache/.gitignore b/bootstrap/cache/.gitignore old mode 100644 new mode 100755 diff --git a/build/logs/.gitignore b/build/logs/.gitignore deleted file mode 100644 index 67c51fe2b0..0000000000 --- a/build/logs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.xml -*.json diff --git a/codeception.yml b/codeception.yml deleted file mode 100644 index 3a8fca8145..0000000000 --- a/codeception.yml +++ /dev/null @@ -1,21 +0,0 @@ -actor: Tester -paths: - tests: tests - log: tests/_output - data: tests/_data - support: tests/_support - envs: tests/_envs -settings: - bootstrap: _bootstrap.php - colors: true - memory_limit: 1024M -extensions: - enabled: - - Codeception\Extension\RunFailed -modules: - config: - Db: - dsn: '' - user: '' - password: '' - dump: tests/_data/dump.sql diff --git a/composer.json b/composer.json old mode 100644 new mode 100755 index 47b7746e25..7dbfee8eb0 --- a/composer.json +++ b/composer.json @@ -1,68 +1,72 @@ { - "name": "grumpydictator/firefly-iii", - "description": "Firefly III: a personal finances manager.", - "keywords": ["finance", "finances", "manager", "euro", "laravel", "money", "financials", "budgets", "transactions", "transfers", "management"], - "license": "MIT", - "homepage": "https://github.com/JC5/firefly-iii", - "type": "project", - "authors": [ - { - "name": "James Cole", - "email": "thegrumpydictator@gmail.com", - "homepage": "https://github.com/JC5", - "role": "Developer" - } - ], - "support": { - "email": "thegrumpydictator@gmail.com", - "issues": "https://github.com/JC5/firefly-iii/issues?state=open", - "source": "https://github.com/JC5/firefly-iii" + "name": "grumpydictator/firefly-iii", + "description": "Firefly III: a personal finances manager.", + "keywords": ["finance", "finances", "manager", "euro", "laravel", "money", "financials", "budgets", "transactions", "transfers", "management"], + "license": "MIT", + "homepage": "https://github.com/JC5/firefly-iii", + "type": "project", + "authors": [ + { + "name": "James Cole", + "email": "thegrumpydictator@gmail.com", + "homepage": "https://github.com/JC5", + "role": "Developer" + }], - }, - "require": { - "laravel/framework": "5.1.*", - "php": ">=5.6.4", - "davejamesmiller/laravel-breadcrumbs": "~3.0", - "watson/validating": "~1.0", - "doctrine/dbal": "~2.5", - "illuminate/html": "~5.0", - "league/commonmark": "~0.7", - "rcrowe/twigbridge": "~0.9", - "zizaco/entrust": "dev-laravel-5", - "league/csv": "^7.1" - }, - "require-dev": { - "barryvdh/laravel-debugbar": "@stable", - "barryvdh/laravel-ide-helper": "~2.0" - }, - "autoload": { - "classmap": [ - "database" - ], - "psr-4": { - "FireflyIII\\": "app/" - } - }, - "autoload-dev": { - "classmap": [ - "tests/TestCase.php" - ] - }, - "scripts": { - "post-install-cmd": [ - "php artisan clear-compiled", - "php artisan optimize" - ], - "post-update-cmd": [ - "php artisan clear-compiled", - "php artisan optimize" - ], - "post-create-project-cmd": [ - "php -r \"copy('.env.example', '.env');\"", - "php artisan key:generate" - ] - }, - "config": { - "preferred-install": "dist" + "require": { + "laravel/framework": "5.2.*", + "davejamesmiller/laravel-breadcrumbs": "~3.0", + "watson/validating": "~2.0", + "doctrine/dbal": "~2.5", + "league/commonmark": "~0.7", + "rcrowe/twigbridge": "~0.9", + "zizaco/entrust": "dev-laravel-5", + "league/csv": "^7.1", + "laravelcollective/html": "^5.2" + }, + "require-dev": { + "fzaninotto/faker": "~1.4", + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "~4.0", + "symfony/css-selector": "2.8.*|3.0.*", + "symfony/dom-crawler": "2.8.*|3.0.*", + "barryvdh/laravel-debugbar": "@stable", + "barryvdh/laravel-ide-helper": "~2.0" + }, + "autoload": { + "classmap": [ + "database" + ], + "psr-4": { + "FireflyIII\\": "app/" } + }, + "autoload-dev": { + "classmap": [ + "tests/TestCase.php" + ] + }, + "scripts": { + "post-root-package-install": [ + "php -r \"copy('.env.example', '.env');\"" + ], + "post-create-project-cmd": [ + "php artisan key:generate" + ], + "post-install-cmd": [ + "php artisan clear-compiled", + "php artisan optimize", + "php artisan firefly:upgrade-instructions" + ], + "pre-update-cmd": [ + "php artisan clear-compiled" + ], + "post-update-cmd": [ + "php artisan optimize", + "php artisan firefly:upgrade-instructions" + ] + }, + "config": { + "preferred-install": "dist" + } } diff --git a/composer.lock b/composer.lock index bc2c523575..91b23f2f19 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "8ed88de4a8bb53d4fff4b764048b8d32", - "content-hash": "1d6d8db5b01d70aed4926680b5236331", + "hash": "df00127da416acad2a36b6128b82fdd9", + "content-hash": "28b178f07a713b4db441e7e1f380916e", "packages": [ { "name": "classpreloader/classpreloader", @@ -61,62 +61,6 @@ ], "time": "2015-11-09 22:51:51" }, - { - "name": "danielstjules/stringy", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/danielstjules/Stringy.git", - "reference": "4749c205db47ee5b32e8d1adf6d9aff8db6caf3b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/danielstjules/Stringy/zipball/4749c205db47ee5b32e8d1adf6d9aff8db6caf3b", - "reference": "4749c205db47ee5b32e8d1adf6d9aff8db6caf3b", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Stringy\\": "src/" - }, - "files": [ - "src/Create.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel St. Jules", - "email": "danielst.jules@gmail.com", - "homepage": "http://www.danielstjules.com" - } - ], - "description": "A string manipulation library with multibyte support", - "homepage": "https://github.com/danielstjules/Stringy", - "keywords": [ - "UTF", - "helpers", - "manipulation", - "methods", - "multibyte", - "string", - "utf-8", - "utility", - "utils" - ], - "time": "2015-07-23 00:54:12" - }, { "name": "davejamesmiller/laravel-breadcrumbs", "version": "3.0.0", @@ -668,52 +612,6 @@ ], "time": "2014-09-09 13:34:57" }, - { - "name": "illuminate/html", - "version": "v5.0.0", - "source": { - "type": "git", - "url": "https://github.com/illuminate/html.git", - "reference": "3d1009bb8e0f25720c914af5c1f4015dd373c9ef" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/html/zipball/3d1009bb8e0f25720c914af5c1f4015dd373c9ef", - "reference": "3d1009bb8e0f25720c914af5c1f4015dd373c9ef", - "shasum": "" - }, - "require": { - "illuminate/http": "~5.0", - "illuminate/session": "~5.0", - "illuminate/support": "~5.0", - "php": ">=5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "Illuminate\\Html\\": "" - }, - "files": [ - "helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - } - ], - "time": "2015-01-01 16:31:18" - }, { "name": "jakub-onderka/php-console-color", "version": "0.1", @@ -861,45 +759,43 @@ }, { "name": "laravel/framework", - "version": "v5.1.28", + "version": "v5.2.10", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "3f0fd27939dfdafb1e50058423cd24e640894ba2" + "reference": "93dc5b0089eef468157fd7200e575c3861ec59a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/3f0fd27939dfdafb1e50058423cd24e640894ba2", - "reference": "3f0fd27939dfdafb1e50058423cd24e640894ba2", + "url": "https://api.github.com/repos/laravel/framework/zipball/93dc5b0089eef468157fd7200e575c3861ec59a5", + "reference": "93dc5b0089eef468157fd7200e575c3861ec59a5", "shasum": "" }, "require": { - "classpreloader/classpreloader": "~2.0|~3.0", - "danielstjules/stringy": "~1.8", + "classpreloader/classpreloader": "~3.0", "doctrine/inflector": "~1.0", "ext-mbstring": "*", "ext-openssl": "*", - "jeremeamia/superclosure": "~2.0", + "jeremeamia/superclosure": "~2.2", "league/flysystem": "~1.0", "monolog/monolog": "~1.11", "mtdowling/cron-expression": "~1.0", - "nesbot/carbon": "~1.19", + "nesbot/carbon": "~1.20", "paragonie/random_compat": "~1.1", "php": ">=5.5.9", "psy/psysh": "0.6.*", "swiftmailer/swiftmailer": "~5.1", - "symfony/console": "2.7.*", - "symfony/css-selector": "2.7.*", - "symfony/debug": "2.7.*", - "symfony/dom-crawler": "2.7.*", - "symfony/finder": "2.7.*", - "symfony/http-foundation": "2.7.*", - "symfony/http-kernel": "2.7.*", - "symfony/process": "2.7.*", - "symfony/routing": "2.7.*", - "symfony/translation": "2.7.*", - "symfony/var-dumper": "2.7.*", - "vlucas/phpdotenv": "~1.0" + "symfony/console": "2.8.*|3.0.*", + "symfony/debug": "2.8.*|3.0.*", + "symfony/finder": "2.8.*|3.0.*", + "symfony/http-foundation": "2.8.*|3.0.*", + "symfony/http-kernel": "2.8.*|3.0.*", + "symfony/polyfill-php56": "~1.0", + "symfony/process": "2.8.*|3.0.*", + "symfony/routing": "2.8.*|3.0.*", + "symfony/translation": "2.8.*|3.0.*", + "symfony/var-dumper": "2.8.*|3.0.*", + "vlucas/phpdotenv": "~2.2" }, "replace": { "illuminate/auth": "self.version", @@ -933,28 +829,30 @@ }, "require-dev": { "aws/aws-sdk-php": "~3.0", - "iron-io/iron_mq": "~2.0", "mockery/mockery": "~0.9.2", "pda/pheanstalk": "~3.0", - "phpunit/phpunit": "~4.0", - "predis/predis": "~1.0" + "phpunit/phpunit": "~4.1", + "predis/predis": "~1.0", + "symfony/css-selector": "2.8.*|3.0.*", + "symfony/dom-crawler": "2.8.*|3.0.*" }, "suggest": { "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).", "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~5.3|~6.0).", - "iron-io/iron_mq": "Required to use the iron queue driver (~2.0).", "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).", "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0)." + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0).", + "symfony/css-selector": "Required to use some of the crawler integration testing tools (2.8.*|3.0.*).", + "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (2.8.*|3.0.*)." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-master": "5.2-dev" } }, "autoload": { @@ -985,20 +883,74 @@ "framework", "laravel" ], - "time": "2015-12-31 17:41:30" + "time": "2016-01-13 20:29:10" }, { - "name": "league/commonmark", - "version": "0.12.0", + "name": "laravelcollective/html", + "version": "v5.2.2", "source": { "type": "git", - "url": "https://github.com/thephpleague/commonmark.git", - "reference": "3eb64850ee688623db494398a5284a7a4cdf7b47" + "url": "https://github.com/LaravelCollective/html.git", + "reference": "c88b2d59a56ed2290fc5082a1a6099e357c9fdbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/3eb64850ee688623db494398a5284a7a4cdf7b47", - "reference": "3eb64850ee688623db494398a5284a7a4cdf7b47", + "url": "https://api.github.com/repos/LaravelCollective/html/zipball/c88b2d59a56ed2290fc5082a1a6099e357c9fdbc", + "reference": "c88b2d59a56ed2290fc5082a1a6099e357c9fdbc", + "shasum": "" + }, + "require": { + "illuminate/http": "5.2.*", + "illuminate/routing": "5.2.*", + "illuminate/session": "5.2.*", + "illuminate/support": "5.2.*", + "illuminate/view": "5.2.*", + "php": ">=5.5.9" + }, + "require-dev": { + "illuminate/database": "5.2.*", + "mockery/mockery": "~0.9", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Collective\\Html\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + }, + { + "name": "Adam Engebretson", + "email": "adam@laravelcollective.com" + } + ], + "description": "HTML and Form Builders for the Laravel Framework", + "homepage": "http://laravelcollective.com", + "time": "2016-01-16 16:54:49" + }, + { + "name": "league/commonmark", + "version": "0.13.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "a4e93bc4fd1a8ff8f534040c4a07371ea5f4b484" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/a4e93bc4fd1a8ff8f534040c4a07371ea5f4b484", + "reference": "a4e93bc4fd1a8ff8f534040c4a07371ea5f4b484", "shasum": "" }, "require": { @@ -1010,21 +962,23 @@ }, "require-dev": { "erusev/parsedown": "~1.0", - "jgm/commonmark": "0.22", - "jgm/smartpunct": "0.22", + "jgm/commonmark": "0.24", "michelf/php-markdown": "~1.4", "mikehaertl/php-shellcommand": "~1.1.0", "phpunit/phpunit": "~4.3|~5.0", "scrutinizer/ocular": "^1.1", "symfony/finder": "~2.3" }, + "suggest": { + "league/commonmark-extras": "Library of useful extensions including smart punctuation" + }, "bin": [ "bin/commonmark" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "0.13-dev" + "dev-master": "0.14-dev" } }, "autoload": { @@ -1051,7 +1005,7 @@ "markdown", "parser" ], - "time": "2015-11-04 14:24:41" + "time": "2016-01-14 04:29:54" }, { "name": "league/csv", @@ -1690,25 +1644,26 @@ }, { "name": "symfony/console", - "version": "v2.7.8", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "4e35a78f932a4c07bd349efea647ac741c1419b6" + "reference": "ebcdc507829df915f4ca23067bd59ee4ef61f6c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/4e35a78f932a4c07bd349efea647ac741c1419b6", - "reference": "4e35a78f932a4c07bd349efea647ac741c1419b6", + "url": "https://api.github.com/repos/symfony/console/zipball/ebcdc507829df915f4ca23067bd59ee4ef61f6c3", + "reference": "ebcdc507829df915f4ca23067bd59ee4ef61f6c3", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.1", - "symfony/process": "~2.1" + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" }, "suggest": { "psr/log": "For using the console logger", @@ -1718,7 +1673,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1745,90 +1700,37 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2015-12-23 11:17:38" - }, - { - "name": "symfony/css-selector", - "version": "v2.7.8", - "source": { - "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "35bebec48d3d08e3138257419e3ca84070152012" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/35bebec48d3d08e3138257419e3ca84070152012", - "reference": "35bebec48d3d08e3138257419e3ca84070152012", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\CssSelector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony CssSelector Component", - "homepage": "https://symfony.com", - "time": "2015-12-05 17:37:09" + "time": "2015-12-22 10:39:06" }, { "name": "symfony/debug", - "version": "v2.7.8", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "08589346bd2ec9a8eb3d935e3b1fedba9bb6463f" + "reference": "73612266ac709769effdbfc0762e5b07cfd2ac2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/08589346bd2ec9a8eb3d935e3b1fedba9bb6463f", - "reference": "08589346bd2ec9a8eb3d935e3b1fedba9bb6463f", + "url": "https://api.github.com/repos/symfony/debug/zipball/73612266ac709769effdbfc0762e5b07cfd2ac2a", + "reference": "73612266ac709769effdbfc0762e5b07cfd2ac2a", "shasum": "" }, "require": { - "php": ">=5.3.9", + "php": ">=5.5.9", "psr/log": "~1.0" }, "conflict": { "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" }, "require-dev": { - "symfony/class-loader": "~2.2", - "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2" + "symfony/class-loader": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1855,86 +1757,31 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2015-12-26 14:05:15" - }, - { - "name": "symfony/dom-crawler", - "version": "v2.7.8", - "source": { - "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "b33593cbfe1d81b50d48353f338aca76a08658d8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b33593cbfe1d81b50d48353f338aca76a08658d8", - "reference": "b33593cbfe1d81b50d48353f338aca76a08658d8", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "require-dev": { - "symfony/css-selector": "~2.3" - }, - "suggest": { - "symfony/css-selector": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony DomCrawler Component", - "homepage": "https://symfony.com", - "time": "2015-11-02 20:20:53" + "time": "2015-12-26 13:39:53" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.1", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc" + "reference": "d36355e026905fa5229e1ed7b4e9eda2e67adfcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a5eb815363c0388e83247e7e9853e5dbc14999cc", - "reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d36355e026905fa5229e1ed7b4e9eda2e67adfcf", + "reference": "d36355e026905fa5229e1ed7b4e9eda2e67adfcf", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.0,>=2.0.5|~3.0.0", - "symfony/dependency-injection": "~2.6|~3.0.0", - "symfony/expression-language": "~2.6|~3.0.0", - "symfony/stopwatch": "~2.3|~3.0.0" + "symfony/config": "~2.8|~3.0", + "symfony/dependency-injection": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0" }, "suggest": { "symfony/dependency-injection": "", @@ -1943,7 +1790,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1970,29 +1817,29 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2015-10-30 20:15:42" + "time": "2015-10-30 23:35:59" }, { "name": "symfony/finder", - "version": "v2.7.8", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "937edcbac3f2dd3187c56cf90368867d55dee991" + "reference": "8617895eb798b6bdb338321ce19453dc113e5675" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/937edcbac3f2dd3187c56cf90368867d55dee991", - "reference": "937edcbac3f2dd3187c56cf90368867d55dee991", + "url": "https://api.github.com/repos/symfony/finder/zipball/8617895eb798b6bdb338321ce19453dc113e5675", + "reference": "8617895eb798b6bdb338321ce19453dc113e5675", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2019,41 +1866,38 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2015-12-05 11:06:38" + "time": "2015-12-05 11:13:14" }, { "name": "symfony/http-foundation", - "version": "v2.7.8", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "cf11faac7df5384bb14774ad7266add227e10ec1" + "reference": "939c8c28a5b1e4ab7317bc30c1f9aa881c4b06b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/cf11faac7df5384bb14774ad7266add227e10ec1", - "reference": "cf11faac7df5384bb14774ad7266add227e10ec1", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/939c8c28a5b1e4ab7317bc30c1f9aa881c4b06b5", + "reference": "939c8c28a5b1e4ab7317bc30c1f9aa881c4b06b5", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9" }, "require-dev": { - "symfony/expression-language": "~2.4" + "symfony/expression-language": "~2.8|~3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "3.0-dev" } }, "autoload": { "psr-4": { "Symfony\\Component\\HttpFoundation\\": "" }, - "classmap": [ - "Resources/stubs" - ], "exclude-from-classmap": [ "/Tests/" ] @@ -2074,48 +1918,48 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2015-12-18 15:35:58" + "time": "2015-12-18 15:43:53" }, { "name": "symfony/http-kernel", - "version": "v2.7.8", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "2dea13800e1a48710cf23a2c60c804c88e72ed57" + "reference": "f7933e9f19e26e7baba7ec04735b466fedd3a6db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/2dea13800e1a48710cf23a2c60c804c88e72ed57", - "reference": "2dea13800e1a48710cf23a2c60c804c88e72ed57", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f7933e9f19e26e7baba7ec04735b466fedd3a6db", + "reference": "f7933e9f19e26e7baba7ec04735b466fedd3a6db", "shasum": "" }, "require": { - "php": ">=5.3.9", + "php": ">=5.5.9", "psr/log": "~1.0", - "symfony/debug": "~2.6,>=2.6.2", - "symfony/event-dispatcher": "~2.6,>=2.6.7", - "symfony/http-foundation": "~2.5,>=2.5.4" + "symfony/debug": "~2.8|~3.0", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/http-foundation": "~2.8|~3.0" }, "conflict": { - "symfony/config": "<2.7" + "symfony/config": "<2.8" }, "require-dev": { - "symfony/browser-kit": "~2.3", - "symfony/class-loader": "~2.1", - "symfony/config": "~2.7", - "symfony/console": "~2.3", - "symfony/css-selector": "~2.0,>=2.0.5", - "symfony/dependency-injection": "~2.2", - "symfony/dom-crawler": "~2.0,>=2.0.5", - "symfony/expression-language": "~2.4", - "symfony/finder": "~2.0,>=2.0.5", - "symfony/process": "~2.0,>=2.0.5", - "symfony/routing": "~2.2", - "symfony/stopwatch": "~2.3", - "symfony/templating": "~2.2", - "symfony/translation": "~2.0,>=2.0.5", - "symfony/var-dumper": "~2.6" + "symfony/browser-kit": "~2.8|~3.0", + "symfony/class-loader": "~2.8|~3.0", + "symfony/config": "~2.8|~3.0", + "symfony/console": "~2.8|~3.0", + "symfony/css-selector": "~2.8|~3.0", + "symfony/dependency-injection": "~2.8|~3.0", + "symfony/dom-crawler": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/finder": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0", + "symfony/routing": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0", + "symfony/templating": "~2.8|~3.0", + "symfony/translation": "~2.8|~3.0", + "symfony/var-dumper": "~2.8|~3.0" }, "suggest": { "symfony/browser-kit": "", @@ -2129,7 +1973,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2156,7 +2000,66 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2015-12-26 15:01:55" + "time": "2015-12-26 16:46:13" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/49ff736bd5d41f45240cec77b44967d76e0c3d25", + "reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2015-11-20 09:19:13" }, { "name": "symfony/polyfill-php56", @@ -2268,25 +2171,25 @@ }, { "name": "symfony/process", - "version": "v2.7.8", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "a3fb8f4c4afc4f1b285de5df07e568602934f525" + "reference": "f4794f1d00f0746621be3020ffbd8c5e0b217ee3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/a3fb8f4c4afc4f1b285de5df07e568602934f525", - "reference": "a3fb8f4c4afc4f1b285de5df07e568602934f525", + "url": "https://api.github.com/repos/symfony/process/zipball/f4794f1d00f0746621be3020ffbd8c5e0b217ee3", + "reference": "f4794f1d00f0746621be3020ffbd8c5e0b217ee3", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2313,47 +2216,48 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2015-12-23 11:03:39" + "time": "2015-12-23 11:04:02" }, { "name": "symfony/routing", - "version": "v2.7.8", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "2c100bd94be50e2a1fce7fe1ac534e28776c24ff" + "reference": "3b1bac52f42cb0f54df1a2dbabd55a1d214e2a59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/2c100bd94be50e2a1fce7fe1ac534e28776c24ff", - "reference": "2c100bd94be50e2a1fce7fe1ac534e28776c24ff", + "url": "https://api.github.com/repos/symfony/routing/zipball/3b1bac52f42cb0f54df1a2dbabd55a1d214e2a59", + "reference": "3b1bac52f42cb0f54df1a2dbabd55a1d214e2a59", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9" }, "conflict": { - "symfony/config": "<2.7" + "symfony/config": "<2.8" }, "require-dev": { "doctrine/annotations": "~1.0", "doctrine/common": "~2.2", "psr/log": "~1.0", - "symfony/config": "~2.7", - "symfony/expression-language": "~2.4", - "symfony/http-foundation": "~2.3", - "symfony/yaml": "~2.0,>=2.0.5" + "symfony/config": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/http-foundation": "~2.8|~3.0", + "symfony/yaml": "~2.8|~3.0" }, "suggest": { "doctrine/annotations": "For using the annotation loader", "symfony/config": "For using the all-in-one router or any loader", + "symfony/dependency-injection": "For loading routes from a service", "symfony/expression-language": "For using expression matching", "symfony/yaml": "For using the YAML loader" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2386,33 +2290,34 @@ "uri", "url" ], - "time": "2015-12-23 06:54:35" + "time": "2015-12-23 08:00:11" }, { "name": "symfony/translation", - "version": "v2.7.8", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "e7e95debf0465f7886d2994cd808f9382adb423c" + "reference": "dff0867826a7068d673801b7522f8e2634016ef9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e7e95debf0465f7886d2994cd808f9382adb423c", - "reference": "e7e95debf0465f7886d2994cd808f9382adb423c", + "url": "https://api.github.com/repos/symfony/translation/zipball/dff0867826a7068d673801b7522f8e2634016ef9", + "reference": "dff0867826a7068d673801b7522f8e2634016ef9", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/config": "<2.7" + "symfony/config": "<2.8" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.7", - "symfony/intl": "~2.4", - "symfony/yaml": "~2.2" + "symfony/config": "~2.8|~3.0", + "symfony/intl": "~2.8|~3.0", + "symfony/yaml": "~2.8|~3.0" }, "suggest": { "psr/log": "To use logging capability in translator", @@ -2422,7 +2327,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2449,24 +2354,28 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2015-12-05 17:37:09" + "time": "2015-12-05 17:45:07" }, { "name": "symfony/var-dumper", - "version": "v2.7.8", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "ec3233d755578c56612c13d81d4ef141f8f94e9e" + "reference": "87db8700deb12ba2b65e858f656a1f885530bcb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ec3233d755578c56612c13d81d4ef141f8f94e9e", - "reference": "ec3233d755578c56612c13d81d4ef141f8f94e9e", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/87db8700deb12ba2b65e858f656a1f885530bcb0", + "reference": "87db8700deb12ba2b65e858f656a1f885530bcb0", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "twig/twig": "~1.20|~2.0" }, "suggest": { "ext-symfony_debug": "" @@ -2474,7 +2383,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2508,20 +2417,20 @@ "debug", "dump" ], - "time": "2015-12-05 10:02:55" + "time": "2015-12-05 11:13:14" }, { "name": "twig/twig", - "version": "v1.23.1", + "version": "v1.23.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6" + "reference": "ae53fc2c312fdee63773b75cb570304f85388b08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/d9b6333ae8dd2c8e3fd256e127548def0bc614c6", - "reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/ae53fc2c312fdee63773b75cb570304f85388b08", + "reference": "ae53fc2c312fdee63773b75cb570304f85388b08", "shasum": "" }, "require": { @@ -2569,32 +2478,37 @@ "keywords": [ "templating" ], - "time": "2015-11-05 12:49:06" + "time": "2016-01-11 14:02:19" }, { "name": "vlucas/phpdotenv", - "version": "v1.1.1", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "0cac554ce06277e33ddf9f0b7ade4b8bbf2af3fa" + "reference": "9caf304153dc2288e4970caec6f1f3b3bc205412" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/0cac554ce06277e33ddf9f0b7ade4b8bbf2af3fa", - "reference": "0cac554ce06277e33ddf9f0b7ade4b8bbf2af3fa", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/9caf304153dc2288e4970caec6f1f3b3bc205412", + "reference": "9caf304153dc2288e4970caec6f1f3b3bc205412", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": ">=5.3.9" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "^4.8|^5.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, "autoload": { - "psr-0": { - "Dotenv": "src/" + "psr-4": { + "Dotenv\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2615,28 +2529,28 @@ "env", "environment" ], - "time": "2015-05-30 15:59:26" + "time": "2015-12-29 15:10:30" }, { "name": "watson/validating", - "version": "1.0.9", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/dwightwatson/validating.git", - "reference": "0b225ddc3187745ff9efcbcd0d9b4b712df190ba" + "reference": "508c130ea82bc83c65071ffcf1680cdfa16412d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dwightwatson/validating/zipball/0b225ddc3187745ff9efcbcd0d9b4b712df190ba", - "reference": "0b225ddc3187745ff9efcbcd0d9b4b712df190ba", + "url": "https://api.github.com/repos/dwightwatson/validating/zipball/508c130ea82bc83c65071ffcf1680cdfa16412d6", + "reference": "508c130ea82bc83c65071ffcf1680cdfa16412d6", "shasum": "" }, "require": { - "illuminate/contracts": "5.0.*|5.1.*", - "illuminate/database": "5.0.*|5.1.*", - "illuminate/events": "5.0.*|5.1.*", - "illuminate/support": "5.0.*|5.1.*", - "illuminate/validation": "5.0.*|5.1.*", + "illuminate/contracts": "~5.0", + "illuminate/database": "~5.0 || >=5.1.27", + "illuminate/events": "~5.0", + "illuminate/support": "~5.0", + "illuminate/validation": "~5.0", "php": ">=5.4.0" }, "require-dev": { @@ -2670,7 +2584,7 @@ "laravel", "validation" ], - "time": "2015-12-16 23:15:51" + "time": "2015-12-25 23:19:17" }, { "name": "zizaco/entrust", @@ -2740,7 +2654,1460 @@ "time": "2015-11-12 17:38:37" } ], - "packages-dev": null, + "packages-dev": [ + { + "name": "barryvdh/laravel-debugbar", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-debugbar.git", + "reference": "974fd16e328ca851a081449100d9509af59cf0ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/974fd16e328ca851a081449100d9509af59cf0ff", + "reference": "974fd16e328ca851a081449100d9509af59cf0ff", + "shasum": "" + }, + "require": { + "illuminate/support": "~5.0.17|5.1.*|5.2.*", + "maximebf/debugbar": "~1.11.0", + "php": ">=5.4.0", + "symfony/finder": "~2.6|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\Debugbar\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "PHP Debugbar integration for Laravel", + "keywords": [ + "debug", + "debugbar", + "laravel", + "profiler", + "webprofiler" + ], + "time": "2015-12-22 06:22:38" + }, + { + "name": "barryvdh/laravel-ide-helper", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-ide-helper.git", + "reference": "d82e8f191fb043a0f8cbf2de64fd3027bfa4f772" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/d82e8f191fb043a0f8cbf2de64fd3027bfa4f772", + "reference": "d82e8f191fb043a0f8cbf2de64fd3027bfa4f772", + "shasum": "" + }, + "require": { + "illuminate/console": "5.0.x|5.1.x|5.2.x", + "illuminate/filesystem": "5.0.x|5.1.x|5.2.x", + "illuminate/support": "5.0.x|5.1.x|5.2.x", + "php": ">=5.4.0", + "phpdocumentor/reflection-docblock": "2.0.4", + "symfony/class-loader": "~2.3" + }, + "require-dev": { + "doctrine/dbal": "~2.3" + }, + "suggest": { + "doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\LaravelIdeHelper\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.", + "keywords": [ + "autocomplete", + "codeintel", + "helper", + "ide", + "laravel", + "netbeans", + "phpdoc", + "phpstorm", + "sublime" + ], + "time": "2015-12-21 19:48:06" + }, + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14 21:17:01" + }, + { + "name": "fzaninotto/faker", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "d0190b156bcca848d401fb80f31f504f37141c8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d0190b156bcca848d401fb80f31f504f37141c8d", + "reference": "d0190b156bcca848d401fb80f31f504f37141c8d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "suggest": { + "ext-intl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2015-05-29 06:29:14" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b37020aa976fa52d3de9aa904aa2522dc518f79c", + "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "1.3.3", + "satooshi/php-coveralls": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "hamcrest" + ], + "files": [ + "hamcrest/Hamcrest.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "time": "2015-05-11 14:41:42" + }, + { + "name": "maximebf/debugbar", + "version": "v1.11.0", + "source": { + "type": "git", + "url": "https://github.com/maximebf/php-debugbar.git", + "reference": "07741d84d39d10f00551c94284cdefcc69703e77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/07741d84d39d10f00551c94284cdefcc69703e77", + "reference": "07741d84d39d10f00551c94284cdefcc69703e77", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "^1.0", + "symfony/var-dumper": "^2.6|^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0" + }, + "suggest": { + "kriswallsmith/assetic": "The best way to manage assets", + "monolog/monolog": "Log using Monolog", + "predis/predis": "Redis storage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + }, + "autoload": { + "psr-4": { + "DebugBar\\": "src/DebugBar/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maxime Bouroumeau-Fuseau", + "email": "maxime.bouroumeau@gmail.com", + "homepage": "http://maximebf.com" + }, + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Debug bar in the browser for php application", + "homepage": "https://github.com/maximebf/php-debugbar", + "keywords": [ + "debug", + "debugbar" + ], + "time": "2015-12-10 09:50:24" + }, + { + "name": "mockery/mockery", + "version": "0.9.4", + "source": { + "type": "git", + "url": "https://github.com/padraic/mockery.git", + "reference": "70bba85e4aabc9449626651f48b9018ede04f86b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/padraic/mockery/zipball/70bba85e4aabc9449626651f48b9018ede04f86b", + "reference": "70bba85e4aabc9449626651f48b9018ede04f86b", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "~1.1", + "lib-pcre": ">=7.0", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.9.x-dev" + } + }, + "autoload": { + "psr-0": { + "Mockery": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "http://blog.astrumfutura.com" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "http://davedevelopment.co.uk" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", + "homepage": "http://github.com/padraic/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "time": "2015-04-02 19:54:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03 12:10:50" + }, + { + "name": "phpspec/prophecy", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7", + "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "phpdocumentor/reflection-docblock": "~2.0", + "sebastian/comparator": "~1.1" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2015-08-13 10:07:40" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-10-06 15:47:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-06-21 13:08:43" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b", + "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2015-06-21 08:01:12" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-09-15 10:49:45" + }, + { + "name": "phpunit/phpunit", + "version": "4.8.21", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "ea76b17bced0500a28098626b84eda12dbcf119c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea76b17bced0500a28098626b84eda12dbcf119c", + "reference": "ea76b17bced0500a28098626b84eda12dbcf119c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": ">=1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.3", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.8.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2015-12-12 07:45:58" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-10-02 06:51:40" + }, + { + "name": "sebastian/comparator", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-07-26 15:48:44" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-12-08 07:14:41" + }, + { + "name": "sebastian/environment", + "version": "1.3.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "6e7133793a8e5a5714a551a8324337374be209df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e7133793a8e5a5714a551a8324337374be209df", + "reference": "6e7133793a8e5a5714a551a8324337374be209df", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2015-12-02 08:37:27" + }, + { + "name": "sebastian/exporter", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "7ae5513327cb536431847bcc0c10edba2701064e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e", + "reference": "7ae5513327cb536431847bcc0c10edba2701064e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2015-06-21 07:55:53" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12 03:26:01" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-11-11 19:50:13" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21 13:59:46" + }, + { + "name": "symfony/class-loader", + "version": "v2.8.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/class-loader.git", + "reference": "98e9089a428ed0e39423b67352c57ef5910a3269" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/class-loader/zipball/98e9089a428ed0e39423b67352c57ef5910a3269", + "reference": "98e9089a428ed0e39423b67352c57ef5910a3269", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/finder": "~2.0,>=2.0.5|~3.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ClassLoader\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ClassLoader Component", + "homepage": "https://symfony.com", + "time": "2016-01-03 15:33:41" + }, + { + "name": "symfony/css-selector", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "4613311fd46e146f506403ce2f8a0c71d402d2a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/4613311fd46e146f506403ce2f8a0c71d402d2a3", + "reference": "4613311fd46e146f506403ce2f8a0c71d402d2a3", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2015-12-05 17:45:07" + }, + { + "name": "symfony/dom-crawler", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d", + "reference": "7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "~2.8|~3.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "https://symfony.com", + "time": "2015-12-26 13:42:31" + }, + { + "name": "symfony/yaml", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "3df409958a646dad2bc5046c3fb671ee24a1a691" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/3df409958a646dad2bc5046c3fb671ee24a1a691", + "reference": "3df409958a646dad2bc5046c3fb671ee24a1a691", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2015-12-26 13:39:53" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": { @@ -2749,8 +4116,6 @@ }, "prefer-stable": false, "prefer-lowest": false, - "platform": { - "php": ">=5.6.4" - }, + "platform": [], "platform-dev": [] } diff --git a/config/app.php b/config/app.php old mode 100644 new mode 100755 index ced4a3e0b6..aa8b880314 --- a/config/app.php +++ b/config/app.php @@ -2,6 +2,19 @@ return [ + /* + |-------------------------------------------------------------------------- + | Application Environment + |-------------------------------------------------------------------------- + | + | This value determines the "environment" your application is currently + | running in. This may determine how you prefer to configure various + | services your application utilizes. Set this in your ".env" file. + | + */ + + 'env' => env('APP_ENV', 'production'), + /* |-------------------------------------------------------------------------- | Application Debug Mode @@ -13,7 +26,7 @@ return [ | */ - 'debug' => env('APP_DEBUG'), + 'debug' => env('APP_DEBUG', false), /* |-------------------------------------------------------------------------- @@ -26,7 +39,7 @@ return [ | */ - 'url' => 'http://localhost', + 'url' => 'http://localhost', /* |-------------------------------------------------------------------------- @@ -39,7 +52,7 @@ return [ | */ - 'timezone' => 'UTC', + 'timezone' => 'UTC', /* |-------------------------------------------------------------------------- @@ -52,7 +65,7 @@ return [ | */ - 'locale' => 'en_US', + 'locale' => 'en_US', /* |-------------------------------------------------------------------------- @@ -78,9 +91,9 @@ return [ | */ - 'key' => env('APP_KEY', 'SomeRandomString'), + 'key' => env('APP_KEY'), - 'cipher' => MCRYPT_RIJNDAEL_128, + 'cipher' => 'AES-256-CBC', /* |-------------------------------------------------------------------------- @@ -95,7 +108,7 @@ return [ | */ - 'log' => 'daily', + 'log' => env('APP_LOG', 'daily'), /* |-------------------------------------------------------------------------- @@ -108,52 +121,48 @@ return [ | */ - 'providers' => [ + 'providers' => [ /* * Laravel Framework Service Providers... */ - 'Illuminate\Foundation\Providers\ArtisanServiceProvider', - 'Illuminate\Auth\AuthServiceProvider', - //'Illuminate\Bus\BusServiceProvider', - 'Illuminate\Cache\CacheServiceProvider', - 'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider', - 'Illuminate\Routing\ControllerServiceProvider', - 'Illuminate\Cookie\CookieServiceProvider', - 'Illuminate\Database\DatabaseServiceProvider', - 'Illuminate\Encryption\EncryptionServiceProvider', - 'Illuminate\Filesystem\FilesystemServiceProvider', - 'Illuminate\Foundation\Providers\FoundationServiceProvider', - 'Illuminate\Hashing\HashServiceProvider', - 'Illuminate\Mail\MailServiceProvider', - 'Illuminate\Pagination\PaginationServiceProvider', - 'Illuminate\Pipeline\PipelineServiceProvider', - 'Illuminate\Queue\QueueServiceProvider', - 'Illuminate\Redis\RedisServiceProvider', - 'Illuminate\Auth\Passwords\PasswordResetServiceProvider', - 'Illuminate\Session\SessionServiceProvider', - 'Illuminate\Translation\TranslationServiceProvider', - 'Illuminate\Validation\ValidationServiceProvider', - 'Illuminate\View\ViewServiceProvider', - 'Illuminate\Html\HtmlServiceProvider', - 'TwigBridge\ServiceProvider', + Illuminate\Auth\AuthServiceProvider::class, + Illuminate\Broadcasting\BroadcastServiceProvider::class, + Illuminate\Bus\BusServiceProvider::class, + Illuminate\Cache\CacheServiceProvider::class, + Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, + Illuminate\Cookie\CookieServiceProvider::class, + Illuminate\Database\DatabaseServiceProvider::class, + Illuminate\Encryption\EncryptionServiceProvider::class, + Illuminate\Filesystem\FilesystemServiceProvider::class, + Illuminate\Foundation\Providers\FoundationServiceProvider::class, + Illuminate\Hashing\HashServiceProvider::class, + Illuminate\Mail\MailServiceProvider::class, + Illuminate\Pagination\PaginationServiceProvider::class, + Illuminate\Pipeline\PipelineServiceProvider::class, + Illuminate\Queue\QueueServiceProvider::class, + Illuminate\Redis\RedisServiceProvider::class, + Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, + Illuminate\Session\SessionServiceProvider::class, + Illuminate\Translation\TranslationServiceProvider::class, + Illuminate\Validation\ValidationServiceProvider::class, + Illuminate\View\ViewServiceProvider::class, + Collective\Html\HtmlServiceProvider::class, - 'DaveJamesMiller\Breadcrumbs\ServiceProvider', -// 'Barryvdh\Debugbar\ServiceProvider', -// 'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider', - 'Zizaco\Entrust\EntrustServiceProvider', /* * Application Service Providers... */ - 'FireflyIII\Providers\AppServiceProvider', - 'FireflyIII\Providers\BusServiceProvider', - 'FireflyIII\Providers\ConfigServiceProvider', - 'FireflyIII\Providers\EventServiceProvider', - 'FireflyIII\Providers\RouteServiceProvider', - 'FireflyIII\Providers\FireflyServiceProvider', - 'FireflyIII\Providers\TestingServiceProvider', + FireflyIII\Providers\AppServiceProvider::class, + FireflyIII\Providers\AuthServiceProvider::class, + FireflyIII\Providers\EventServiceProvider::class, + FireflyIII\Providers\RouteServiceProvider::class, + FireflyIII\Providers\FireflyServiceProvider::class, + // own stuff: +// Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, + 'DaveJamesMiller\Breadcrumbs\ServiceProvider', + 'TwigBridge\ServiceProvider', ], @@ -168,50 +177,50 @@ return [ | */ - 'aliases' => [ + 'aliases' => [ - 'App' => 'Illuminate\Support\Facades\App', - 'Artisan' => 'Illuminate\Support\Facades\Artisan', - 'Auth' => 'Illuminate\Support\Facades\Auth', - 'Blade' => 'Illuminate\Support\Facades\Blade', - 'Bus' => 'Illuminate\Support\Facades\Bus', - 'Cache' => 'Illuminate\Support\Facades\Cache', - 'Config' => 'Illuminate\Support\Facades\Config', - 'Cookie' => 'Illuminate\Support\Facades\Cookie', - 'Crypt' => 'Illuminate\Support\Facades\Crypt', - 'DB' => 'Illuminate\Support\Facades\DB', - 'Eloquent' => 'Illuminate\Database\Eloquent\Model', - 'Event' => 'Illuminate\Support\Facades\Event', - 'File' => 'Illuminate\Support\Facades\File', - 'Hash' => 'Illuminate\Support\Facades\Hash', - 'Input' => 'Illuminate\Support\Facades\Input', - 'Inspiring' => 'Illuminate\Foundation\Inspiring', - 'Lang' => 'Illuminate\Support\Facades\Lang', - 'Log' => 'Illuminate\Support\Facades\Log', - 'Mail' => 'Illuminate\Support\Facades\Mail', - 'Password' => 'Illuminate\Support\Facades\Password', - 'Queue' => 'Illuminate\Support\Facades\Queue', - 'Redirect' => 'Illuminate\Support\Facades\Redirect', - 'Redis' => 'Illuminate\Support\Facades\Redis', - 'Request' => 'Illuminate\Support\Facades\Request', - 'Response' => 'Illuminate\Support\Facades\Response', - 'Route' => 'Illuminate\Support\Facades\Route', - 'Schema' => 'Illuminate\Support\Facades\Schema', - 'Session' => 'Illuminate\Support\Facades\Session', - 'Storage' => 'Illuminate\Support\Facades\Storage', - 'URL' => 'Illuminate\Support\Facades\URL', - 'Validator' => 'Illuminate\Support\Facades\Validator', - 'View' => 'Illuminate\Support\Facades\View', - 'Form' => 'Illuminate\Html\FormFacade', - 'Html' => 'Illuminate\Html\HtmlFacade', + 'App' => Illuminate\Support\Facades\App::class, + 'Artisan' => Illuminate\Support\Facades\Artisan::class, + 'Auth' => Illuminate\Support\Facades\Auth::class, + 'Blade' => Illuminate\Support\Facades\Blade::class, + 'Cache' => Illuminate\Support\Facades\Cache::class, + 'Config' => Illuminate\Support\Facades\Config::class, + 'Cookie' => Illuminate\Support\Facades\Cookie::class, + 'Crypt' => Illuminate\Support\Facades\Crypt::class, + 'DB' => Illuminate\Support\Facades\DB::class, + 'Eloquent' => Illuminate\Database\Eloquent\Model::class, + 'Event' => Illuminate\Support\Facades\Event::class, + 'File' => Illuminate\Support\Facades\File::class, + 'Gate' => Illuminate\Support\Facades\Gate::class, + 'Hash' => Illuminate\Support\Facades\Hash::class, + + 'Lang' => Illuminate\Support\Facades\Lang::class, + 'Log' => Illuminate\Support\Facades\Log::class, + 'Mail' => Illuminate\Support\Facades\Mail::class, + 'Password' => Illuminate\Support\Facades\Password::class, + 'Queue' => Illuminate\Support\Facades\Queue::class, + 'Redirect' => Illuminate\Support\Facades\Redirect::class, + 'Redis' => Illuminate\Support\Facades\Redis::class, + 'Request' => Illuminate\Support\Facades\Request::class, + 'Response' => Illuminate\Support\Facades\Response::class, + 'Route' => Illuminate\Support\Facades\Route::class, + 'Schema' => Illuminate\Support\Facades\Schema::class, + 'Session' => Illuminate\Support\Facades\Session::class, + 'Storage' => Illuminate\Support\Facades\Storage::class, + 'URL' => Illuminate\Support\Facades\URL::class, + 'Validator' => Illuminate\Support\Facades\Validator::class, + 'View' => Illuminate\Support\Facades\View::class, + 'Twig' => 'TwigBridge\Facade\Twig', + 'Form' => Collective\Html\FormFacade::class, + 'Html' => Collective\Html\HtmlFacade::class, 'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade', 'Preferences' => 'FireflyIII\Support\Facades\Preferences', 'Navigation' => 'FireflyIII\Support\Facades\Navigation', 'Amount' => 'FireflyIII\Support\Facades\Amount', 'Steam' => 'FireflyIII\Support\Facades\Steam', 'ExpandedForm' => 'FireflyIII\Support\Facades\ExpandedForm', - 'Twig' => 'TwigBridge\Facade\Twig', - 'Entrust' => 'Zizaco\Entrust\EntrustFacade' + 'Entrust' => 'Zizaco\Entrust\EntrustFacade', + 'Input' => 'Illuminate\Support\Facades\Input', ], diff --git a/config/auth.php b/config/auth.php old mode 100644 new mode 100755 index 685437114c..e0ad255263 --- a/config/auth.php +++ b/config/auth.php @@ -2,67 +2,42 @@ return [ - /* - |-------------------------------------------------------------------------- - | Default Authentication Driver - |-------------------------------------------------------------------------- - | - | This option controls the authentication driver that will be utilized. - | This driver manages the retrieval and authentication of the users - | attempting to get access to protected areas of your application. - | - | Supported: "database", "eloquent" - | - */ - - 'driver' => 'eloquent', - - /* - |-------------------------------------------------------------------------- - | Authentication Model - |-------------------------------------------------------------------------- - | - | When using the "Eloquent" authentication driver, we need to know which - | Eloquent model should be used to retrieve your users. Of course, it - | is often just the "User" model but you may use whatever you like. - | - */ - - 'model' => 'FireflyIII\User', - - /* - |-------------------------------------------------------------------------- - | Authentication Table - |-------------------------------------------------------------------------- - | - | When using the "Database" authentication driver, we need to know which - | table should be used to retrieve your users. We have chosen a basic - | default value but you may easily change it to any table you like. - | - */ - - 'table' => 'users', - - /* - |-------------------------------------------------------------------------- - | Password Reset Settings - |-------------------------------------------------------------------------- - | - | Here you may set the options for resetting passwords including the view - | that is your password reset e-mail. You can also set the name of the - | table that maintains all of the reset tokens for your application. - | - | The expire time is the number of minutes that the reset token should be - | considered valid. This security feature keeps tokens short-lived so - | they have less time to be guessed. You may change this as needed. - | - */ - - 'password' => [ - 'email' => 'emails.password', - 'table' => 'password_resets', - 'expire' => 60, + 'allow_register' => true, + 'defaults' => [ + 'guard' => 'web', + 'passwords' => 'users', + ], + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + + 'api' => [ + 'driver' => 'token', + 'provider' => 'users', + ], + ], + + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => FireflyIII\User::class, + ], + + // 'users' => [ + // 'driver' => 'database', + // 'table' => 'users', + // ], + ], + + 'passwords' => [ + 'users' => [ + 'provider' => 'users', + 'email' => 'emails.password', + 'table' => 'password_resets', + 'expire' => 60, + ], ], - 'allow_register' => true ]; diff --git a/config/breadcrumbs.php b/config/breadcrumbs.php deleted file mode 100644 index aa133d355c..0000000000 --- a/config/breadcrumbs.php +++ /dev/null @@ -1,7 +0,0 @@ - 'breadcrumbs::bootstrap3', - -]; diff --git a/config/broadcasting.php b/config/broadcasting.php new file mode 100755 index 0000000000..abaaac32a7 --- /dev/null +++ b/config/broadcasting.php @@ -0,0 +1,52 @@ + env('BROADCAST_DRIVER', 'pusher'), + + /* + |-------------------------------------------------------------------------- + | Broadcast Connections + |-------------------------------------------------------------------------- + | + | Here you may define all of the broadcast connections that will be used + | to broadcast events to other systems or over websockets. Samples of + | each available type of connection are provided inside this array. + | + */ + + 'connections' => [ + + 'pusher' => [ + 'driver' => 'pusher', + 'key' => env('PUSHER_KEY'), + 'secret' => env('PUSHER_SECRET'), + 'app_id' => env('PUSHER_APP_ID'), + 'options' => [ + // + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + ], + + 'log' => [ + 'driver' => 'log', + ], + + ], + +]; diff --git a/config/cache.php b/config/cache.php old mode 100644 new mode 100755 index 0a2d218517..379135b0eb --- a/config/cache.php +++ b/config/cache.php @@ -26,38 +26,38 @@ return [ | */ - 'stores' => [ + 'stores' => [ - 'apc' => [ - 'driver' => 'apc' + 'apc' => [ + 'driver' => 'apc', ], - 'array' => [ - 'driver' => 'array' + 'array' => [ + 'driver' => 'array', ], - 'database' => [ - 'driver' => 'database', - 'table' => 'cache', + 'database' => [ + 'driver' => 'database', + 'table' => 'cache', 'connection' => null, ], - 'file' => [ + 'file' => [ 'driver' => 'file', - 'path' => storage_path() . '/framework/cache', + 'path' => storage_path('framework/cache'), ], 'memcached' => [ 'driver' => 'memcached', 'servers' => [ [ - 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 100 + 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 100, ], ], ], - 'redis' => [ - 'driver' => 'redis', + 'redis' => [ + 'driver' => 'redis', 'connection' => 'default', ], @@ -74,6 +74,6 @@ return [ | */ - 'prefix' => 'laravel', + 'prefix' => 'laravel', ]; diff --git a/config/compile.php b/config/compile.php old mode 100644 new mode 100755 index 317efeb092..04807eac45 --- a/config/compile.php +++ b/config/compile.php @@ -13,14 +13,8 @@ return [ | */ - 'files' => [ - - realpath(__DIR__ . '/../app/Providers/AppServiceProvider.php'), - realpath(__DIR__ . '/../app/Providers/BusServiceProvider.php'), - realpath(__DIR__ . '/../app/Providers/ConfigServiceProvider.php'), - realpath(__DIR__ . '/../app/Providers/EventServiceProvider.php'), - realpath(__DIR__ . '/../app/Providers/RouteServiceProvider.php'), - + 'files' => [ + // ], /* diff --git a/config/csv.php b/config/csv.php index ba1ae72f47..dfdcc3d26f 100644 --- a/config/csv.php +++ b/config/csv.php @@ -2,6 +2,7 @@ return [ 'specifix' => [ 'RabobankDescription', + 'AbnAmroDescription', 'Dummy' ], 'post_processors' => [ @@ -176,6 +177,12 @@ return [ 'converter' => 'Amount', 'field' => 'amount', ], + 'amount-comma-separated' => [ + 'name' => 'Amount (comma as decimal separator)', + 'mappable' => false, + 'converter' => 'AmountComma', + 'field' => 'amount', + ], 'sepa-ct-id' => [ 'name' => 'SEPA Credit Transfer end-to-end ID', 'mappable' => false, diff --git a/config/database.php b/config/database.php old mode 100644 new mode 100755 index f1a98b129b..9467c969e6 --- a/config/database.php +++ b/config/database.php @@ -13,7 +13,7 @@ return [ | */ - 'fetch' => PDO::FETCH_CLASS, + 'fetch' => PDO::FETCH_CLASS, /* |-------------------------------------------------------------------------- @@ -26,8 +26,7 @@ return [ | */ - 'default' => env('DB_CONNECTION', 'mysql'), - + 'default' => env('DB_CONNECTION', 'mysql'), /* |-------------------------------------------------------------------------- @@ -49,11 +48,11 @@ return [ 'sqlite' => [ 'driver' => 'sqlite', - 'database' => storage_path('database/testing.db'), + 'database' => storage_path('database') . '/testing.db', 'prefix' => '', ], - 'mysql' => [ + 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', 'localhost'), 'database' => env('DB_DATABASE', 'forge'), @@ -65,7 +64,7 @@ return [ 'strict' => false, ], - 'pgsql' => [ + 'pgsql' => [ 'driver' => 'pgsql', 'host' => env('DB_HOST', 'localhost'), 'database' => env('DB_DATABASE', 'forge'), @@ -82,6 +81,7 @@ return [ 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8', 'prefix' => '', ], @@ -98,7 +98,7 @@ return [ | */ - 'migrations' => 'migrations', + 'migrations' => 'migrations', /* |-------------------------------------------------------------------------- @@ -111,13 +111,14 @@ return [ | */ - 'redis' => [ + 'redis' => [ 'cluster' => false, 'default' => [ - 'host' => '127.0.0.1', - 'port' => 6379, + 'host' => env('REDIS_HOST', 'localhost'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', 6379), 'database' => 0, ], diff --git a/config/filesystems.php b/config/filesystems.php old mode 100644 new mode 100755 index 9765bd1016..3fffcf0a2f --- a/config/filesystems.php +++ b/config/filesystems.php @@ -11,7 +11,7 @@ return [ | by the framework. A "local" driver, as well as a variety of cloud | based drivers are available for your choosing. Just store away! | - | Supported: "local", "s3", "rackspace" + | Supported: "local", "ftp", "s3", "rackspace" | */ @@ -28,7 +28,7 @@ return [ | */ - 'cloud' => 's3', + 'cloud' => 's3', /* |-------------------------------------------------------------------------- @@ -41,14 +41,28 @@ return [ | */ - 'disks' => [ + 'disks' => [ - 'local' => [ + 'local' => [ 'driver' => 'local', - 'root' => storage_path() . '/app', + 'root' => storage_path('app'), ], - 's3' => [ + 'ftp' => [ + 'driver' => 'ftp', + 'host' => 'ftp.example.com', + 'username' => 'your-username', + 'password' => 'your-password', + + // Optional FTP Settings... + // 'port' => 21, + // 'root' => '', + // 'passive' => true, + // 'ssl' => true, + // 'timeout' => 30, + ], + + 's3' => [ 'driver' => 's3', 'key' => 'your-key', 'secret' => 'your-secret', @@ -63,6 +77,7 @@ return [ 'container' => 'your-container', 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', 'region' => 'IAD', + 'url_type' => 'publicURL', ], ], diff --git a/config/firefly.php b/config/firefly.php index 3659db04e6..f37b62ce98 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -2,7 +2,7 @@ return [ 'chart' => 'chartjs', - 'version' => '3.6.1', + 'version' => '3.7.0', 'index_periods' => ['1D', '1W', '1M', '3M', '6M', '1Y', 'custom'], 'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'], 'csv_import_enabled' => true, @@ -98,7 +98,7 @@ return [ 'Revenue account' => 'revenue', 'Cash account' => 'cash', ], - 'languages' => [ + 'languages' => [ 'en_US' => ['name_locale' => 'English', 'name_english' => 'English', 'complete' => true], 'nl_NL' => ['name_locale' => 'Nederlands', 'name_english' => 'Dutch', 'complete' => true], 'pt_BR' => ['name_locale' => 'Português do Brasil', 'name_english' => 'Portugese (Brazil)', 'complete' => false], @@ -146,5 +146,70 @@ return [ 'fr_FR' => '%B %e, %Y', 'pt_BR' => '%B %e, %Y', ], + 'bindables' => [ + // models + 'account' => 'FireflyIII\Models\Account', + 'attachment' => 'FireflyIII\Models\Attachment', + 'bill' => 'FireflyIII\Models\Bill', + 'budget' => 'FireflyIII\Models\Budget', + 'category' => 'FireflyIII\Models\Category', + 'currency' => 'FireflyIII\Models\TransactionCurrency', + 'limitrepetition' => 'FireflyIII\Models\LimitRepetition', + 'piggyBank' => 'FireflyIII\Models\PiggyBank', + 'tj' => 'FireflyIII\Models\TransactionJournal', + 'tag' => 'FireflyIII\Models\Tag', + 'rule' => 'FireflyIII\Models\Rule', + 'ruleGroup' => 'FireflyIII\Models\RuleGroup', + // lists + 'accountList' => 'FireflyIII\Support\Binder\AccountList', + 'budgetList' => 'FireflyIII\Support\Binder\BudgetList', + 'categoryList' => 'FireflyIII\Support\Binder\CategoryList', + + // others + 'start_date' => 'FireflyIII\Support\Binder\Date', + 'end_date' => 'FireflyIII\Support\Binder\Date' + ], + + 'rule-triggers' => [ + 'user_action' => 'FireflyIII\Rules\Triggers\UserAction', + 'from_account_starts' => 'FireflyIII\Rules\Triggers\FromAccountStarts', + 'from_account_ends' => 'FireflyIII\Rules\Triggers\FromAccountEnds', + 'from_account_is' => 'FireflyIII\Rules\Triggers\FromAccountIs', + 'from_account_contains' => 'FireflyIII\Rules\Triggers\FromAccountContains', + 'to_account_starts' => 'FireflyIII\Rules\Triggers\ToAccountStarts', + 'to_account_ends' => 'FireflyIII\Rules\Triggers\ToAccountEnds', + 'to_account_is' => 'FireflyIII\Rules\Triggers\ToAccountIs', + 'to_account_contains' => 'FireflyIII\Rules\Triggers\ToAccountContains', + 'transaction_type' => 'FireflyIII\Rules\Triggers\TransactionType', + 'amount_less' => 'FireflyIII\Rules\Triggers\AmountLess', + 'amount_exactly' => 'FireflyIII\Rules\Triggers\AmountExactly', + 'amount_more' => 'FireflyIII\Rules\Triggers\AmountMore', + 'description_starts' => 'FireflyIII\Rules\Triggers\DescriptionStarts', + 'description_ends' => 'FireflyIII\Rules\Triggers\DescriptionEnds', + 'description_contains' => 'FireflyIII\Rules\Triggers\DescriptionContains', + 'description_is' => 'FireflyIII\Rules\Triggers\DescriptionIs', + ], + 'rule-actions' => [ + 'set_category' => 'FireflyIII\Rules\Actions\SetCategory', + 'clear_category' => 'FireflyIII\Rules\Actions\ClearCategory', + 'set_budget' => 'FireflyIII\Rules\Actions\SetBudget', + 'clear_budget' => 'FireflyIII\Rules\Actions\ClearBudget', + 'add_tag' => 'FireflyIII\Rules\Actions\AddTag', + 'remove_tag' => 'FireflyIII\Rules\Actions\RemoveTag', + 'remove_all_tags' => 'FireflyIII\Rules\Actions\RemoveAllTags', + 'set_description' => 'FireflyIII\Rules\Actions\SetDescription', + 'append_description' => 'FireflyIII\Rules\Actions\AppendDescription', + 'prepend_description' => 'FireflyIII\Rules\Actions\PrependDescription', + ], + // all rule actions that require text input: + 'rule-actions-text' => [ + 'set_category', + 'set_budget', + 'add_tag', + 'remove_tag', + 'set_description', + 'append_description', + 'prepend_description', + ] ]; diff --git a/config/mail.php b/config/mail.php old mode 100644 new mode 100755 index a89c2eaad6..0fc18bc022 --- a/config/mail.php +++ b/config/mail.php @@ -11,12 +11,11 @@ return [ | sending of e-mail. You may specify which one you're using throughout | your application here. By default, Laravel is setup for SMTP mail. | - | Supported: "smtp", "mail", "sendmail", "mailgun", "mandrill", "log" + | Supported: "smtp", "mail", "sendmail", "mailgun", "mandrill", "ses", "log" | */ - 'blocked_domains' => explode(',', env('BLOCKED_DOMAINS')), - 'driver' => env('EMAIL_DRIVER', 'smtp'), + 'driver' => env('MAIL_DRIVER', 'smtp'), /* |-------------------------------------------------------------------------- @@ -29,7 +28,7 @@ return [ | */ - 'host' => env('EMAIL_SMTP', 'smtp.mailgun.org'), + 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), /* |-------------------------------------------------------------------------- @@ -42,7 +41,7 @@ return [ | */ - 'port' => 587, + 'port' => env('MAIL_PORT', 587), /* |-------------------------------------------------------------------------- @@ -55,7 +54,7 @@ return [ | */ - 'from' => ['address' => env('EMAIL_USERNAME', null), 'name' => 'Firefly III Mailer'], + 'from' => ['address' => env('MAIL_FROM', null), 'name' => 'Firefly III Mailer'], /* |-------------------------------------------------------------------------- @@ -68,7 +67,7 @@ return [ | */ - 'encryption' => 'tls', + 'encryption' => env('MAIL_ENCRYPTION', 'tls'), /* |-------------------------------------------------------------------------- @@ -81,7 +80,7 @@ return [ | */ - 'username' => env('EMAIL_USERNAME', null), + 'username' => env('MAIL_USERNAME'), /* |-------------------------------------------------------------------------- @@ -94,7 +93,7 @@ return [ | */ - 'password' => env('EMAIL_PASSWORD', null), + 'password' => env('MAIL_PASSWORD'), /* |-------------------------------------------------------------------------- @@ -109,17 +108,4 @@ return [ 'sendmail' => '/usr/sbin/sendmail -bs', - /* - |-------------------------------------------------------------------------- - | Mail "Pretend" - |-------------------------------------------------------------------------- - | - | When this option is enabled, e-mail will not actually be sent over the - | web and will instead be written to your application's logs files so - | you may inspect the message. This is great for local development. - | - */ - - 'pretend' => env('EMAIL_PRETEND', false), - ]; diff --git a/config/queue.php b/config/queue.php old mode 100644 new mode 100755 index 5be8d63bf3..6c2b7d2e17 --- a/config/queue.php +++ b/config/queue.php @@ -12,11 +12,11 @@ return [ | syntax for each one. Here you may set the default queue driver. | | Supported: "null", "sync", "database", "beanstalkd", - | "sqs", "iron", "redis" + | "sqs", "redis" | */ - 'default' => env('QUEUE_DRIVER', 'sync'), + 'default' => env('QUEUE_DRIVER', 'sync'), /* |-------------------------------------------------------------------------- @@ -31,11 +31,11 @@ return [ 'connections' => [ - 'sync' => [ + 'sync' => [ 'driver' => 'sync', ], - 'database' => [ + 'database' => [ 'driver' => 'database', 'table' => 'jobs', 'queue' => 'default', @@ -49,27 +49,20 @@ return [ 'ttr' => 60, ], - 'sqs' => [ + 'sqs' => [ 'driver' => 'sqs', 'key' => 'your-public-key', 'secret' => 'your-secret-key', - 'queue' => 'your-queue-url', + 'prefix' => 'https://sqs.us-east-1.amazonaws.com/your-account-id', + 'queue' => 'your-queue-name', 'region' => 'us-east-1', ], - 'iron' => [ - 'driver' => 'iron', - 'host' => 'mq-aws-us-east-1.iron.io', - 'token' => 'your-token', - 'project' => 'your-project-id', - 'queue' => 'your-queue-name', - 'encrypt' => true, - ], - - 'redis' => [ - 'driver' => 'redis', - 'queue' => 'default', - 'expire' => 60, + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + 'queue' => 'default', + 'expire' => 60, ], ], @@ -85,8 +78,9 @@ return [ | */ - 'failed' => [ - 'database' => 'mysql', 'table' => 'failed_jobs', + 'failed' => [ + 'database' => env('DB_CONNECTION', 'mysql'), + 'table' => 'failed_jobs', ], ]; diff --git a/config/services.php b/config/services.php old mode 100644 new mode 100755 index 3ee3eed75e..9fbb81549e --- a/config/services.php +++ b/config/services.php @@ -14,24 +14,25 @@ return [ | */ - 'mailgun' => [ - 'domain' => '', - 'secret' => '', + 'mailgun' => [ + 'domain' => env('MAILGUN_DOMAIN'), + 'secret' => env('MAILGUN_SECRET'), ], 'mandrill' => [ - 'secret' => '', + 'secret' => env('MANDRILL_SECRET'), ], - 'ses' => [ - 'key' => '', - 'secret' => '', + 'ses' => [ + 'key' => env('SES_KEY'), + 'secret' => env('SES_SECRET'), 'region' => 'us-east-1', ], - 'stripe' => [ - 'model' => 'User', - 'secret' => '', + 'stripe' => [ + 'model' => FireflyIII\User::class, + 'key' => env('STRIPE_KEY'), + 'secret' => env('STRIPE_SECRET'), ], ]; diff --git a/config/session.php b/config/session.php old mode 100644 new mode 100755 index 17aed45faf..e90989cd8a --- a/config/session.php +++ b/config/session.php @@ -2,6 +2,22 @@ return [ + /* + |-------------------------------------------------------------------------- + | Default Session Driver + |-------------------------------------------------------------------------- + | + | This option controls the default session "driver" that will be used on + | requests. By default, we will use the lightweight native driver but + | you may specify any of the other wonderful drivers provided here. + | + | Supported: "file", "cookie", "database", "apc", + | "memcached", "redis", "array" + | + */ + + 'driver' => env('SESSION_DRIVER', 'file'), + /* |-------------------------------------------------------------------------- | Session Lifetime @@ -13,10 +29,22 @@ return [ | */ - 'lifetime' => 120, + 'lifetime' => 120, 'expire_on_close' => false, + /* + |-------------------------------------------------------------------------- + | Session Encryption + |-------------------------------------------------------------------------- + | + | This option allows you to easily specify that all of your session data + | should be encrypted before it is stored. All encryption will be run + | automatically by Laravel and you can use the Session like normal. + | + */ + + 'encrypt' => true, /* |-------------------------------------------------------------------------- @@ -29,8 +57,20 @@ return [ | */ - 'files' => storage_path() . '/framework/sessions', + 'files' => storage_path('framework/sessions'), + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => null, /* |-------------------------------------------------------------------------- @@ -43,7 +83,7 @@ return [ | */ - 'table' => 'sessions', + 'table' => 'sessions', /* |-------------------------------------------------------------------------- @@ -56,15 +96,20 @@ return [ | */ - 'lottery' => [2, 100], + 'lottery' => [2, 100], - 'driver' => env('SESSION_DRIVER', 'database'), - 'cookie' => 'firefly_session', + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the cookie used to identify a session + | instance by ID. The name specified here will get used every time a + | new session cookie is created by the framework for every driver. + | + */ - 'connection' => env('DB_CONNECTION', 'mysql'), - - - 'encrypt' => true, + 'cookie' => 'firefly_session', /* |-------------------------------------------------------------------------- @@ -77,7 +122,7 @@ return [ | */ - 'path' => '/', + 'path' => '/', /* |-------------------------------------------------------------------------- @@ -90,7 +135,7 @@ return [ | */ - 'domain' => null, + 'domain' => null, /* |-------------------------------------------------------------------------- @@ -103,6 +148,6 @@ return [ | */ - 'secure' => false, + 'secure' => false, ]; diff --git a/config/upgrade.php b/config/upgrade.php new file mode 100644 index 0000000000..be8b331d37 --- /dev/null +++ b/config/upgrade.php @@ -0,0 +1,15 @@ + [ + '3.7.0' => 'Because of the upgrade to Laravel 5.2, several manual changes must be made to your Firefly III installation. ' . + 'Please follow the instructions on the following page: https://github.com/JC5/firefly-iii/wiki/Upgrade-to-3.7.0'], +]; \ No newline at end of file diff --git a/config/view.php b/config/view.php old mode 100644 new mode 100755 index 3ea032617f..e193ab61d9 --- a/config/view.php +++ b/config/view.php @@ -13,8 +13,8 @@ return [ | */ - 'paths' => [ - realpath(base_path('resources/twig')) + 'paths' => [ + realpath(base_path('resources/views')), ], /* @@ -28,6 +28,6 @@ return [ | */ - 'compiled' => realpath(storage_path() . '/framework/views'), + 'compiled' => realpath(storage_path('framework/views')), ]; diff --git a/cover.sh b/cover.sh new file mode 100755 index 0000000000..3f7cd1b6bf --- /dev/null +++ b/cover.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# set testing environment +cp .env.testing .env + +# set cover: +cp phpunit.cover.xml phpunit.xml + +# delete test databases: +if [ -f storage/database/testing.db ] +then + rm storage/database/testing.db +fi + +if [ -f storage/database/testing-copy.db ] +then + rm storage/database/testing-copy.db +fi + +# test! +if [ -z "$1" ] +then + echo "Running all tests..." + phpunit --verbose +fi + +# test selective.. +dirs=("acceptance/Controllers" "acceptance/Controllers/Auth" "acceptance/Controllers/Chart" "unit") +# +if [ ! -z "$1" ] +then + for i in "${dirs[@]}" + do + firstFile="./tests/$i/$1.php" + secondFile="./tests/$i/$1Test.php" + if [ -f "$firstFile" ] + then + # run it! + echo "Now running $firstFile" + phpunit --verbose $firstFile + result=$? + fi + if [ -f "$secondFile" ] + then + # run it! + echo "Now running $secondFile" + phpunit --verbose $secondFile + result=$? + fi + + + done +fi + +# restore .env file +cp .env.local .env + +# restore cover +cp phpunit.default.xml phpunit.xml + +exit ${result} \ No newline at end of file diff --git a/database/.gitignore b/database/.gitignore old mode 100644 new mode 100755 index 8b13789179..9b1dffd90f --- a/database/.gitignore +++ b/database/.gitignore @@ -1 +1 @@ - +*.sqlite diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php new file mode 100755 index 0000000000..5141a751d0 --- /dev/null +++ b/database/factories/ModelFactory.php @@ -0,0 +1,21 @@ +define( + FireflyIII\User::class, function (Faker\Generator $faker) { + return [ + 'name' => $faker->name, + 'email' => $faker->email, + 'password' => bcrypt(str_random(10)), + 'remember_token' => str_random(10), + ]; +} +); + +$factory->define( + FireflyIII\Models\TransactionType::class, function (Faker\Generator $faker) { + return [ + 'type' => $faker->name, + ]; +} +); + diff --git a/database/migrations/.gitkeep b/database/migrations/.gitkeep old mode 100644 new mode 100755 diff --git a/database/migrations/2014_12_13_190730_changes_for_v321.php b/database/migrations/2014_12_13_190730_changes_for_v321.php index a893f8c0a7..a10d7785ae 100644 --- a/database/migrations/2014_12_13_190730_changes_for_v321.php +++ b/database/migrations/2014_12_13_190730_changes_for_v321.php @@ -10,7 +10,8 @@ use Illuminate\Support\Facades\Schema; /** * @SuppressWarnings(PHPMD.ShortMethodName) // method names are mandated by laravel. - * @SuppressWarnings("TooManyMethods") // I'm fine with this + * @SuppressWarnings(PHPMD.TooManyMethods) + * * * Down: * 1. Create new Components based on Budgets. diff --git a/database/migrations/2015_04_26_054507_changes_for_v3310.php b/database/migrations/2015_04_26_054507_changes_for_v3310.php index 3598736a21..7073e1b6b1 100644 --- a/database/migrations/2015_04_26_054507_changes_for_v3310.php +++ b/database/migrations/2015_04_26_054507_changes_for_v3310.php @@ -5,7 +5,7 @@ use Illuminate\Database\Schema\Blueprint; /** * @SuppressWarnings(PHPMD.ShortMethodName) - * @SuppressWarnings("PHPMD.ExcessiveMethodLength") + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) * * Class ChangesForV3310 */ diff --git a/database/migrations/2015_05_28_041652_entrust_setup_tables.php b/database/migrations/2015_05_28_041652_entrust_setup_tables.php index 270f46a768..f18279e3a5 100644 --- a/database/migrations/2015_05_28_041652_entrust_setup_tables.php +++ b/database/migrations/2015_05_28_041652_entrust_setup_tables.php @@ -4,6 +4,9 @@ use Illuminate\Database\Schema\Blueprint; /** * Class EntrustSetupTables + * + * @SuppressWarnings(PHPMD.ShortMethodName) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ class EntrustSetupTables extends Migration { diff --git a/database/migrations/2015_06_14_093841_changes_for_v345.php b/database/migrations/2015_06_14_093841_changes_for_v345.php index 43a1df7223..752a0a54f9 100644 --- a/database/migrations/2015_06_14_093841_changes_for_v345.php +++ b/database/migrations/2015_06_14_093841_changes_for_v345.php @@ -5,6 +5,9 @@ use Illuminate\Database\Schema\Blueprint; /** * Class ChangesForV345 + * + * @SuppressWarnings(PHPMD.ShortMethodName) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ class ChangesForV345 extends Migration { diff --git a/database/migrations/2015_07_03_102450_changes_for_v3462.php b/database/migrations/2015_07_03_102450_changes_for_v3462.php index 930c8b0bab..d18d7c232c 100644 --- a/database/migrations/2015_07_03_102450_changes_for_v3462.php +++ b/database/migrations/2015_07_03_102450_changes_for_v3462.php @@ -5,6 +5,8 @@ use Illuminate\Database\Schema\Blueprint; /** * Class ChangesForV3462 + * + * @SuppressWarnings(PHPMD.ShortMethodName) */ class ChangesForV3462 extends Migration { diff --git a/database/migrations/2015_07_14_204645_changes_for_v349.php b/database/migrations/2015_07_14_204645_changes_for_v349.php index 3f2538c339..48147e6448 100644 --- a/database/migrations/2015_07_14_204645_changes_for_v349.php +++ b/database/migrations/2015_07_14_204645_changes_for_v349.php @@ -5,6 +5,8 @@ use Illuminate\Database\Schema\Blueprint; /** * Class ChangesForV349 + * + * @SuppressWarnings(PHPMD.ShortMethodName) */ class ChangesForV349 extends Migration { diff --git a/database/migrations/2015_07_17_190438_changes_for_v3410.php b/database/migrations/2015_07_17_190438_changes_for_v3410.php index c8e64213d9..feebb8396b 100644 --- a/database/migrations/2015_07_17_190438_changes_for_v3410.php +++ b/database/migrations/2015_07_17_190438_changes_for_v3410.php @@ -5,6 +5,8 @@ use Illuminate\Database\Schema\Blueprint; /** * Class ChangesForV3410 + * + * @SuppressWarnings(PHPMD.ShortMethodName) */ class ChangesForV3410 extends Migration { diff --git a/database/migrations/2016_01_11_193428_changes_for_v370.php b/database/migrations/2016_01_11_193428_changes_for_v370.php new file mode 100644 index 0000000000..87134f0581 --- /dev/null +++ b/database/migrations/2016_01_11_193428_changes_for_v370.php @@ -0,0 +1,125 @@ +increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->integer('user_id')->unsigned(); + $table->unsignedSmallInteger('order'); + $table->string('title', 255); + $table->text('description')->nullable(); + $table->unsignedTinyInteger('active')->default(1); + + // connect rule groups to users + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + } + ); + + + // new table "rules": + Schema::create( + 'rules', function (Blueprint $table) { + $table->increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->integer('user_id')->unsigned(); + $table->integer('rule_group_id')->unsigned(); + $table->unsignedSmallInteger('order'); + $table->unsignedTinyInteger('active')->default(1); + $table->unsignedTinyInteger('stop_processing')->default(0); + + $table->string('title', 255); + $table->text('description')->nullable(); + + + // connect rules to users + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + // connect rules to rule groups + $table->foreign('rule_group_id')->references('id')->on('rule_groups')->onDelete('cascade'); + + } + ); + + + // new table "rule_triggers" + Schema::create( + 'rule_triggers', function (Blueprint $table) { + $table->increments('id'); + $table->timestamps(); + $table->integer('rule_id')->unsigned(); + $table->unsignedSmallInteger('order'); + $table->unsignedTinyInteger('active')->default(1); + $table->unsignedTinyInteger('stop_processing')->default(0); + + $table->string('trigger_type', 50); + $table->string('trigger_value', 255)->nullable(); + + // connect rule triggers to rules + $table->foreign('rule_id')->references('id')->on('rules')->onDelete('cascade'); + } + ); + + // new table "rule_actions" + Schema::create( + 'rule_actions', function (Blueprint $table) { + $table->increments('id'); + $table->timestamps(); + $table->integer('rule_id')->unsigned(); + $table->unsignedSmallInteger('order'); + $table->unsignedTinyInteger('active')->default(1); + $table->unsignedTinyInteger('stop_processing')->default(0); + + $table->string('action_type', 50); + $table->string('action_value', 255)->nullable(); + + // connect rule actions to rules + $table->foreign('rule_id')->references('id')->on('rules')->onDelete('cascade'); + + } + ); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('rule_actions'); + Schema::drop('rule_triggers'); + Schema::drop('rules'); + Schema::drop('rule_groups'); + + } +} diff --git a/database/seeds/.gitkeep b/database/seeds/.gitkeep old mode 100644 new mode 100755 diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 9adb4e5c34..69a846e857 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -22,9 +22,15 @@ class DatabaseSeeder extends Seeder $this->call('TransactionTypeSeeder'); $this->call('PermissionSeeder'); - if (App::environment() == 'testing' || App::environment() == 'homestead' || gethostname() == 'lightning') { + // set up basic test data (as little as possible): + if (App::environment() == 'testing') { $this->call('TestDataSeeder'); } + + // this one is reserved for more extensive testing. + if (App::environment() == 'local') { + $this->call('VisualTestDataSeeder'); + } } } diff --git a/database/seeds/TestDataSeeder.php b/database/seeds/TestDataSeeder.php index 9d6bf19497..bff773ef8c 100644 --- a/database/seeds/TestDataSeeder.php +++ b/database/seeds/TestDataSeeder.php @@ -1,7 +1,9 @@ start = Carbon::create()->subYear()->startOfYear(); } /** + * Run the database seeds. * + * @return void */ public function run() { - $this->createUsers(); - - // create accounts: - $this->createAssetAccounts(); - $this->createExpenseAccounts(); - $this->createRevenueAccounts(); - $this->createBills(); - $this->createPiggybanks(); - - // dates: - $start = Carbon::now()->subYears(5)->startOfMonth(); - $end = Carbon::now()->endOfDay(); + $user = User::create(['email' => 'thegrumpydictator@gmail.com', 'password' => bcrypt('james'), 'reset' => null, 'remember_token' => null]); + $emptyUser = User::create(['email' => 'thegrumpydictator+empty@gmail.com', 'password' => bcrypt('james'), 'reset' => null, 'remember_token' => null]); - $current = clone $start; - while ($current < $end) { - $month = $current->format('F Y'); - // create salaries: - $this->createIncome('Salary ' . $month, $current, rand(2000, 2200)); + $admin = Role::where('name', 'owner')->first(); + $user->attachRole($admin); - // pay bills: - $this->createRent('Rent for ' . $month, $current, 800); - $this->createWater('Water bill for ' . $month, $current, 15); - $this->createTV('TV bill for ' . $month, $current, 60); - $this->createPower('Power bill for ' . $month, $current, 120); - // pay daily groceries: - $this->createGroceries($current); + // create asset accounts for user #1. + $this->createAssetAccounts($user); - // create tag (each type of tag, for date): - $this->createTags($current); + // create bills for user #1 + $this->createBills($user); - // go out for drinks: - $this->createDrinksAndOthers($current); + // create some budgets for user #1 + $this->createBudgets($user); - // save money every month: - $this->createSavings($current); + // create some categories for user #1 + $this->createCategories($user); - // budget limit for this month, on "Groceries". - $this->createBudgetLimit($current, 'Groceries', 400); - $this->createBudgetLimit($current, 'Bills', 1000); + // create some piggy banks for user #1 + $this->createPiggybanks($user); - echo 'Created test data for ' . $month . "\n"; - $current->addMonth(); - } + // create some expense accounts for user #1 + $this->createExpenseAccounts($user); + // create some revenue accounts for user #1 + $this->createRevenueAccounts($user); + + // create journal + attachment: + $this->createAttachments($user); + + // create opening balance for savings account: + $this->openingBalanceSavings($user); } /** - * @param Carbon $date + * @param User $user */ - protected function createTags(Carbon $date) + private function createAssetAccounts(User $user) { - Tag::create( - [ - 'user_id' => $this->user->id, - 'tag' => 'SomeTag' . $date->month . '.' . $date->year . '.nothing', - 'tagMode' => 'nothing', - 'date' => $date->format('Y-m-d'), - - - ] - ); - } - - /** - * - */ - protected function createUsers() - { - User::create(['email' => 'thegrumpydictator@gmail.com', 'password' => bcrypt('james'), 'reset' => null, 'remember_token' => null]); - $this->user = User::whereEmail('thegrumpydictator@gmail.com')->first(); - - // create rights: - $role = Role::find(1); - $this->user->roles()->save($role); - - } - - protected function createAssetAccounts() - { - $assets = ['MyBank Checking Account', 'Savings', 'Shared', 'Creditcard', 'Emergencies', 'STE']; - $ibans = ['NL47JDYU6179706202', 'NL51WGBP5832453599', 'NL81RCQZ7160379858', 'NL19NRAP2367994221', 'NL40UKBK3619908726', 'NL38SRMN4325934708']; + $assets = ['TestData Checking Account', 'TestData Savings', 'TestData Shared', 'TestData Creditcard', 'Emergencies', 'STE']; + // first two ibans match test-upload.csv + $ibans = ['NL11XOLA6707795988', 'NL96DZCO4665940223', 'NL81RCQZ7160379858', 'NL19NRAP2367994221', 'NL40UKBK3619908726', 'NL38SRMN4325934708']; $assetMeta = [ - [ - 'accountRole' => 'defaultAsset', - ], - [ - 'accountRole' => 'savingAsset', - ], - [ - 'accountRole' => 'sharedAsset', - ], - [ - 'accountRole' => 'ccAsset', - 'ccMonthlyPaymentDate' => '2015-05-27', - 'ccType' => 'monthlyFull' - ], - [ - 'accountRole' => 'savingAsset', - ], - [ - 'accountRole' => 'savingAsset', - ], - + ['accountRole' => 'defaultAsset'], + ['accountRole' => 'savingAsset',], + ['accountRole' => 'sharedAsset',], + ['accountRole' => 'ccAsset', 'ccMonthlyPaymentDate' => '2015-05-27', 'ccType' => 'monthlyFull',], + ['accountRole' => 'savingAsset',], + ['accountRole' => 'savingAsset',], ]; foreach ($assets as $index => $name) { // create account: $account = Account::create( [ - 'user_id' => $this->user->id, + 'user_id' => $user->id, 'account_type_id' => 3, 'name' => $name, 'active' => 1, @@ -162,49 +109,90 @@ class TestDataSeeder extends Seeder AccountMeta::create(['account_id' => $account->id, 'name' => $name, 'data' => $value,]); } } - } - - protected function createExpenseAccounts() - { - $expenses = ['Adobe', 'Google', 'Vitens', 'Albert Heijn', 'PLUS', 'Apple', 'Bakker', 'Belastingdienst', 'bol.com', 'Cafe Central', 'conrad.nl', - 'coolblue', - 'DUO', 'Etos', 'FEBO', 'Greenchoice', 'Halfords', 'XS4All', 'iCentre', 'Jumper', 'Land lord']; - foreach ($expenses as $name) { - // create account: - Account::create( - [ - 'user_id' => $this->user->id, - 'account_type_id' => 4, - 'name' => $name, - 'active' => 1, - 'encrypted' => 1, - ] - ); - } } /** - * + * @param User $user */ - protected function createRevenueAccounts() + private function createAttachments(User $user) { - $revenues = ['Job', 'Belastingdienst', 'Bank', 'KPN', 'Google']; - foreach ($revenues as $name) { - // create account: - Account::create( - [ - 'user_id' => $this->user->id, - 'account_type_id' => 5, - 'name' => $name, - 'active' => 1, - 'encrypted' => 1, - ] - ); - } + + $toAccount = $this->findAccount($user, 'TestData Checking Account'); + $fromAccount = $this->findAccount($user, 'Job'); + + $journal = TransactionJournal::create( + [ + 'user_id' => $user->id, + 'transaction_type_id' => 2, + 'transaction_currency_id' => 1, + 'description' => 'Some journal for attachment', + 'completed' => 1, + 'date' => new Carbon, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => -100, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => 100, + + ] + ); + + // and now attachments + $encrypted = Crypt::encrypt('I are secret'); + Attachment::create( + [ + 'attachable_id' => $journal->id, + 'attachable_type' => 'FireflyIII\Models\TransactionJournal', + 'user_id' => $user->id, + 'md5' => md5('Hallo'), + 'filename' => 'empty-file.txt', + 'title' => 'Empty file', + 'description' => 'This file is empty', + 'notes' => 'What notes', + 'mime' => 'text/plain', + 'size' => strlen($encrypted), + 'uploaded' => 1, + ] + ); + + + // and now attachment. + Attachment::create( + [ + 'attachable_id' => $journal->id, + 'attachable_type' => 'FireflyIII\Models\TransactionJournal', + 'user_id' => $user->id, + 'md5' => md5('Ook hallo'), + 'filename' => 'empty-file-2.txt', + 'title' => 'Empty file 2', + 'description' => 'This file is empty too', + 'notes' => 'What notes do', + 'mime' => 'text/plain', + 'size' => strlen($encrypted), + 'uploaded' => 1, + ] + ); + // echo crypted data to the file. + file_put_contents(storage_path('upload/at-1.data'), $encrypted); + file_put_contents(storage_path('upload/at-2.data'), $encrypted); + } - public function createBills() + /** + * @param User $user + */ + private function createBills(User $user) { Bill::create( [ @@ -212,7 +200,7 @@ class TestDataSeeder extends Seeder 'match' => 'rent,land,lord', 'amount_min' => 795, 'amount_max' => 805, - 'user_id' => $this->user->id, + 'user_id' => $user->id, 'date' => '2015-01-01', 'active' => 1, 'automatch' => 1, @@ -226,7 +214,7 @@ class TestDataSeeder extends Seeder 'match' => 'zilveren,kruis,health', 'amount_min' => 120, 'amount_max' => 140, - 'user_id' => $this->user->id, + 'user_id' => $user->id, 'date' => '2015-01-01', 'active' => 1, 'automatch' => 1, @@ -236,9 +224,76 @@ class TestDataSeeder extends Seeder ); } - protected function createPiggybanks() + /** + * @param $user + */ + private function createBudgets($user) { - $account = $this->findAccount('Savings'); + $set = [ + Budget::firstOrCreateEncrypted(['name' => 'Groceries', 'user_id' => $user->id]), + Budget::firstOrCreateEncrypted(['name' => 'Bills', 'user_id' => $user->id]), + ]; + $current = new Carbon; + /** @var Budget $budget */ + foreach ($set as $budget) { + + // some budget limits: + $start = clone $current; + $end = clone $current; + $start->startOfMonth(); + $end->endOfMonth(); + + BudgetLimit::create( + [ + 'budget_id' => $budget->id, + 'startdate' => $start->format('Y-m-d'), + 'amount' => 500, + 'repeats' => 0, + 'repeat_freq' => 'monthly', + ] + ); + } + } + + /** + * @param User $user + */ + private function createCategories(User $user) + { + Category::firstOrCreateEncrypted(['name' => 'Groceries', 'user_id' => $user->id]); + Category::firstOrCreateEncrypted(['name' => 'Car', 'user_id' => $user->id]); + } + + /** + * @param User $user + */ + private function createExpenseAccounts(User $user) + { + $expenses = ['Adobe', 'Google', 'Vitens', 'Albert Heijn', 'PLUS', 'Apple', 'Bakker', 'Belastingdienst', 'bol.com', 'Cafe Central', 'conrad.nl', + 'coolblue', 'Shell', + 'DUO', 'Etos', 'FEBO', 'Greenchoice', 'Halfords', 'XS4All', 'iCentre', 'Jumper', 'Land lord']; + foreach ($expenses as $name) { + // create account: + Account::create( + [ + 'user_id' => $user->id, + 'account_type_id' => 4, + 'name' => $name, + 'active' => 1, + 'encrypted' => 1, + ] + ); + } + + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @param User $user + */ + private function createPiggybanks(User $user) + { + $account = $this->findAccount($user, 'TestData Savings'); $camera = PiggyBank::create( [ @@ -260,21 +315,21 @@ class TestDataSeeder extends Seeder [ 'piggy_bank_id' => $camera->id, 'date' => '2015-05-01', - 'amount' => '245' + 'amount' => '245', ] ); PiggyBankEvent::create( [ 'piggy_bank_id' => $camera->id, 'date' => '2015-06-01', - 'amount' => '245' + 'amount' => '245', ] ); PiggyBankEvent::create( [ 'piggy_bank_id' => $camera->id, 'date' => '2015-07-01', - 'amount' => '245' + 'amount' => '245', ] ); @@ -299,21 +354,21 @@ class TestDataSeeder extends Seeder [ 'piggy_bank_id' => $phone->id, 'date' => '2015-05-01', - 'amount' => '111' + 'amount' => '111', ] ); PiggyBankEvent::create( [ 'piggy_bank_id' => $phone->id, 'date' => '2015-06-01', - 'amount' => '111' + 'amount' => '111', ] ); PiggyBankEvent::create( [ 'piggy_bank_id' => $phone->id, 'date' => '2015-07-01', - 'amount' => '111' + 'amount' => '111', ] ); @@ -337,21 +392,21 @@ class TestDataSeeder extends Seeder [ 'piggy_bank_id' => $couch->id, 'date' => '2015-05-01', - 'amount' => '40' + 'amount' => '40', ] ); PiggyBankEvent::create( [ 'piggy_bank_id' => $couch->id, 'date' => '2015-06-01', - 'amount' => '40' + 'amount' => '40', ] ); PiggyBankEvent::create( [ 'piggy_bank_id' => $couch->id, 'date' => '2015-07-01', - 'amount' => '40' + 'amount' => '40', ] ); @@ -371,15 +426,36 @@ class TestDataSeeder extends Seeder } /** - * @param $name + * @param User $user + */ + private function createRevenueAccounts(User $user) + { + $revenues = ['Job', 'Belastingdienst', 'Bank', 'KPN', 'Google']; + foreach ($revenues as $name) { + // create account: + Account::create( + [ + 'user_id' => $user->id, + 'account_type_id' => 5, + 'name' => $name, + 'active' => 1, + 'encrypted' => 1, + ] + ); + } + } + + /** + * @param User $user + * @param $name * * @return Account|null */ - protected function findAccount($name) + private function findAccount(User $user, $name) { /** @var Account $account */ - foreach (Account::get() as $account) { - if ($account->name == $name && $this->user->id == $account->user_id) { + foreach ($user->accounts()->get() as $account) { + if ($account->name == $name) { return $account; break; } @@ -389,519 +465,52 @@ class TestDataSeeder extends Seeder } /** - * @param $description - * @param Carbon $date - * @param $amount - * - * @return TransactionJournal + * @param User $user */ - protected function createIncome($description, Carbon $date, $amount) + private function openingBalanceSavings(User $user) { - $date = new Carbon($date->format('Y-m') . '-23'); // paid on 23rd. - $today = new Carbon; - if ($date >= $today) { - return null; - } - $toAccount = $this->findAccount('MyBank Checking Account'); - $fromAccount = $this->findAccount('Job'); - $category = Category::firstOrCreateEncrypted(['name' => 'Salary', 'user_id' => $this->user->id]); - // create journal: + // opposing account for opening balance: + $opposing = Account::create( + [ + 'user_id' => $user->id, + 'account_type_id' => 6, + 'name' => 'Opposing for savings', + 'active' => 1, + 'encrypted' => 1, + ] + ); + + // savings + $savings = $this->findAccount($user, 'TestData Savings'); $journal = TransactionJournal::create( [ - 'user_id' => $this->user->id, - 'transaction_type_id' => 2, + 'user_id' => $user->id, + 'transaction_type_id' => 4, 'transaction_currency_id' => 1, - 'description' => $description, + 'description' => 'Opening balance for savings account', 'completed' => 1, - 'date' => $date, + 'date' => $this->start->format('Y-m-d'), ] ); + + // transactions Transaction::create( [ - 'account_id' => $fromAccount->id, + 'account_id' => $opposing->id, 'transaction_journal_id' => $journal->id, - 'amount' => $amount * -1, - + 'amount' => -10000, ] ); + Transaction::create( [ - 'account_id' => $toAccount->id, + 'account_id' => $savings->id, 'transaction_journal_id' => $journal->id, - 'amount' => $amount, - + 'amount' => 10000, ] ); - $journal->categories()->save($category); - return $journal; } - - /** - * @param $description - * @param Carbon $date - * @param $amount - * - * @return TransactionJournal - */ - protected function createRent($description, Carbon $date, $amount) - { - $fromAccount = $this->findAccount('MyBank Checking Account'); - $toAccount = $this->findAccount('Land lord'); - $category = Category::firstOrCreateEncrypted(['name' => 'Rent', 'user_id' => $this->user->id]); - $budget = Budget::firstOrCreateEncrypted(['name' => 'Bills', 'user_id' => $this->user->id]); - $journal = TransactionJournal::create( - [ - 'user_id' => $this->user->id, - 'transaction_type_id' => 1, - 'transaction_currency_id' => 1, - 'bill_id' => 1, - 'description' => $description, - 'completed' => 1, - 'date' => $date, - ] - ); - Transaction::create( - [ - 'account_id' => $fromAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount * -1, - - ] - ); - Transaction::create( - [ - 'account_id' => $toAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount, - - ] - ); - $journal->categories()->save($category); - $journal->budgets()->save($budget); - - return $journal; - - } - - /** - * @param $description - * @param Carbon $date - * @param $amount - * - * @return TransactionJournal - */ - protected function createWater($description, Carbon $date, $amount) - { - $date = new Carbon($date->format('Y-m') . '-10'); // paid on 10th - $fromAccount = $this->findAccount('MyBank Checking Account'); - $toAccount = $this->findAccount('Vitens'); - $category = Category::firstOrCreateEncrypted(['name' => 'House', 'user_id' => $this->user->id]); - $budget = Budget::firstOrCreateEncrypted(['name' => 'Bills', 'user_id' => $this->user->id]); - $journal = TransactionJournal::create( - [ - 'user_id' => $this->user->id, - 'transaction_type_id' => 1, - 'transaction_currency_id' => 1, - 'description' => $description, - 'completed' => 1, - 'date' => $date, - ] - ); - Transaction::create( - [ - 'account_id' => $fromAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount * -1, - - ] - ); - Transaction::create( - [ - 'account_id' => $toAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount, - - ] - ); - $journal->categories()->save($category); - $journal->budgets()->save($budget); - - return $journal; - - } - - /** - * @param $description - * @param Carbon $date - * @param $amount - * - * @return TransactionJournal - */ - protected function createTV($description, Carbon $date, $amount) - { - $date = new Carbon($date->format('Y-m') . '-15'); // paid on 10th - $fromAccount = $this->findAccount('MyBank Checking Account'); - $toAccount = $this->findAccount('XS4All'); - $category = Category::firstOrCreateEncrypted(['name' => 'House', 'user_id' => $this->user->id]); - $budget = Budget::firstOrCreateEncrypted(['name' => 'Bills', 'user_id' => $this->user->id]); - $journal = TransactionJournal::create( - [ - 'user_id' => $this->user->id, - 'transaction_type_id' => 1, - 'transaction_currency_id' => 1, - 'description' => $description, - 'completed' => 1, - 'date' => $date, - ] - ); - Transaction::create( - [ - 'account_id' => $fromAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount * -1, - - ] - ); - Transaction::create( - [ - 'account_id' => $toAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount, - - ] - ); - $journal->categories()->save($category); - $journal->budgets()->save($budget); - - return $journal; - - } - - /** - * @param $description - * @param Carbon $date - * @param $amount - * - * @return TransactionJournal - */ - protected function createPower($description, Carbon $date, $amount) - { - $date = new Carbon($date->format('Y-m') . '-06'); // paid on 10th - $fromAccount = $this->findAccount('MyBank Checking Account'); - $toAccount = $this->findAccount('Greenchoice'); - $category = Category::firstOrCreateEncrypted(['name' => 'House', 'user_id' => $this->user->id]); - $budget = Budget::firstOrCreateEncrypted(['name' => 'Bills', 'user_id' => $this->user->id]); - $journal = TransactionJournal::create( - [ - 'user_id' => $this->user->id, - 'transaction_type_id' => 1, - 'transaction_currency_id' => 1, - 'description' => $description, - 'completed' => 1, - 'date' => $date, - ] - ); - Transaction::create( - [ - 'account_id' => $fromAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount * -1, - - ] - ); - Transaction::create( - [ - 'account_id' => $toAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount, - - ] - ); - $journal->categories()->save($category); - $journal->budgets()->save($budget); - - return $journal; - - } - - /** - * @param Carbon $date - */ - protected function createGroceries(Carbon $date) - { - $start = clone $date; - $end = clone $date; - $today = new Carbon; - $start->startOfMonth(); - $end->endOfMonth(); - - $fromAccount = $this->findAccount('MyBank Checking Account'); - $stores = ['Albert Heijn', 'PLUS', 'Bakker']; - $category = Category::firstOrCreateEncrypted(['name' => 'Daily groceries', 'user_id' => $this->user->id]); - $budget = Budget::firstOrCreateEncrypted(['name' => 'Groceries', 'user_id' => $this->user->id]); - - $current = clone $start; - while ($current < $end && $current < $today) { - // daily groceries: - $amount = rand(1000, 2500) / 100; - $toAccount = $this->findAccount($stores[rand(0, count($stores) - 1)]); - - $journal = TransactionJournal::create( - [ - 'user_id' => $this->user->id, - 'transaction_type_id' => 1, - 'transaction_currency_id' => 1, - 'description' => 'Groceries', - 'completed' => 1, - 'date' => $current, - ] - ); - Transaction::create( - [ - 'account_id' => $fromAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount * -1, - - ] - ); - Transaction::create( - [ - 'account_id' => $toAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount, - - ] - ); - $journal->categories()->save($category); - $journal->budgets()->save($budget); - - - $current->addDay(); - } - } - - /** - * @param Carbon $date - */ - protected function createDrinksAndOthers(Carbon $date) - { - $start = clone $date; - $end = clone $date; - $today = new Carbon; - $start->startOfMonth(); - $end->endOfMonth(); - $current = clone $start; - while ($current < $end && $current < $today) { - - // weekly drink: - $thisDate = clone $current; - $thisDate->addDay(); - $fromAccount = $this->findAccount('MyBank Checking Account'); - $toAccount = $this->findAccount('Cafe Central'); - $category = Category::firstOrCreateEncrypted(['name' => 'Drinks', 'user_id' => $this->user->id]); - $budget = Budget::firstOrCreateEncrypted(['name' => 'Going out', 'user_id' => $this->user->id]); - $amount = rand(1500, 3600) / 100; - $journal = TransactionJournal::create( - [ - 'user_id' => $this->user->id, - 'transaction_type_id' => 1, - 'transaction_currency_id' => 1, - 'description' => 'Going out for drinks', - 'completed' => 1, - 'date' => $thisDate, - ] - ); - Transaction::create( - [ - 'account_id' => $fromAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount * -1, - - ] - ); - Transaction::create( - [ - 'account_id' => $toAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => $amount, - - ] - ); - $journal->categories()->save($category); - $journal->budgets()->save($budget); - - // shopping at some (online) shop: - - - $current->addWeek(); - } - } - - /** - * @param Carbon $date - * - * @return TransactionJournal - */ - protected function createSavings(Carbon $date) - { - $date = new Carbon($date->format('Y-m') . '-24'); // paid on 24th. - $toAccount = $this->findAccount('Savings'); - $fromAccount = $this->findAccount('MyBank Checking Account'); - $category = Category::firstOrCreateEncrypted(['name' => 'Money management', 'user_id' => $this->user->id]); - // create journal: - - $journal = TransactionJournal::create( - [ - 'user_id' => $this->user->id, - 'transaction_type_id' => 3, - 'transaction_currency_id' => 1, - 'description' => 'Save money', - 'completed' => 1, - 'date' => $date, - ] - ); - Transaction::create( - [ - 'account_id' => $fromAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => -150, - - ] - ); - Transaction::create( - [ - 'account_id' => $toAccount->id, - 'transaction_journal_id' => $journal->id, - 'amount' => 150, - - ] - ); - $journal->categories()->save($category); - - return $journal; - - } - - /** - * @param Carbon $current - * @param $name - * @param $amount - */ - protected function createBudgetLimit(Carbon $current, $name, $amount) - { - $start = clone $current; - $end = clone $current; - $budget = $this->findBudget($name); - $start->startOfMonth(); - $end->endOfMonth(); - - BudgetLimit::create( - [ - 'budget_id' => $budget->id, - 'startdate' => $start->format('Y-m-d'), - 'amount' => $amount, - 'repeats' => 0, - 'repeat_freq' => 'monthly' - ] - ); - } - - /** - * @param $name - * - * @return Budget|null - */ - protected function findBudget($name) - { - /** @var Budget $budget */ - foreach (Budget::get() as $budget) { - if ($budget->name == $name && $this->user->id == $budget->user_id) { - return $budget; - break; - } - } - - return null; - } - - /** - * @param $name - * - * @return Bill|null - */ - protected function findBill($name) - { - /** @var Bill $bill */ - foreach (Bill::get() as $bill) { - if ($bill->name == $name && $this->user->id == $bill->user_id) { - return $bill; - break; - } - } - - return null; - } - - /** - * @param $name - * - * @return Category|null - */ - protected function findCategory($name) - { - - /** @var Category $category */ - foreach (Category::get() as $category) { - if ($category->name == $name && $this->user->id == $category->user_id) { - return $category; - break; - } - } - - return null; - } - - /** - * @param $name - * - * @return PiggyBank|null - */ - protected function findPiggyBank($name) - { - - /** @var Budget $budget */ - foreach (PiggyBank::get() as $piggyBank) { - $account = $piggyBank->account()->first(); - if ($piggyBank->name == $name && $this->user->id == $account->user_id) { - return $piggyBank; - break; - } - } - - return null; - } - - /** - * @param $tagName - * - * @return Tag|null - * @internal param $tag - */ - protected function findTag($tagName) - { - /** @var Tag $tag */ - foreach (Tag::get() as $tag) { - if ($tag->tag == $tagName && $this->user->id == $tag->user_id) { - return $tag; - break; - } - } - - return null; - } - - } diff --git a/database/seeds/VisualTestDataSeeder.php b/database/seeds/VisualTestDataSeeder.php new file mode 100644 index 0000000000..b099d2db30 --- /dev/null +++ b/database/seeds/VisualTestDataSeeder.php @@ -0,0 +1,1424 @@ +user()->associate($this->user); + $ruleGroup->order = 1; + $ruleGroup->active = 1; + $ruleGroup->title = 'Default rules'; + $ruleGroup->description = 'All your rules not in a particular group.'; + $ruleGroup->save(); + unset($ruleGroup); + + $ruleGroup = new RuleGroup; + $ruleGroup->user()->associate($this->user); + $ruleGroup->order = 2; + $ruleGroup->active = 1; + $ruleGroup->title = 'Empty rule group'; + $ruleGroup->description = 'Intentionally has no rules.'; + $ruleGroup->save(); + unset($ruleGroup); + + + $ruleGroup = new RuleGroup; + $ruleGroup->user()->associate($this->user); + $ruleGroup->order = 3; + $ruleGroup->active = 1; + $ruleGroup->title = 'Rules for bills'; + $ruleGroup->description = 'All rules for bills and recurring costs.'; + $ruleGroup->save(); + unset($ruleGroup); + + // move groceries to correct budget/category + $rule = new Rule; + $rule->user()->associate($this->user); + $rule->ruleGroup()->associate(RuleGroup::find(1)); + $rule->order = 1; + $rule->active = 1; + $rule->stop_processing = 0; + $rule->title = 'Move groceries'; + $rule->description = 'Move groceries to correct category and budget.'; + + $rule->save(); + + // initial trigger for this rule: + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 1; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'user_action'; + $ruleTrigger->trigger_value = 'store-journal'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // content trigger for this rule. + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 2; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'description_contains'; + $ruleTrigger->trigger_value = 'groceries'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // another + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 3; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'from_account_is'; + $ruleTrigger->trigger_value = 'MyBank Checking Account'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // actions for this rule. one, set category + $ruleAction = new RuleAction; + $ruleAction->rule()->associate($rule); + $ruleAction->order = 1; + $ruleAction->active = 1; + $ruleAction->stop_processing = 0; + $ruleAction->action_type = 'set_category'; + $ruleAction->action_value = 'Groceries'; + $ruleAction->save(); + unset($ruleAction); + + // actions for this rule. one, set budget + $ruleAction = new RuleAction; + $ruleAction->rule()->associate($rule); + $ruleAction->order = 2; + $ruleAction->active = 1; + $ruleAction->stop_processing = 0; + $ruleAction->action_type = 'set_budget'; + $ruleAction->action_value = 'Groceries'; + $ruleAction->save(); + unset($ruleAction); + + + // move "gas" to "Car" and "Car" + $rule = new Rule; + $rule->user()->associate($this->user); + $rule->ruleGroup()->associate(RuleGroup::find(1)); + $rule->order = 2; + $rule->active = 1; + $rule->stop_processing = 0; + $rule->title = 'Move gas'; + $rule->description = null; + + $rule->save(); + + // initial trigger for this rule: + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 1; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'user_action'; + $ruleTrigger->trigger_value = 'store-journal'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // content trigger for this rule. + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 2; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'description_contains'; + $ruleTrigger->trigger_value = 'gas'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // another + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 3; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'from_account_is'; + $ruleTrigger->trigger_value = 'MyBank Checking Account'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // actions for this rule. one, set category + $ruleAction = new RuleAction; + $ruleAction->rule()->associate($rule); + $ruleAction->order = 1; + $ruleAction->active = 1; + $ruleAction->stop_processing = 0; + $ruleAction->action_type = 'set_category'; + $ruleAction->action_value = 'Car'; + $ruleAction->save(); + unset($ruleAction); + + // actions for this rule. one, set budget + $ruleAction = new RuleAction; + $ruleAction->rule()->associate($rule); + $ruleAction->order = 2; + $ruleAction->active = 1; + $ruleAction->stop_processing = 0; + $ruleAction->action_type = 'set_budget'; + $ruleAction->action_value = 'Car'; + $ruleAction->save(); + unset($ruleAction); + + // move savings to money management + $rule = new Rule; + $rule->user()->associate($this->user); + $rule->ruleGroup()->associate(RuleGroup::find(1)); + $rule->order = 3; + $rule->active = 1; + $rule->stop_processing = 0; + $rule->title = 'Move savings'; + $rule->description = null; + + $rule->save(); + + // initial trigger for this rule: + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 1; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'user_action'; + $ruleTrigger->trigger_value = 'store-journal'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // is transfer + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 2; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'transaction_type'; + $ruleTrigger->trigger_value = 'Transfer'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // content trigger for this rule. + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 3; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'description_is'; + $ruleTrigger->trigger_value = 'Save money'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // another + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 4; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'from_account_is'; + $ruleTrigger->trigger_value = 'MyBank Checking Account'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // another + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 5; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'to_account_is'; + $ruleTrigger->trigger_value = 'Savings'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // actions for this rule. one, set category + $ruleAction = new RuleAction; + $ruleAction->rule()->associate($rule); + $ruleAction->order = 1; + $ruleAction->active = 1; + $ruleAction->stop_processing = 0; + $ruleAction->action_type = 'set_category'; + $ruleAction->action_value = 'Money Management'; + $ruleAction->save(); + unset($ruleAction); + + // move TV bill to "Bills" and "House" + $rule = new Rule; + $rule->user()->associate($this->user); + $rule->ruleGroup()->associate(RuleGroup::find(3)); + $rule->order = 1; + $rule->active = 1; + $rule->stop_processing = 0; + $rule->title = 'TV Bill'; + $rule->description = null; + + $rule->save(); + + // initial trigger for this rule: + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 1; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'user_action'; + $ruleTrigger->trigger_value = 'store-journal'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // content trigger for this rule. + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 2; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'description_contains'; + $ruleTrigger->trigger_value = 'tv bill'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // another + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 3; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'from_account_is'; + $ruleTrigger->trigger_value = 'MyBank Checking Account'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // actions for this rule. one, set category + $ruleAction = new RuleAction; + $ruleAction->rule()->associate($rule); + $ruleAction->order = 1; + $ruleAction->active = 1; + $ruleAction->stop_processing = 0; + $ruleAction->action_type = 'set_category'; + $ruleAction->action_value = 'House'; + $ruleAction->save(); + unset($ruleAction); + + // actions for this rule. one, set budget + $ruleAction = new RuleAction; + $ruleAction->rule()->associate($rule); + $ruleAction->order = 2; + $ruleAction->active = 1; + $ruleAction->stop_processing = 0; + $ruleAction->action_type = 'set_budget'; + $ruleAction->action_value = 'Bills'; + $ruleAction->save(); + unset($ruleAction); + + // move rent to bills, rent. + $rule = new Rule; + $rule->user()->associate($this->user); + $rule->ruleGroup()->associate(RuleGroup::find(3)); + $rule->order = 2; + $rule->active = 1; + $rule->stop_processing = 1; + $rule->title = 'Rent'; + $rule->description = 'Do something with rent.'; + + $rule->save(); + + // initial trigger for this rule: + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 1; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'user_action'; + $ruleTrigger->trigger_value = 'update-journal'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // content trigger for this rule. + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 2; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 0; + $ruleTrigger->trigger_type = 'description_contains'; + $ruleTrigger->trigger_value = 'rent'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // another + $ruleTrigger = new RuleTrigger; + $ruleTrigger->rule()->associate($rule); + $ruleTrigger->order = 3; + $ruleTrigger->active = 1; + $ruleTrigger->stop_processing = 1; + $ruleTrigger->trigger_type = 'from_account_is'; + $ruleTrigger->trigger_value = 'MyBank Checking Account'; + + $ruleTrigger->save(); + unset($ruleTrigger); + + // actions for this rule. one, set category + $ruleAction = new RuleAction; + $ruleAction->rule()->associate($rule); + $ruleAction->order = 1; + $ruleAction->active = 1; + $ruleAction->stop_processing = 0; + $ruleAction->action_type = 'set_category'; + $ruleAction->action_value = 'House'; + $ruleAction->save(); + unset($ruleAction); + + // actions for this rule. one, set budget + $ruleAction = new RuleAction; + $ruleAction->rule()->associate($rule); + $ruleAction->order = 2; + $ruleAction->active = 1; + $ruleAction->stop_processing = 1; + $ruleAction->action_type = 'set_budget'; + $ruleAction->action_value = 'Bills'; + $ruleAction->save(); + unset($ruleAction); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function run() + { + $this->createUsers(); + + // create accounts: + $this->createAssetAccounts(); + $this->createExpenseAccounts(); + $this->createRevenueAccounts(); + $this->createBills(); + $this->createPiggybanks(); + + $this->createRules(); + + // preference to only see account #1 on frontpage. + $this->createPreferences(); + + // dates: + $start = Carbon::now()->subYears(2)->startOfMonth(); + $end = Carbon::now()->endOfDay(); + + + $current = clone $start; + while ($current < $end) { + $month = $current->format('F Y'); + // create salaries: + $this->createIncome('Salary ' . $month, $current, rand(2000, 2100)); + + // pay bills: + $this->createRent('Rent for ' . $month, $current, 800); + $this->createWater('Water bill for ' . $month, $current, 15); + $this->createTV('TV bill for ' . $month, $current, 60); + $this->createPower('Power bill for ' . $month, $current, 120); + + + // pay daily groceries: + $this->createGroceries($current); + + // create tag (each type of tag, for date): + $this->createTags($current); + + // go out for drinks: + $this->createDrinksAndOthers($current); + + // save money every month: + $this->createSavings($current); + + // buy gas for the car every month: + $this->createCar($current); + + // budget limit for this month, on "Groceries". + $this->createBudgetLimit($current, 'Groceries', 400); + $this->createBudgetLimit($current, 'Bills', 1000); + $this->createBudgetLimit($current, 'Car', 100); + + echo 'Created test data for ' . $month . "\n"; + $current->addMonth(); + } + + } + + /** + * @param Carbon $date + */ + protected function createTags(Carbon $date) + { + Tag::create( + [ + 'user_id' => $this->user->id, + 'tag' => 'SomeTag' . $date->month . '.' . $date->year . '.nothing', + 'tagMode' => 'nothing', + 'date' => $date->format('Y-m-d'), + + + ] + ); + } + + /** + * + */ + protected function createUsers() + { + User::create(['email' => 'thegrumpydictator@gmail.com', 'password' => bcrypt('james'), 'reset' => null, 'remember_token' => null]); + $this->user = User::whereEmail('thegrumpydictator@gmail.com')->first(); + + // create rights: + $role = Role::find(1); + $this->user->roles()->save($role); + + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + protected function createAssetAccounts() + { + $assets = ['MyBank Checking Account', 'Savings', 'Shared', 'Creditcard', 'Emergencies', 'STE']; + $ibans = ['NL47JDYU6179706202', 'NL51WGBP5832453599', 'NL81RCQZ7160379858', 'NL19NRAP2367994221', 'NL40UKBK3619908726', 'NL38SRMN4325934708']; + $assetMeta = [ + [ + 'accountRole' => 'defaultAsset', + ], + [ + 'accountRole' => 'savingAsset', + ], + [ + 'accountRole' => 'sharedAsset', + ], + [ + 'accountRole' => 'ccAsset', + 'ccMonthlyPaymentDate' => '2015-05-27', + 'ccType' => 'monthlyFull', + ], + [ + 'accountRole' => 'savingAsset', + ], + [ + 'accountRole' => 'savingAsset', + ], + + ]; + + foreach ($assets as $index => $name) { + // create account: + $account = Account::create( + [ + 'user_id' => $this->user->id, + 'account_type_id' => 3, + 'name' => $name, + 'active' => 1, + 'encrypted' => 1, + 'iban' => $ibans[$index], + ] + ); + foreach ($assetMeta[$index] as $name => $value) { + AccountMeta::create(['account_id' => $account->id, 'name' => $name, 'data' => $value,]); + } + } + } + + protected function createExpenseAccounts() + { + $expenses = ['Adobe', 'Google', 'Vitens', 'Albert Heijn', 'PLUS', 'Apple', 'Bakker', 'Belastingdienst', 'bol.com', 'Cafe Central', 'conrad.nl', + 'coolblue', 'Shell', + 'DUO', 'Etos', 'FEBO', 'Greenchoice', 'Halfords', 'XS4All', 'iCentre', 'Jumper', 'Land lord']; + foreach ($expenses as $name) { + // create account: + Account::create( + [ + 'user_id' => $this->user->id, + 'account_type_id' => 4, + 'name' => $name, + 'active' => 1, + 'encrypted' => 1, + ] + ); + } + + } + + /** + * + */ + protected function createRevenueAccounts() + { + $revenues = ['Job', 'Belastingdienst', 'Bank', 'KPN', 'Google']; + foreach ($revenues as $name) { + // create account: + Account::create( + [ + 'user_id' => $this->user->id, + 'account_type_id' => 5, + 'name' => $name, + 'active' => 1, + 'encrypted' => 1, + ] + ); + } + } + + public function createBills() + { + Bill::create( + [ + 'name' => 'Rent', + 'match' => 'rent,land,lord', + 'amount_min' => 795, + 'amount_max' => 805, + 'user_id' => $this->user->id, + 'date' => '2015-01-01', + 'active' => 1, + 'automatch' => 1, + 'repeat_freq' => 'monthly', + 'skip' => 0, + ] + ); + Bill::create( + [ + 'name' => 'Health insurance', + 'match' => 'zilveren,kruis,health', + 'amount_min' => 120, + 'amount_max' => 140, + 'user_id' => $this->user->id, + 'date' => '2015-01-01', + 'active' => 1, + 'automatch' => 1, + 'repeat_freq' => 'monthly', + 'skip' => 0, + ] + ); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + protected function createPiggybanks() + { + $account = $this->findAccount('Savings'); + + $camera = PiggyBank::create( + [ + 'account_id' => $account->id, + 'name' => 'New camera', + 'targetamount' => 1000, + 'startdate' => '2015-04-01', + 'reminder_skip' => 0, + 'remind_me' => 0, + 'order' => 1, + ] + ); + $repetition = $camera->piggyBankRepetitions()->first(); + $repetition->currentamount = 735; + $repetition->save(); + + // events: + PiggyBankEvent::create( + [ + 'piggy_bank_id' => $camera->id, + 'date' => '2015-05-01', + 'amount' => '245', + ] + ); + PiggyBankEvent::create( + [ + 'piggy_bank_id' => $camera->id, + 'date' => '2015-06-01', + 'amount' => '245', + ] + ); + PiggyBankEvent::create( + [ + 'piggy_bank_id' => $camera->id, + 'date' => '2015-07-01', + 'amount' => '245', + ] + ); + + + $phone = PiggyBank::create( + [ + 'account_id' => $account->id, + 'name' => 'New phone', + 'targetamount' => 600, + 'startdate' => '2015-04-01', + 'reminder_skip' => 0, + 'remind_me' => 0, + 'order' => 2, + ] + ); + $repetition = $phone->piggyBankRepetitions()->first(); + $repetition->currentamount = 333; + $repetition->save(); + + // events: + PiggyBankEvent::create( + [ + 'piggy_bank_id' => $phone->id, + 'date' => '2015-05-01', + 'amount' => '111', + ] + ); + PiggyBankEvent::create( + [ + 'piggy_bank_id' => $phone->id, + 'date' => '2015-06-01', + 'amount' => '111', + ] + ); + PiggyBankEvent::create( + [ + 'piggy_bank_id' => $phone->id, + 'date' => '2015-07-01', + 'amount' => '111', + ] + ); + + $couch = PiggyBank::create( + [ + 'account_id' => $account->id, + 'name' => 'New couch', + 'targetamount' => 500, + 'startdate' => '2015-04-01', + 'reminder_skip' => 0, + 'remind_me' => 0, + 'order' => 3, + ] + ); + $repetition = $couch->piggyBankRepetitions()->first(); + $repetition->currentamount = 120; + $repetition->save(); + + // events: + PiggyBankEvent::create( + [ + 'piggy_bank_id' => $couch->id, + 'date' => '2015-05-01', + 'amount' => '40', + ] + ); + PiggyBankEvent::create( + [ + 'piggy_bank_id' => $couch->id, + 'date' => '2015-06-01', + 'amount' => '40', + ] + ); + PiggyBankEvent::create( + [ + 'piggy_bank_id' => $couch->id, + 'date' => '2015-07-01', + 'amount' => '40', + ] + ); + + // empty one. + PiggyBank::create( + [ + 'account_id' => $account->id, + 'name' => 'New head set', + 'targetamount' => 500, + 'startdate' => '2015-04-01', + 'reminder_skip' => 0, + 'remind_me' => 0, + 'order' => 4, + ] + ); + + } + + /** + * @param $name + * + * @return Account|null + */ + protected function findAccount($name) + { + /** @var Account $account */ + foreach (Account::get() as $account) { + if ($account->name == $name && $this->user->id == $account->user_id) { + return $account; + break; + } + } + + return null; + } + + /** + * @param $description + * @param Carbon $date + * @param $amount + * + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * + * @return TransactionJournal + */ + protected function createIncome($description, Carbon $date, $amount) + { + $date = new Carbon($date->format('Y-m') . '-23'); // paid on 23rd. + $today = new Carbon; + if ($date >= $today) { + return null; + } + $toAccount = $this->findAccount('MyBank Checking Account'); + $fromAccount = $this->findAccount('Job'); + $category = Category::firstOrCreateEncrypted(['name' => 'Salary', 'user_id' => $this->user->id]); + // create journal: + + $journal = TransactionJournal::create( + [ + 'user_id' => $this->user->id, + 'transaction_type_id' => 2, + 'transaction_currency_id' => 1, + 'description' => $description, + 'completed' => 1, + 'date' => $date, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount * -1, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount, + + ] + ); + $journal->categories()->save($category); + + return $journal; + + } + + /** + * @param $description + * @param Carbon $date + * @param $amount + * + * @return TransactionJournal + */ + protected function createRent($description, Carbon $date, $amount) + { + $fromAccount = $this->findAccount('MyBank Checking Account'); + $toAccount = $this->findAccount('Land lord'); + $category = Category::firstOrCreateEncrypted(['name' => 'Rent', 'user_id' => $this->user->id]); + $budget = Budget::firstOrCreateEncrypted(['name' => 'Bills', 'user_id' => $this->user->id]); + $journal = TransactionJournal::create( + [ + 'user_id' => $this->user->id, + 'transaction_type_id' => 1, + 'transaction_currency_id' => 1, + 'bill_id' => 1, + 'description' => $description, + 'completed' => 1, + 'date' => $date, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount * -1, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount, + + ] + ); + $journal->categories()->save($category); + $journal->budgets()->save($budget); + + return $journal; + + } + + /** + * @param $description + * @param Carbon $date + * @param $amount + * + * @return TransactionJournal + */ + protected function createWater($description, Carbon $date, $amount) + { + $date = new Carbon($date->format('Y-m') . '-10'); // paid on 10th + $fromAccount = $this->findAccount('MyBank Checking Account'); + $toAccount = $this->findAccount('Vitens'); + $category = Category::firstOrCreateEncrypted(['name' => 'House', 'user_id' => $this->user->id]); + $budget = Budget::firstOrCreateEncrypted(['name' => 'Bills', 'user_id' => $this->user->id]); + $journal = TransactionJournal::create( + [ + 'user_id' => $this->user->id, + 'transaction_type_id' => 1, + 'transaction_currency_id' => 1, + 'description' => $description, + 'completed' => 1, + 'date' => $date, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount * -1, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount, + + ] + ); + $journal->categories()->save($category); + $journal->budgets()->save($budget); + + return $journal; + + } + + /** + * @param $description + * @param Carbon $date + * @param $amount + * + * @return TransactionJournal + */ + protected function createTV($description, Carbon $date, $amount) + { + $date = new Carbon($date->format('Y-m') . '-15'); // paid on 10th + $fromAccount = $this->findAccount('MyBank Checking Account'); + $toAccount = $this->findAccount('XS4All'); + $category = Category::firstOrCreateEncrypted(['name' => 'House', 'user_id' => $this->user->id]); + $budget = Budget::firstOrCreateEncrypted(['name' => 'Bills', 'user_id' => $this->user->id]); + $journal = TransactionJournal::create( + [ + 'user_id' => $this->user->id, + 'transaction_type_id' => 1, + 'transaction_currency_id' => 1, + 'description' => $description, + 'completed' => 1, + 'date' => $date, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount * -1, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount, + + ] + ); + $journal->categories()->save($category); + $journal->budgets()->save($budget); + + return $journal; + + } + + /** + * @param $description + * @param Carbon $date + * @param $amount + * + * @return TransactionJournal + */ + protected function createPower($description, Carbon $date, $amount) + { + $date = new Carbon($date->format('Y-m') . '-06'); // paid on 10th + $fromAccount = $this->findAccount('MyBank Checking Account'); + $toAccount = $this->findAccount('Greenchoice'); + $category = Category::firstOrCreateEncrypted(['name' => 'House', 'user_id' => $this->user->id]); + $budget = Budget::firstOrCreateEncrypted(['name' => 'Bills', 'user_id' => $this->user->id]); + $journal = TransactionJournal::create( + [ + 'user_id' => $this->user->id, + 'transaction_type_id' => 1, + 'transaction_currency_id' => 1, + 'description' => $description, + 'completed' => 1, + 'date' => $date, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount * -1, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount, + + ] + ); + $journal->categories()->save($category); + $journal->budgets()->save($budget); + + return $journal; + + } + + /** + * @param Carbon $date + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + protected function createGroceries(Carbon $date) + { + $start = clone $date; + $end = clone $date; + $today = new Carbon; + $start->startOfMonth(); + $end->endOfMonth(); + + $fromAccount = $this->findAccount('MyBank Checking Account'); + $stores = ['Albert Heijn', 'PLUS', 'Bakker']; + $descriptions = ['Groceries', 'Bought some groceries', 'Got groceries']; + $category = Category::firstOrCreateEncrypted(['name' => 'Daily groceries', 'user_id' => $this->user->id]); + $budget = Budget::firstOrCreateEncrypted(['name' => 'Groceries', 'user_id' => $this->user->id]); + + $current = clone $start; + while ($current < $end && $current < $today) { + // daily groceries: + $amount = rand(1500, 2500) / 100; + $toAccount = $this->findAccount($stores[rand(0, count($stores) - 1)]); + + $journal = TransactionJournal::create( + [ + 'user_id' => $this->user->id, + 'transaction_type_id' => 1, + 'transaction_currency_id' => 1, + 'description' => $descriptions[rand(0, count($descriptions) - 1)], + 'completed' => 1, + 'date' => $current, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount * -1, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount, + + ] + ); + $journal->categories()->save($category); + $journal->budgets()->save($budget); + + + $current->addDay(); + } + } + + /** + * @param Carbon $date + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + protected function createDrinksAndOthers(Carbon $date) + { + $start = clone $date; + $end = clone $date; + $today = new Carbon; + $start->startOfMonth(); + $end->endOfMonth(); + $current = clone $start; + while ($current < $end && $current < $today) { + + // weekly drink: + $thisDate = clone $current; + $thisDate->addDay(); + $fromAccount = $this->findAccount('MyBank Checking Account'); + $toAccount = $this->findAccount('Cafe Central'); + $category = Category::firstOrCreateEncrypted(['name' => 'Drinks', 'user_id' => $this->user->id]); + $budget = Budget::firstOrCreateEncrypted(['name' => 'Going out', 'user_id' => $this->user->id]); + $amount = rand(1500, 3600) / 100; + $journal = TransactionJournal::create( + [ + 'user_id' => $this->user->id, + 'transaction_type_id' => 1, + 'transaction_currency_id' => 1, + 'description' => 'Going out for drinks', + 'completed' => 1, + 'date' => $thisDate, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount * -1, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount, + + ] + ); + $journal->categories()->save($category); + $journal->budgets()->save($budget); + + // shopping at some (online) shop: + + + $current->addWeek(); + } + } + + /** + * @param Carbon $date + * + * @return TransactionJournal + */ + protected function createSavings(Carbon $date) + { + $date = new Carbon($date->format('Y-m') . '-24'); // paid on 24th. + $toAccount = $this->findAccount('Savings'); + $fromAccount = $this->findAccount('MyBank Checking Account'); + $category = Category::firstOrCreateEncrypted(['name' => 'Money management', 'user_id' => $this->user->id]); + // create journal: + + $journal = TransactionJournal::create( + [ + 'user_id' => $this->user->id, + 'transaction_type_id' => 3, + 'transaction_currency_id' => 1, + 'description' => 'Save money', + 'completed' => 1, + 'date' => $date, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => -150, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => 150, + + ] + ); + $journal->categories()->save($category); + + return $journal; + + } + + /** + * @param Carbon $current + * @param $name + * @param $amount + */ + protected function createBudgetLimit(Carbon $current, $name, $amount) + { + $start = clone $current; + $end = clone $current; + $budget = $this->findBudget($name); + $start->startOfMonth(); + $end->endOfMonth(); + + BudgetLimit::create( + [ + 'budget_id' => $budget->id, + 'startdate' => $start->format('Y-m-d'), + 'amount' => $amount, + 'repeats' => 0, + 'repeat_freq' => 'monthly', + ] + ); + } + + /** + * @param $name + * + * @return Budget|null + */ + protected function findBudget($name) + { + /** @var Budget $budget */ + foreach (Budget::get() as $budget) { + if ($budget->name == $name && $this->user->id == $budget->user_id) { + return $budget; + break; + } + } + + return null; + } + + /** + * @param $name + * + * @return Bill|null + */ + protected function findBill($name) + { + /** @var Bill $bill */ + foreach (Bill::get() as $bill) { + if ($bill->name == $name && $this->user->id == $bill->user_id) { + return $bill; + break; + } + } + + return null; + } + + /** + * @param $name + * + * @return Category|null + */ + protected function findCategory($name) + { + + /** @var Category $category */ + foreach (Category::get() as $category) { + if ($category->name == $name && $this->user->id == $category->user_id) { + return $category; + break; + } + } + + return null; + } + + /** + * @param $name + * + * @return PiggyBank|null + */ + protected function findPiggyBank($name) + { + + /** @var Budget $budget */ + foreach (PiggyBank::get() as $piggyBank) { + $account = $piggyBank->account()->first(); + if ($piggyBank->name == $name && $this->user->id == $account->user_id) { + return $piggyBank; + break; + } + } + + return null; + } + + /** + * @param $tagName + * + * @return Tag|null + * @internal param $tag + */ + protected function findTag($tagName) + { + /** @var Tag $tag */ + foreach (Tag::get() as $tag) { + if ($tag->tag == $tagName && $this->user->id == $tag->user_id) { + return $tag; + break; + } + } + + return null; + } + + /** + * @param $date + * + * @return static + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + protected function createCar($date) + { + // twice: + $date = new Carbon($date->format('Y-m') . '-10'); // paid on 10th + $fromAccount = $this->findAccount('MyBank Checking Account'); + $toAccount = $this->findAccount('Shell'); + $category = Category::firstOrCreateEncrypted(['name' => 'Car', 'user_id' => $this->user->id]); + $budget = Budget::firstOrCreateEncrypted(['name' => 'Car', 'user_id' => $this->user->id]); + $amount = rand(4000, 5000) / 100; + $journal = TransactionJournal::create( + [ + 'user_id' => $this->user->id, + 'transaction_type_id' => 1, + 'transaction_currency_id' => 1, + 'description' => 'Bought gas', + 'completed' => 1, + 'date' => $date, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount * -1, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount, + + ] + ); + $journal->categories()->save($category); + $journal->budgets()->save($budget); + + // and again! + $date = new Carbon($date->format('Y-m') . '-20'); // paid on 20th + $amount = rand(4000, 5000) / 100; + + + $journal = TransactionJournal::create( + [ + 'user_id' => $this->user->id, + 'transaction_type_id' => 1, + 'transaction_currency_id' => 1, + 'description' => 'Gas for car', + 'completed' => 1, + 'date' => $date, + ] + ); + Transaction::create( + [ + 'account_id' => $fromAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount * -1, + + ] + ); + Transaction::create( + [ + 'account_id' => $toAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $amount, + + ] + ); + + // and again! + + return $journal; + } + + protected function createPreferences() + { + $preference = new Preference; + $preference->name = 'frontPageAccounts'; + $preference->data = [1]; + $preference->user()->associate($this->user); + $preference->save(); + } + + +} diff --git a/gulpfile.js b/gulpfile.js old mode 100644 new mode 100755 index 14dd43eabf..dc6f1ebb4e --- a/gulpfile.js +++ b/gulpfile.js @@ -1,4 +1,3 @@ -/* globals require */ var elixir = require('laravel-elixir'); /* @@ -7,12 +6,11 @@ var elixir = require('laravel-elixir'); |-------------------------------------------------------------------------- | | Elixir provides a clean, fluent API for defining some basic Gulp tasks - | for your Laravel application. By default, we are compiling the Less + | for your Laravel application. By default, we are compiling the Sass | file for our application, as well as publishing vendor resources. | */ elixir(function(mix) { - "use strict"; - mix.less('app.less'); + mix.sass('app.scss'); }); diff --git a/package.json b/package.json old mode 100644 new mode 100755 index f45052ae2e..460ee907b5 --- a/package.json +++ b/package.json @@ -1,6 +1,10 @@ { + "private": true, "devDependencies": { - "gulp": "^3.8.8", - "laravel-elixir": "*" + "gulp": "^3.8.8" + }, + "dependencies": { + "laravel-elixir": "^4.0.0", + "bootstrap-sass": "^3.0.0" } } diff --git a/phpunit.cover.xml b/phpunit.cover.xml new file mode 100755 index 0000000000..a37e48b5e4 --- /dev/null +++ b/phpunit.cover.xml @@ -0,0 +1,63 @@ + + + + + + + ./tests/ + + + + + app/Http + + + vendor/ + app/Console + app/Events + app/Exceptions + app/Generator + app/Handlers + app/Helpers + + app/Jobs + app/Listeners + app/Models + app/Policies + app/Providers + app/Repositories + app/Rules + app/Sql + app/Support + app/Validation + + + + + + + + + + + + + + + diff --git a/phpunit.default.xml b/phpunit.default.xml new file mode 100755 index 0000000000..cc0841c1d3 --- /dev/null +++ b/phpunit.default.xml @@ -0,0 +1,27 @@ + + + + + ./tests/ + + + + + app/ + + + + + + + + + diff --git a/phpunit.xml b/phpunit.xml old mode 100644 new mode 100755 index 6b3ab70282..cc0841c1d3 --- a/phpunit.xml +++ b/phpunit.xml @@ -7,25 +7,17 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="true" - syntaxCheck="false"> + stopOnFailure="false"> - ./tests + ./tests/ - ./app + app/ - - - diff --git a/pu.sh b/pu.sh new file mode 100755 index 0000000000..f3efd0a96b --- /dev/null +++ b/pu.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# set testing environment +cp .env.testing .env + +# set default phpunit. +cp phpunit.default.xml phpunit.xml + +# "create" default attachment: +touch storage/upload/at-1.data +touch storage/upload/at-2.data + + +# delete test databases: +if [ -f storage/database/testing.db ] +then + rm storage/database/testing.db +fi + +if [ -f storage/database/testing-copy.db ] +then + rm storage/database/testing-copy.db +fi + +# test! +if [ -z "$1" ] +then + echo "Running all tests..." + phpunit + result=$? +fi + +# test selective.. +dirs=("acceptance/Controllers" "acceptance/Controllers/Auth" "acceptance/Controllers/Chart" "unit") +# +if [ ! -z "$1" ] +then + for i in "${dirs[@]}" + do + firstFile="./tests/$i/$1.php" + secondFile="./tests/$i/$1Test.php" + if [ -f "$firstFile" ] + then + # run it! + echo "Now running $firstFile" + phpunit --verbose $firstFile + result=$? + fi + if [ -f "$secondFile" ] + then + # run it! + echo "Now running $secondFile" + phpunit --verbose $secondFile + result=$? + fi + + + done +fi + + +# restore .env file +cp .env.local .env + +exit ${result} \ No newline at end of file diff --git a/public/.htaccess b/public/.htaccess old mode 100644 new mode 100755 index 77827ae705..8eb2dd0ddf --- a/public/.htaccess +++ b/public/.htaccess @@ -5,7 +5,8 @@ RewriteEngine On - # Redirect Trailing Slashes... + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)/$ /$1 [L,R=301] # Handle Front Controller... diff --git a/public/css/firefly.css b/public/css/firefly.css index f60f7b03c6..670ca9d721 100644 --- a/public/css/firefly.css +++ b/public/css/firefly.css @@ -16,4 +16,8 @@ .login-box {width:600px;} .login-logo {width:360px;margin-left:110px;} .login-box-body {width:360px;margin-left:110px;} -.register-box-body {width:360px;margin-left:110px;} \ No newline at end of file +.register-box-body {width:360px;margin-left:110px;} + +/* cursors */ +.rule-triggers {cursor:move;} +.rule-actions {cursor:move;} \ No newline at end of file diff --git a/public/font-awesome/css/font-awesome.css b/public/font-awesome/css/font-awesome.css new file mode 100644 index 0000000000..b2a5fe2f25 --- /dev/null +++ b/public/font-awesome/css/font-awesome.css @@ -0,0 +1,2086 @@ +/*! + * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=4.5.0'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: .3em; +} +.fa.fa-pull-right { + margin-left: .3em; +} +/* Deprecated as of 4.4.0 */ +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-remove:before, +.fa-close:before, +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before, +.fa-bar-chart:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook-f:before, +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-feed:before, +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-desc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-asc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before, +.fa-gratipay:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} +.fa-space-shuttle:before { + content: "\f197"; +} +.fa-slack:before { + content: "\f198"; +} +.fa-envelope-square:before { + content: "\f199"; +} +.fa-wordpress:before { + content: "\f19a"; +} +.fa-openid:before { + content: "\f19b"; +} +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: "\f19c"; +} +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: "\f19d"; +} +.fa-yahoo:before { + content: "\f19e"; +} +.fa-google:before { + content: "\f1a0"; +} +.fa-reddit:before { + content: "\f1a1"; +} +.fa-reddit-square:before { + content: "\f1a2"; +} +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} +.fa-stumbleupon:before { + content: "\f1a4"; +} +.fa-delicious:before { + content: "\f1a5"; +} +.fa-digg:before { + content: "\f1a6"; +} +.fa-pied-piper:before { + content: "\f1a7"; +} +.fa-pied-piper-alt:before { + content: "\f1a8"; +} +.fa-drupal:before { + content: "\f1a9"; +} +.fa-joomla:before { + content: "\f1aa"; +} +.fa-language:before { + content: "\f1ab"; +} +.fa-fax:before { + content: "\f1ac"; +} +.fa-building:before { + content: "\f1ad"; +} +.fa-child:before { + content: "\f1ae"; +} +.fa-paw:before { + content: "\f1b0"; +} +.fa-spoon:before { + content: "\f1b1"; +} +.fa-cube:before { + content: "\f1b2"; +} +.fa-cubes:before { + content: "\f1b3"; +} +.fa-behance:before { + content: "\f1b4"; +} +.fa-behance-square:before { + content: "\f1b5"; +} +.fa-steam:before { + content: "\f1b6"; +} +.fa-steam-square:before { + content: "\f1b7"; +} +.fa-recycle:before { + content: "\f1b8"; +} +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} +.fa-tree:before { + content: "\f1bb"; +} +.fa-spotify:before { + content: "\f1bc"; +} +.fa-deviantart:before { + content: "\f1bd"; +} +.fa-soundcloud:before { + content: "\f1be"; +} +.fa-database:before { + content: "\f1c0"; +} +.fa-file-pdf-o:before { + content: "\f1c1"; +} +.fa-file-word-o:before { + content: "\f1c2"; +} +.fa-file-excel-o:before { + content: "\f1c3"; +} +.fa-file-powerpoint-o:before { + content: "\f1c4"; +} +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: "\f1c5"; +} +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: "\f1c6"; +} +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: "\f1c7"; +} +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: "\f1c8"; +} +.fa-file-code-o:before { + content: "\f1c9"; +} +.fa-vine:before { + content: "\f1ca"; +} +.fa-codepen:before { + content: "\f1cb"; +} +.fa-jsfiddle:before { + content: "\f1cc"; +} +.fa-life-bouy:before, +.fa-life-buoy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: "\f1cd"; +} +.fa-circle-o-notch:before { + content: "\f1ce"; +} +.fa-ra:before, +.fa-rebel:before { + content: "\f1d0"; +} +.fa-ge:before, +.fa-empire:before { + content: "\f1d1"; +} +.fa-git-square:before { + content: "\f1d2"; +} +.fa-git:before { + content: "\f1d3"; +} +.fa-y-combinator-square:before, +.fa-yc-square:before, +.fa-hacker-news:before { + content: "\f1d4"; +} +.fa-tencent-weibo:before { + content: "\f1d5"; +} +.fa-qq:before { + content: "\f1d6"; +} +.fa-wechat:before, +.fa-weixin:before { + content: "\f1d7"; +} +.fa-send:before, +.fa-paper-plane:before { + content: "\f1d8"; +} +.fa-send-o:before, +.fa-paper-plane-o:before { + content: "\f1d9"; +} +.fa-history:before { + content: "\f1da"; +} +.fa-circle-thin:before { + content: "\f1db"; +} +.fa-header:before { + content: "\f1dc"; +} +.fa-paragraph:before { + content: "\f1dd"; +} +.fa-sliders:before { + content: "\f1de"; +} +.fa-share-alt:before { + content: "\f1e0"; +} +.fa-share-alt-square:before { + content: "\f1e1"; +} +.fa-bomb:before { + content: "\f1e2"; +} +.fa-soccer-ball-o:before, +.fa-futbol-o:before { + content: "\f1e3"; +} +.fa-tty:before { + content: "\f1e4"; +} +.fa-binoculars:before { + content: "\f1e5"; +} +.fa-plug:before { + content: "\f1e6"; +} +.fa-slideshare:before { + content: "\f1e7"; +} +.fa-twitch:before { + content: "\f1e8"; +} +.fa-yelp:before { + content: "\f1e9"; +} +.fa-newspaper-o:before { + content: "\f1ea"; +} +.fa-wifi:before { + content: "\f1eb"; +} +.fa-calculator:before { + content: "\f1ec"; +} +.fa-paypal:before { + content: "\f1ed"; +} +.fa-google-wallet:before { + content: "\f1ee"; +} +.fa-cc-visa:before { + content: "\f1f0"; +} +.fa-cc-mastercard:before { + content: "\f1f1"; +} +.fa-cc-discover:before { + content: "\f1f2"; +} +.fa-cc-amex:before { + content: "\f1f3"; +} +.fa-cc-paypal:before { + content: "\f1f4"; +} +.fa-cc-stripe:before { + content: "\f1f5"; +} +.fa-bell-slash:before { + content: "\f1f6"; +} +.fa-bell-slash-o:before { + content: "\f1f7"; +} +.fa-trash:before { + content: "\f1f8"; +} +.fa-copyright:before { + content: "\f1f9"; +} +.fa-at:before { + content: "\f1fa"; +} +.fa-eyedropper:before { + content: "\f1fb"; +} +.fa-paint-brush:before { + content: "\f1fc"; +} +.fa-birthday-cake:before { + content: "\f1fd"; +} +.fa-area-chart:before { + content: "\f1fe"; +} +.fa-pie-chart:before { + content: "\f200"; +} +.fa-line-chart:before { + content: "\f201"; +} +.fa-lastfm:before { + content: "\f202"; +} +.fa-lastfm-square:before { + content: "\f203"; +} +.fa-toggle-off:before { + content: "\f204"; +} +.fa-toggle-on:before { + content: "\f205"; +} +.fa-bicycle:before { + content: "\f206"; +} +.fa-bus:before { + content: "\f207"; +} +.fa-ioxhost:before { + content: "\f208"; +} +.fa-angellist:before { + content: "\f209"; +} +.fa-cc:before { + content: "\f20a"; +} +.fa-shekel:before, +.fa-sheqel:before, +.fa-ils:before { + content: "\f20b"; +} +.fa-meanpath:before { + content: "\f20c"; +} +.fa-buysellads:before { + content: "\f20d"; +} +.fa-connectdevelop:before { + content: "\f20e"; +} +.fa-dashcube:before { + content: "\f210"; +} +.fa-forumbee:before { + content: "\f211"; +} +.fa-leanpub:before { + content: "\f212"; +} +.fa-sellsy:before { + content: "\f213"; +} +.fa-shirtsinbulk:before { + content: "\f214"; +} +.fa-simplybuilt:before { + content: "\f215"; +} +.fa-skyatlas:before { + content: "\f216"; +} +.fa-cart-plus:before { + content: "\f217"; +} +.fa-cart-arrow-down:before { + content: "\f218"; +} +.fa-diamond:before { + content: "\f219"; +} +.fa-ship:before { + content: "\f21a"; +} +.fa-user-secret:before { + content: "\f21b"; +} +.fa-motorcycle:before { + content: "\f21c"; +} +.fa-street-view:before { + content: "\f21d"; +} +.fa-heartbeat:before { + content: "\f21e"; +} +.fa-venus:before { + content: "\f221"; +} +.fa-mars:before { + content: "\f222"; +} +.fa-mercury:before { + content: "\f223"; +} +.fa-intersex:before, +.fa-transgender:before { + content: "\f224"; +} +.fa-transgender-alt:before { + content: "\f225"; +} +.fa-venus-double:before { + content: "\f226"; +} +.fa-mars-double:before { + content: "\f227"; +} +.fa-venus-mars:before { + content: "\f228"; +} +.fa-mars-stroke:before { + content: "\f229"; +} +.fa-mars-stroke-v:before { + content: "\f22a"; +} +.fa-mars-stroke-h:before { + content: "\f22b"; +} +.fa-neuter:before { + content: "\f22c"; +} +.fa-genderless:before { + content: "\f22d"; +} +.fa-facebook-official:before { + content: "\f230"; +} +.fa-pinterest-p:before { + content: "\f231"; +} +.fa-whatsapp:before { + content: "\f232"; +} +.fa-server:before { + content: "\f233"; +} +.fa-user-plus:before { + content: "\f234"; +} +.fa-user-times:before { + content: "\f235"; +} +.fa-hotel:before, +.fa-bed:before { + content: "\f236"; +} +.fa-viacoin:before { + content: "\f237"; +} +.fa-train:before { + content: "\f238"; +} +.fa-subway:before { + content: "\f239"; +} +.fa-medium:before { + content: "\f23a"; +} +.fa-yc:before, +.fa-y-combinator:before { + content: "\f23b"; +} +.fa-optin-monster:before { + content: "\f23c"; +} +.fa-opencart:before { + content: "\f23d"; +} +.fa-expeditedssl:before { + content: "\f23e"; +} +.fa-battery-4:before, +.fa-battery-full:before { + content: "\f240"; +} +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: "\f241"; +} +.fa-battery-2:before, +.fa-battery-half:before { + content: "\f242"; +} +.fa-battery-1:before, +.fa-battery-quarter:before { + content: "\f243"; +} +.fa-battery-0:before, +.fa-battery-empty:before { + content: "\f244"; +} +.fa-mouse-pointer:before { + content: "\f245"; +} +.fa-i-cursor:before { + content: "\f246"; +} +.fa-object-group:before { + content: "\f247"; +} +.fa-object-ungroup:before { + content: "\f248"; +} +.fa-sticky-note:before { + content: "\f249"; +} +.fa-sticky-note-o:before { + content: "\f24a"; +} +.fa-cc-jcb:before { + content: "\f24b"; +} +.fa-cc-diners-club:before { + content: "\f24c"; +} +.fa-clone:before { + content: "\f24d"; +} +.fa-balance-scale:before { + content: "\f24e"; +} +.fa-hourglass-o:before { + content: "\f250"; +} +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: "\f251"; +} +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: "\f252"; +} +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: "\f253"; +} +.fa-hourglass:before { + content: "\f254"; +} +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: "\f255"; +} +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: "\f256"; +} +.fa-hand-scissors-o:before { + content: "\f257"; +} +.fa-hand-lizard-o:before { + content: "\f258"; +} +.fa-hand-spock-o:before { + content: "\f259"; +} +.fa-hand-pointer-o:before { + content: "\f25a"; +} +.fa-hand-peace-o:before { + content: "\f25b"; +} +.fa-trademark:before { + content: "\f25c"; +} +.fa-registered:before { + content: "\f25d"; +} +.fa-creative-commons:before { + content: "\f25e"; +} +.fa-gg:before { + content: "\f260"; +} +.fa-gg-circle:before { + content: "\f261"; +} +.fa-tripadvisor:before { + content: "\f262"; +} +.fa-odnoklassniki:before { + content: "\f263"; +} +.fa-odnoklassniki-square:before { + content: "\f264"; +} +.fa-get-pocket:before { + content: "\f265"; +} +.fa-wikipedia-w:before { + content: "\f266"; +} +.fa-safari:before { + content: "\f267"; +} +.fa-chrome:before { + content: "\f268"; +} +.fa-firefox:before { + content: "\f269"; +} +.fa-opera:before { + content: "\f26a"; +} +.fa-internet-explorer:before { + content: "\f26b"; +} +.fa-tv:before, +.fa-television:before { + content: "\f26c"; +} +.fa-contao:before { + content: "\f26d"; +} +.fa-500px:before { + content: "\f26e"; +} +.fa-amazon:before { + content: "\f270"; +} +.fa-calendar-plus-o:before { + content: "\f271"; +} +.fa-calendar-minus-o:before { + content: "\f272"; +} +.fa-calendar-times-o:before { + content: "\f273"; +} +.fa-calendar-check-o:before { + content: "\f274"; +} +.fa-industry:before { + content: "\f275"; +} +.fa-map-pin:before { + content: "\f276"; +} +.fa-map-signs:before { + content: "\f277"; +} +.fa-map-o:before { + content: "\f278"; +} +.fa-map:before { + content: "\f279"; +} +.fa-commenting:before { + content: "\f27a"; +} +.fa-commenting-o:before { + content: "\f27b"; +} +.fa-houzz:before { + content: "\f27c"; +} +.fa-vimeo:before { + content: "\f27d"; +} +.fa-black-tie:before { + content: "\f27e"; +} +.fa-fonticons:before { + content: "\f280"; +} +.fa-reddit-alien:before { + content: "\f281"; +} +.fa-edge:before { + content: "\f282"; +} +.fa-credit-card-alt:before { + content: "\f283"; +} +.fa-codiepie:before { + content: "\f284"; +} +.fa-modx:before { + content: "\f285"; +} +.fa-fort-awesome:before { + content: "\f286"; +} +.fa-usb:before { + content: "\f287"; +} +.fa-product-hunt:before { + content: "\f288"; +} +.fa-mixcloud:before { + content: "\f289"; +} +.fa-scribd:before { + content: "\f28a"; +} +.fa-pause-circle:before { + content: "\f28b"; +} +.fa-pause-circle-o:before { + content: "\f28c"; +} +.fa-stop-circle:before { + content: "\f28d"; +} +.fa-stop-circle-o:before { + content: "\f28e"; +} +.fa-shopping-bag:before { + content: "\f290"; +} +.fa-shopping-basket:before { + content: "\f291"; +} +.fa-hashtag:before { + content: "\f292"; +} +.fa-bluetooth:before { + content: "\f293"; +} +.fa-bluetooth-b:before { + content: "\f294"; +} +.fa-percent:before { + content: "\f295"; +} diff --git a/public/font-awesome/css/font-awesome.min.css b/public/font-awesome/css/font-awesome.min.css index 24fcc04c4e..d0603cb4b0 100644 --- a/public/font-awesome/css/font-awesome.min.css +++ b/public/font-awesome/css/font-awesome.min.css @@ -1,4 +1,4 @@ /*! - * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"} \ No newline at end of file + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.5.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"} diff --git a/public/font-awesome/fonts/FontAwesome.otf b/public/font-awesome/fonts/FontAwesome.otf index f7936cc1e7..3ed7f8b48a 100644 Binary files a/public/font-awesome/fonts/FontAwesome.otf and b/public/font-awesome/fonts/FontAwesome.otf differ diff --git a/public/font-awesome/fonts/fontawesome-webfont.eot b/public/font-awesome/fonts/fontawesome-webfont.eot index 33b2bb8005..9b6afaedc0 100644 Binary files a/public/font-awesome/fonts/fontawesome-webfont.eot and b/public/font-awesome/fonts/fontawesome-webfont.eot differ diff --git a/public/font-awesome/fonts/fontawesome-webfont.svg b/public/font-awesome/fonts/fontawesome-webfont.svg index 1ee89d4368..d05688e9e2 100644 --- a/public/font-awesome/fonts/fontawesome-webfont.svg +++ b/public/font-awesome/fonts/fontawesome-webfont.svg @@ -1,6 +1,6 @@ - + @@ -219,8 +219,8 @@ - - + + @@ -362,7 +362,7 @@ - + @@ -399,7 +399,7 @@ - + @@ -410,9 +410,9 @@ - - - + + + @@ -454,12 +454,12 @@ - + - + @@ -483,13 +483,13 @@ - + - + @@ -523,7 +523,7 @@ - + @@ -531,18 +531,18 @@ - + - + - + - + @@ -555,11 +555,101 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/font-awesome/fonts/fontawesome-webfont.ttf b/public/font-awesome/fonts/fontawesome-webfont.ttf index ed9372f8ea..26dea7951a 100644 Binary files a/public/font-awesome/fonts/fontawesome-webfont.ttf and b/public/font-awesome/fonts/fontawesome-webfont.ttf differ diff --git a/public/font-awesome/fonts/fontawesome-webfont.woff b/public/font-awesome/fonts/fontawesome-webfont.woff index 8b280b98fa..dc35ce3c2c 100644 Binary files a/public/font-awesome/fonts/fontawesome-webfont.woff and b/public/font-awesome/fonts/fontawesome-webfont.woff differ diff --git a/public/font-awesome/fonts/fontawesome-webfont.woff2 b/public/font-awesome/fonts/fontawesome-webfont.woff2 index 3311d58514..500e517253 100644 Binary files a/public/font-awesome/fonts/fontawesome-webfont.woff2 and b/public/font-awesome/fonts/fontawesome-webfont.woff2 differ diff --git a/public/index.php b/public/index.php old mode 100644 new mode 100755 index 94d706ee68..c5820533bc --- a/public/index.php +++ b/public/index.php @@ -1,4 +1,5 @@ make('Illuminate\Contracts\Http\Kernel'); +$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); $response = $kernel->handle( $request = Illuminate\Http\Request::capture() @@ -55,5 +55,4 @@ $response = $kernel->handle( $response->send(); - $kernel->terminate($request, $response); diff --git a/public/js/accounts.js b/public/js/accounts.js index 14f5054583..80c908f7a9 100644 --- a/public/js/accounts.js +++ b/public/js/accounts.js @@ -2,12 +2,17 @@ // Return a helper with preserved width of cells -var fixHelper = function (e, ui) { +var fixHelper = function(e, tr) +{ "use strict"; - ui.children().each(function () { - $(this).width($(this).width()); + var $originals = tr.children(); + var $helper = tr.clone(); + $helper.children().each(function(index) + { + // Set helper cell sizes to match the original sizes + $(this).width($originals.eq(index).width()); }); - return ui; + return $helper; }; $(function () { @@ -80,4 +85,4 @@ function sortStop(event, ui) { //check if the item above OR under this one have the same date //if not. return false -} \ No newline at end of file +} diff --git a/public/js/jquery-ui.min.js b/public/js/jquery-ui.min.js index ed2b0cbfea..5824d1292d 100755 --- a/public/js/jquery-ui.min.js +++ b/public/js/jquery-ui.min.js @@ -1,7 +1,13 @@ -/*! jQuery UI - v1.11.4 - 2015-03-26 +/*! jQuery UI - v1.11.4 - 2015-03-11 * http://jqueryui.com -* Includes: core.js, widget.js, mouse.js, sortable.js, effect.js +* Includes: core.js, widget.js, mouse.js, position.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, draggable.js, droppable.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js, menu.js, progressbar.js, resizable.js, selectable.js, selectmenu.js, slider.js, sortable.js, spinner.js, tabs.js, tooltip.js * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ -(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var n,a,o,r=t.nodeName.toLowerCase();return"area"===r?(n=t.parentNode,a=n.name,t.href&&a&&"map"===n.nodeName.toLowerCase()?(o=e("img[usemap='#"+a+"']")[0],!!o&&i(o)):!1):(/^(input|select|textarea|button|object)$/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}e.ui=e.ui||{},e.extend(e.ui,{version:"1.11.4",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({scrollParent:function(t){var i=this.css("position"),s="absolute"===i,n=t?/(auto|scroll|hidden)/:/(auto|scroll)/,a=this.parents().filter(function(){var t=e(this);return s&&"static"===t.css("position")?!1:n.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==i&&a.length?a:e(this[0].ownerDocument||document)},uniqueId:function(){var e=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(i){return t(i,!isNaN(e.attr(i,"tabindex")))},tabbable:function(i){var s=e.attr(i,"tabindex"),n=isNaN(s);return(n||s>=0)&&t(i,!n)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(t,i){function s(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],a=i.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+i]=function(t){return void 0===t?o["inner"+i].call(this):this.each(function(){e(this).css(a,s(this,t)+"px")})},e.fn["outer"+i]=function(t,n){return"number"!=typeof t?o["outer"+i].call(this,t):this.each(function(){e(this).css(a,s(this,t,!0,n)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(void 0!==t)return this.css("zIndex",t);if(this.length)for(var i,s,n=e(this[0]);n.length&&n[0]!==document;){if(i=n.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0}}),e.ui.plugin={add:function(t,i,s){var n,a=e.ui[t].prototype;for(n in s)a.plugins[n]=a.plugins[n]||[],a.plugins[n].push([i,s[n]])},call:function(e,t,i,s){var n,a=e.plugins[t];if(a&&(s||e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType))for(n=0;a.length>n;n++)e.options[a[n][0]]&&a[n][1].apply(e.element,i)}};var s=0,n=Array.prototype.slice;e.cleanData=function(t){return function(i){var s,n,a;for(a=0;null!=(n=i[a]);a++)try{s=e._data(n,"events"),s&&s.remove&&e(n).triggerHandler("remove")}catch(o){}t(i)}}(e.cleanData),e.widget=function(t,i,s){var n,a,o,r,h={},l=t.split(".")[0];return t=t.split(".")[1],n=l+"-"+t,s||(s=i,i=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[l]=e[l]||{},a=e[l][t],o=e[l][t]=function(e,t){return this._createWidget?(arguments.length&&this._createWidget(e,t),void 0):new o(e,t)},e.extend(o,a,{version:s.version,_proto:e.extend({},s),_childConstructors:[]}),r=new i,r.options=e.widget.extend({},r.options),e.each(s,function(t,s){return e.isFunction(s)?(h[t]=function(){var e=function(){return i.prototype[t].apply(this,arguments)},n=function(e){return i.prototype[t].apply(this,e)};return function(){var t,i=this._super,a=this._superApply;return this._super=e,this._superApply=n,t=s.apply(this,arguments),this._super=i,this._superApply=a,t}}(),void 0):(h[t]=s,void 0)}),o.prototype=e.widget.extend(r,{widgetEventPrefix:a?r.widgetEventPrefix||t:t},h,{constructor:o,namespace:l,widgetName:t,widgetFullName:n}),a?(e.each(a._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete a._childConstructors):i._childConstructors.push(o),e.widget.bridge(t,o),o},e.widget.extend=function(t){for(var i,s,a=n.call(arguments,1),o=0,r=a.length;r>o;o++)for(i in a[o])s=a[o][i],a[o].hasOwnProperty(i)&&void 0!==s&&(t[i]=e.isPlainObject(s)?e.isPlainObject(t[i])?e.widget.extend({},t[i],s):e.widget.extend({},s):s);return t},e.widget.bridge=function(t,i){var s=i.prototype.widgetFullName||t;e.fn[t]=function(a){var o="string"==typeof a,r=n.call(arguments,1),h=this;return o?this.each(function(){var i,n=e.data(this,s);return"instance"===a?(h=n,!1):n?e.isFunction(n[a])&&"_"!==a.charAt(0)?(i=n[a].apply(n,r),i!==n&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):e.error("no such method '"+a+"' for "+t+" widget instance"):e.error("cannot call methods on "+t+" prior to initialization; "+"attempted to call method '"+a+"'")}):(r.length&&(a=e.widget.extend.apply(null,[a].concat(r))),this.each(function(){var t=e.data(this,s);t?(t.option(a||{}),t._init&&t._init()):e.data(this,s,new i(a,this))})),h}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(t,i){i=e(i||this.defaultElement||this)[0],this.element=e(i),this.uuid=s++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=e(),this.hoverable=e(),this.focusable=e(),i!==this&&(e.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===i&&this.destroy()}}),this.document=e(i.style?i.ownerDocument:i.document||i),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,i){var s,n,a,o=t;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof t)if(o={},s=t.split("."),t=s.shift(),s.length){for(n=o[t]=e.widget.extend({},this.options[t]),a=0;s.length-1>a;a++)n[s[a]]=n[s[a]]||{},n=n[s[a]];if(t=s.pop(),1===arguments.length)return void 0===n[t]?null:n[t];n[t]=i}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=i}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!t),t&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(t,i,s){var n,a=this;"boolean"!=typeof t&&(s=i,i=t,t=!1),s?(i=n=e(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),e.each(s,function(s,o){function r(){return t||a.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?a[o]:o).apply(a,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||e.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+a.eventNamespace,u=h[2];u?n.delegate(u,l,r):i.bind(l,r)})},_off:function(t,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(i).undelegate(i),this.bindings=e(this.bindings.not(t).get()),this.focusable=e(this.focusable.not(t).get()),this.hoverable=e(this.hoverable.not(t).get())},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,o=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var o,r=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),o=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),o&&e.effects&&e.effects.effect[r]?s[t](n):r!==t&&s[r]?s[r](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}}),e.widget;var a=!1;e(document).mouseup(function(){a=!1}),e.widget("ui.mouse",{version:"1.11.4",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(t){if(!a){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(t),this._mouseDownEvent=t;var i=this,s=1===t.which,n="string"==typeof this.options.cancel&&t.target.nodeName?e(t.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(t)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(t)!==!1,!this._mouseStarted)?(t.preventDefault(),!0):(!0===e.data(t.target,this.widgetName+".preventClickEvent")&&e.removeData(t.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return i._mouseMove(e)},this._mouseUpDelegate=function(e){return i._mouseUp(e)},this.document.bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),t.preventDefault(),a=!0,!0)):!0}},_mouseMove:function(t){if(this._mouseMoved){if(e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button)return this._mouseUp(t);if(!t.which)return this._mouseUp(t)}return(t.which||t.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),a=!1,!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),e.widget("ui.sortable",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(e,t,i){return e>=t&&t+i>e},_isFloating:function(e){return/left|right/.test(e.css("float"))||/inline|table-cell/.test(e.css("display"))},_create:function(){this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(e,t){this._super(e,t),"handle"===e&&this._setHandleClassName()},_setHandleClassName:function(){this.element.find(".ui-sortable-handle").removeClass("ui-sortable-handle"),e.each(this.items,function(){(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item).addClass("ui-sortable-handle")})},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").find(".ui-sortable-handle").removeClass("ui-sortable-handle"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(t,i){var s=null,n=!1,a=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(t),e(t.target).parents().each(function(){return e.data(this,a.widgetName+"-item")===a?(s=e(this),!1):void 0}),e.data(t.target,a.widgetName+"-item")===a&&(s=e(t.target)),s?!this.options.handle||i||(e(this.options.handle,s).find("*").addBack().each(function(){this===t.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(t,i,s){var n,a,o=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),o.containment&&this._setContainment(),o.cursor&&"auto"!==o.cursor&&(a=this.document.find("body"),this.storedCursor=a.css("cursor"),a.css("cursor",o.cursor),this.storedStylesheet=e("").appendTo(a)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!o.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){var i,s,n,a,o=this.options,r=!1;for(this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY=0;i--)if(s=this.items[i],n=s.item[0],a=this._intersectsWithPointer(s),a&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===a?"next":"prev"]()[0]!==n&&!e.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!e.contains(this.element[0],n):!0)){if(this.direction=1===a?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,i){if(t){if(e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t),this.options.revert){var s=this,n=this.placeholder.offset(),a=this.options.axis,o={};a&&"x"!==a||(o.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollLeft)),a&&"y"!==a||(o.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,e(this.helper).animate(o,parseInt(this.options.revert,10)||500,function(){s._clear(t)})}else this._clear(t,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},e(i).each(function(){var i=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[\-=_](.+)/);i&&s.push((t.key||i[1]+"[]")+"="+(t.key&&t.expression?i[1]:i[2]))}),!s.length&&t.key&&s.push(t.key+"="),s.join("&")},toArray:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},i.each(function(){s.push(e(t.item||this).attr(t.attribute||"id")||"")}),s},_intersectsWith:function(e){var t=this.positionAbs.left,i=t+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,a=e.left,o=a+e.width,r=e.top,h=r+e.height,l=this.offset.click.top,u=this.offset.click.left,d="x"===this.options.axis||s+l>r&&h>s+l,c="y"===this.options.axis||t+u>a&&o>t+u,p=d&&c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>e[this.floating?"width":"height"]?p:t+this.helperProportions.width/2>a&&o>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(e){var t="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top,e.height),i="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left,e.width),s=t&&i,n=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return s?this.floating?a&&"right"===a||"down"===n?2:1:n&&("down"===n?2:1):!1},_intersectsWithSides:function(e){var t=this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+e.height/2,e.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+e.width/2,e.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&t||"up"===s&&!t)},_getDragVerticalDirection:function(){var e=this.positionAbs.top-this.lastPositionAbs.top;return 0!==e&&(e>0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return 0!==e&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor===String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){function i(){r.push(this)}var s,n,a,o,r=[],h=[],l=this._connectWith();if(l&&t)for(s=l.length-1;s>=0;s--)for(a=e(l[s],this.document[0]),n=a.length-1;n>=0;n--)o=e.data(a[n],this.widgetFullName),o&&o!==this&&!o.options.disabled&&h.push([e.isFunction(o.options.items)?o.options.items.call(o.element):e(o.options.items,o.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),o]);for(h.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return e(r)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var i=0;t.length>i;i++)if(t[i]===e.item[0])return!1;return!0})},_refreshItems:function(t){this.items=[],this.containers=[this];var i,s,n,a,o,r,h,l,u=this.items,d=[[e.isFunction(this.options.items)?this.options.items.call(this.element[0],t,{item:this.currentItem}):e(this.options.items,this.element),this]],c=this._connectWith();if(c&&this.ready)for(i=c.length-1;i>=0;i--)for(n=e(c[i],this.document[0]),s=n.length-1;s>=0;s--)a=e.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&(d.push([e.isFunction(a.options.items)?a.options.items.call(a.element[0],t,{item:this.currentItem}):e(a.options.items,a.element),a]),this.containers.push(a));for(i=d.length-1;i>=0;i--)for(o=d[i][1],r=d[i][0],s=0,l=r.length;l>s;s++)h=e(r[s]),h.data(this.widgetName+"-item",o),u.push({item:h,instance:o,width:0,height:0,left:0,top:0})},refreshPositions:function(t){this.floating=this.items.length?"x"===this.options.axis||this._isFloating(this.items[0].item):!1,this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,a;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?e(this.options.toleranceElement,s.item):s.item,t||(s.width=n.outerWidth(),s.height=n.outerHeight()),a=n.offset(),s.left=a.left,s.top=a.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)a=this.containers[i].element.offset(),this.containers[i].containerCache.left=a.left,this.containers[i].containerCache.top=a.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(t){t=t||this;var i,s=t.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=t.currentItem[0].nodeName.toLowerCase(),n=e("<"+s+">",t.document[0]).addClass(i||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tbody"===s?t._createTrPlaceholder(t.currentItem.find("tr").eq(0),e("",t.document[0]).appendTo(n)):"tr"===s?t._createTrPlaceholder(t.currentItem,n):"img"===s&&n.attr("src",t.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(e,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10)))}}),t.placeholder=e(s.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),s.placeholder.update(t,t.placeholder)},_createTrPlaceholder:function(t,i){var s=this;t.children().each(function(){e(" ",s.document[0]).attr("colspan",e(this).attr("colspan")||1).appendTo(i)})},_contactContainers:function(t){var i,s,n,a,o,r,h,l,u,d,c=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!e.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(c&&e.contains(this.containers[i].element[0],c.element[0]))continue;c=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0);if(c)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,a=null,u=c.floating||this._isFloating(this.currentItem),o=u?"left":"top",r=u?"width":"height",d=u?"clientX":"clientY",s=this.items.length-1;s>=0;s--)e.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(h=this.items[s].item.offset()[o],l=!1,t[d]-h>this.items[s][r]/2&&(l=!0),n>Math.abs(t[d]-h)&&(n=Math.abs(t[d]-h),a=this.items[s],this.direction=l?"up":"down"));if(!a&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;a?this._rearrange(t,a,null,!0):this._rearrange(t,null,this.containers[p].element,!0),this._trigger("change",t,this._uiHash()),this.containers[p]._trigger("change",t,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||e("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===this.document[0].body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.currentItem.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,"document"===n.containment?this.document.width():this.window.width()-this.helperProportions.width-this.margins.left,("document"===n.containment?this.document.width():this.window.height()||this.document[0].body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(t=e(n.containment)[0],i=e(n.containment).offset(),s="hidden"!==e(t).css("overflow"),this.containment=[i.left+(parseInt(e(t).css("borderLeftWidth"),10)||0)+(parseInt(e(t).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(e(t).css("borderTopWidth"),10)||0)+(parseInt(e(t).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(t.scrollWidth,t.offsetWidth):t.offsetWidth)-(parseInt(e(t).css("borderLeftWidth"),10)||0)-(parseInt(e(t).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(t.scrollHeight,t.offsetHeight):t.offsetHeight)-(parseInt(e(t).css("borderTopWidth"),10)||0)-(parseInt(e(t).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]) -},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,a=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():a?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():a?0:n.scrollLeft())*s}},_generatePosition:function(t){var i,s,n=this.options,a=t.pageX,o=t.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(t.pageX-this.offset.click.leftthis.containment[2]&&(a=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1],o=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((a-this.originalPageX)/n.grid[0])*n.grid[0],a=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:a-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(e,t,i,s){i?i[0].appendChild(this.placeholder[0]):t.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?t.item[0]:t.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(e,t){function i(e,t,i){return function(s){i._trigger(e,s,t._uiHash(t))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!t&&n.push(function(e){this._trigger("receive",e,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||t||n.push(function(e){this._trigger("update",e,this._uiHash())}),this!==this.currentContainer&&(t||(n.push(function(e){this._trigger("remove",e,this._uiHash())}),n.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)t||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,t||this._trigger("beforeStop",e,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!t){for(s=0;n.length>s;s++)n[s].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){e.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(t){var i=t||this;return{helper:i.helper,placeholder:i.placeholder||e([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:t?t.element:null}}});var o="ui-effects-",r=e;e.effects={effect:{}},function(e,t){function i(e,t,i){var s=d[t.type]||{};return null==e?i||!t.def?null:t.def:(e=s.floor?~~e:parseFloat(e),isNaN(e)?t.def:s.mod?(e+s.mod)%s.mod:0>e?0:e>s.max?s.max:e)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(e,a){var o,r=a.re.exec(i),h=r&&a.parse(r),l=a.space||"rgba";return h?(o=s[l](h),s[u[l].cache]=o[u[l].cache],n=s._rgba=o._rgba,!1):t}),n.length?("0,0,0,0"===n.join()&&e.extend(n,a.transparent),s):a[i]}function n(e,t,i){return i=(i+1)%1,1>6*i?e+6*(t-e)*i:1>2*i?t:2>3*i?e+6*(t-e)*(2/3-i):e}var a,o="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(e){return[e[1],e[2],e[3],e[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(e){return[2.55*e[1],2.55*e[2],2.55*e[3],e[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(e){return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(e){return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(e){return[e[1],e[2]/100,e[3]/100,e[4]]}}],l=e.Color=function(t,i,s,n){return new e.Color.fn.parse(t,i,s,n)},u={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},d={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},c=l.support={},p=e("

")[0],f=e.each;p.style.cssText="background-color:rgba(1,1,1,.5)",c.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(u,function(e,t){t.cache="_"+e,t.props.alpha={idx:3,type:"percent",def:1}}),l.fn=e.extend(l.prototype,{parse:function(n,o,r,h){if(n===t)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=e(n).css(o),o=t);var d=this,c=e.type(n),p=this._rgba=[];return o!==t&&(n=[n,o,r,h],c="array"),"string"===c?this.parse(s(n)||a._default):"array"===c?(f(u.rgba.props,function(e,t){p[t.idx]=i(n[t.idx],t)}),this):"object"===c?(n instanceof l?f(u,function(e,t){n[t.cache]&&(d[t.cache]=n[t.cache].slice())}):f(u,function(t,s){var a=s.cache;f(s.props,function(e,t){if(!d[a]&&s.to){if("alpha"===e||null==n[e])return;d[a]=s.to(d._rgba)}d[a][t.idx]=i(n[e],t,!0)}),d[a]&&0>e.inArray(null,d[a].slice(0,3))&&(d[a][3]=1,s.from&&(d._rgba=s.from(d[a])))}),this):t},is:function(e){var i=l(e),s=!0,n=this;return f(u,function(e,a){var o,r=i[a.cache];return r&&(o=n[a.cache]||a.to&&a.to(n._rgba)||[],f(a.props,function(e,i){return null!=r[i.idx]?s=r[i.idx]===o[i.idx]:t})),s}),s},_space:function(){var e=[],t=this;return f(u,function(i,s){t[s.cache]&&e.push(i)}),e.pop()},transition:function(e,t){var s=l(e),n=s._space(),a=u[n],o=0===this.alpha()?l("transparent"):this,r=o[a.cache]||a.to(o._rgba),h=r.slice();return s=s[a.cache],f(a.props,function(e,n){var a=n.idx,o=r[a],l=s[a],u=d[n.type]||{};null!==l&&(null===o?h[a]=l:(u.mod&&(l-o>u.mod/2?o+=u.mod:o-l>u.mod/2&&(o-=u.mod)),h[a]=i((l-o)*t+o,n)))}),this[n](h)},blend:function(t){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(t)._rgba;return l(e.map(i,function(e,t){return(1-s)*n[t]+s*e}))},toRgbaString:function(){var t="rgba(",i=e.map(this._rgba,function(e,t){return null==e?t>2?1:0:e});return 1===i[3]&&(i.pop(),t="rgb("),t+i.join()+")"},toHslaString:function(){var t="hsla(",i=e.map(this.hsla(),function(e,t){return null==e&&(e=t>2?1:0),t&&3>t&&(e=Math.round(100*e)+"%"),e});return 1===i[3]&&(i.pop(),t="hsl("),t+i.join()+")"},toHexString:function(t){var i=this._rgba.slice(),s=i.pop();return t&&i.push(~~(255*s)),"#"+e.map(i,function(e){return e=(e||0).toString(16),1===e.length?"0"+e:e}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,u.hsla.to=function(e){if(null==e[0]||null==e[1]||null==e[2])return[null,null,null,e[3]];var t,i,s=e[0]/255,n=e[1]/255,a=e[2]/255,o=e[3],r=Math.max(s,n,a),h=Math.min(s,n,a),l=r-h,u=r+h,d=.5*u;return t=h===r?0:s===r?60*(n-a)/l+360:n===r?60*(a-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=d?l/u:l/(2-u),[Math.round(t)%360,i,d,null==o?1:o]},u.hsla.from=function(e){if(null==e[0]||null==e[1]||null==e[2])return[null,null,null,e[3]];var t=e[0]/360,i=e[1],s=e[2],a=e[3],o=.5>=s?s*(1+i):s+i-s*i,r=2*s-o;return[Math.round(255*n(r,o,t+1/3)),Math.round(255*n(r,o,t)),Math.round(255*n(r,o,t-1/3)),a]},f(u,function(s,n){var a=n.props,o=n.cache,h=n.to,u=n.from;l.fn[s]=function(s){if(h&&!this[o]&&(this[o]=h(this._rgba)),s===t)return this[o].slice();var n,r=e.type(s),d="array"===r||"object"===r?s:arguments,c=this[o].slice();return f(a,function(e,t){var s=d["object"===r?e:t.idx];null==s&&(s=c[t.idx]),c[t.idx]=i(s,t)}),u?(n=l(u(c)),n[o]=c,n):l(c)},f(a,function(t,i){l.fn[t]||(l.fn[t]=function(n){var a,o=e.type(n),h="alpha"===t?this._hsla?"hsla":"rgba":s,l=this[h](),u=l[i.idx];return"undefined"===o?u:("function"===o&&(n=n.call(this,u),o=e.type(n)),null==n&&i.empty?this:("string"===o&&(a=r.exec(n),a&&(n=u+parseFloat(a[2])*("+"===a[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(t){var i=t.split(" ");f(i,function(t,i){e.cssHooks[i]={set:function(t,n){var a,o,r="";if("transparent"!==n&&("string"!==e.type(n)||(a=s(n)))){if(n=l(a||n),!c.rgba&&1!==n._rgba[3]){for(o="backgroundColor"===i?t.parentNode:t;(""===r||"transparent"===r)&&o&&o.style;)try{r=e.css(o,"backgroundColor"),o=o.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{t.style[i]=n}catch(h){}}},e.fx.step[i]=function(t){t.colorInit||(t.start=l(t.elem,i),t.end=l(t.end),t.colorInit=!0),e.cssHooks[i].set(t.elem,t.start.transition(t.end,t.pos))}})},l.hook(o),e.cssHooks.borderColor={expand:function(e){var t={};return f(["Top","Right","Bottom","Left"],function(i,s){t["border"+s+"Color"]=e}),t}},a=e.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(r),function(){function t(t){var i,s,n=t.ownerDocument.defaultView?t.ownerDocument.defaultView.getComputedStyle(t,null):t.currentStyle,a={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(a[e.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(a[i]=n[i]);return a}function i(t,i){var s,a,o={};for(s in i)a=i[s],t[s]!==a&&(n[s]||(e.fx.step[s]||!isNaN(parseFloat(a)))&&(o[s]=a));return o}var s=["add","remove","toggle"],n={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};e.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(t,i){e.fx.step[i]=function(e){("none"!==e.end&&!e.setAttr||1===e.pos&&!e.setAttr)&&(r.style(e.elem,i,e.end),e.setAttr=!0)}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e.effects.animateClass=function(n,a,o,r){var h=e.speed(a,o,r);return this.queue(function(){var a,o=e(this),r=o.attr("class")||"",l=h.children?o.find("*").addBack():o;l=l.map(function(){var i=e(this);return{el:i,start:t(this)}}),a=function(){e.each(s,function(e,t){n[t]&&o[t+"Class"](n[t])})},a(),l=l.map(function(){return this.end=t(this.el[0]),this.diff=i(this.start,this.end),this}),o.attr("class",r),l=l.map(function(){var t=this,i=e.Deferred(),s=e.extend({},h,{queue:!1,complete:function(){i.resolve(t)}});return this.el.animate(this.diff,s),i.promise()}),e.when.apply(e,l.get()).done(function(){a(),e.each(arguments,function(){var t=this.el;e.each(this.diff,function(e){t.css(e,"")})}),h.complete.call(o[0])})})},e.fn.extend({addClass:function(t){return function(i,s,n,a){return s?e.effects.animateClass.call(this,{add:i},s,n,a):t.apply(this,arguments)}}(e.fn.addClass),removeClass:function(t){return function(i,s,n,a){return arguments.length>1?e.effects.animateClass.call(this,{remove:i},s,n,a):t.apply(this,arguments)}}(e.fn.removeClass),toggleClass:function(t){return function(i,s,n,a,o){return"boolean"==typeof s||void 0===s?n?e.effects.animateClass.call(this,s?{add:i}:{remove:i},n,a,o):t.apply(this,arguments):e.effects.animateClass.call(this,{toggle:i},s,n,a)}}(e.fn.toggleClass),switchClass:function(t,i,s,n,a){return e.effects.animateClass.call(this,{add:i,remove:t},s,n,a)}})}(),function(){function t(t,i,s,n){return e.isPlainObject(t)&&(i=t,t=t.effect),t={effect:t},null==i&&(i={}),e.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||e.fx.speeds[i])&&(n=s,s=i,i={}),e.isFunction(s)&&(n=s,s=null),i&&e.extend(t,i),s=s||i.duration,t.duration=e.fx.off?0:"number"==typeof s?s:s in e.fx.speeds?e.fx.speeds[s]:e.fx.speeds._default,t.complete=n||i.complete,t}function i(t){return!t||"number"==typeof t||e.fx.speeds[t]?!0:"string"!=typeof t||e.effects.effect[t]?e.isFunction(t)?!0:"object"!=typeof t||t.effect?!1:!0:!0}e.extend(e.effects,{version:"1.11.4",save:function(e,t){for(var i=0;t.length>i;i++)null!==t[i]&&e.data(o+t[i],e[0].style[t[i]])},restore:function(e,t){var i,s;for(s=0;t.length>s;s++)null!==t[s]&&(i=e.data(o+t[s]),void 0===i&&(i=""),e.css(t[s],i))},setMode:function(e,t){return"toggle"===t&&(t=e.is(":hidden")?"show":"hide"),t},getBaseline:function(e,t){var i,s;switch(e[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=e[0]/t.height}switch(e[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=e[1]/t.width}return{x:s,y:i}},createWrapper:function(t){if(t.parent().is(".ui-effects-wrapper"))return t.parent();var i={width:t.outerWidth(!0),height:t.outerHeight(!0),"float":t.css("float")},s=e("

").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:t.width(),height:t.height()},a=document.activeElement;try{a.id}catch(o){a=document.body}return t.wrap(s),(t[0]===a||e.contains(t[0],a))&&e(a).focus(),s=t.parent(),"static"===t.css("position")?(s.css({position:"relative"}),t.css({position:"relative"})):(e.extend(i,{position:t.css("position"),zIndex:t.css("z-index")}),e.each(["top","left","bottom","right"],function(e,s){i[s]=t.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),t.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),t.css(n),s.css(i).show()},removeWrapper:function(t){var i=document.activeElement;return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),(t[0]===i||e.contains(t[0],i))&&e(i).focus()),t},setTransition:function(t,i,s,n){return n=n||{},e.each(i,function(e,i){var a=t.cssUnit(i);a[0]>0&&(n[i]=a[0]*s+a[1])}),n}}),e.fn.extend({effect:function(){function i(t){function i(){e.isFunction(a)&&a.call(n[0]),e.isFunction(t)&&t()}var n=e(this),a=s.complete,r=s.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),i()):o.call(n[0],s,i)}var s=t.apply(this,arguments),n=s.mode,a=s.queue,o=e.effects.effect[s.effect];return e.fx.off||!o?n?this[n](s.duration,s.complete):this.each(function(){s.complete&&s.complete.call(this)}):a===!1?this.each(i):this.queue(a||"fx",i)},show:function(e){return function(s){if(i(s))return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="show",this.effect.call(this,n)}}(e.fn.show),hide:function(e){return function(s){if(i(s))return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="hide",this.effect.call(this,n)}}(e.fn.hide),toggle:function(e){return function(s){if(i(s)||"boolean"==typeof s)return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)}}(e.fn.toggle),cssUnit:function(t){var i=this.css(t),s=[];return e.each(["em","px","%","pt"],function(e,t){i.indexOf(t)>0&&(s=[parseFloat(i),t])}),s}})}(),function(){var t={};e.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,i){t[i]=function(t){return Math.pow(t,e+2)}}),e.extend(t,{Sine:function(e){return 1-Math.cos(e*Math.PI/2)},Circ:function(e){return 1-Math.sqrt(1-e*e)},Elastic:function(e){return 0===e||1===e?e:-Math.pow(2,8*(e-1))*Math.sin((80*(e-1)-7.5)*Math.PI/15)},Back:function(e){return e*e*(3*e-2)},Bounce:function(e){for(var t,i=4;((t=Math.pow(2,--i))-1)/11>e;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*t-2)/22-e,2)}}),e.each(t,function(t,i){e.easing["easeIn"+t]=i,e.easing["easeOut"+t]=function(e){return 1-i(1-e)},e.easing["easeInOut"+t]=function(e){return.5>e?i(2*e)/2:1-i(-2*e+2)/2}})}(),e.effects}); \ No newline at end of file +(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var n,a,o,r=t.nodeName.toLowerCase();return"area"===r?(n=t.parentNode,a=n.name,t.href&&a&&"map"===n.nodeName.toLowerCase()?(o=e("img[usemap='#"+a+"']")[0],!!o&&i(o)):!1):(/^(input|select|textarea|button|object)$/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}function s(e){for(var t,i;e.length&&e[0]!==document;){if(t=e.css("position"),("absolute"===t||"relative"===t||"fixed"===t)&&(i=parseInt(e.css("zIndex"),10),!isNaN(i)&&0!==i))return i;e=e.parent()}return 0}function n(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},e.extend(this._defaults,this.regional[""]),this.regional.en=e.extend(!0,{},this.regional[""]),this.regional["en-US"]=e.extend(!0,{},this.regional.en),this.dpDiv=a(e("
"))}function a(t){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return t.delegate(i,"mouseout",function(){e(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",o)}function o(){e.datepicker._isDisabledDatepicker(v.inline?v.dpDiv.parent()[0]:v.input[0])||(e(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),e(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).addClass("ui-datepicker-next-hover"))}function r(t,i){e.extend(t,i);for(var s in i)null==i[s]&&(t[s]=i[s]);return t}function h(e){return function(){var t=this.element.val();e.apply(this,arguments),this._refresh(),t!==this.element.val()&&this._trigger("change")}}e.ui=e.ui||{},e.extend(e.ui,{version:"1.11.4",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({scrollParent:function(t){var i=this.css("position"),s="absolute"===i,n=t?/(auto|scroll|hidden)/:/(auto|scroll)/,a=this.parents().filter(function(){var t=e(this);return s&&"static"===t.css("position")?!1:n.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==i&&a.length?a:e(this[0].ownerDocument||document)},uniqueId:function(){var e=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(i){return t(i,!isNaN(e.attr(i,"tabindex")))},tabbable:function(i){var s=e.attr(i,"tabindex"),n=isNaN(s);return(n||s>=0)&&t(i,!n)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(t,i){function s(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],a=i.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+i]=function(t){return void 0===t?o["inner"+i].call(this):this.each(function(){e(this).css(a,s(this,t)+"px")})},e.fn["outer"+i]=function(t,n){return"number"!=typeof t?o["outer"+i].call(this,t):this.each(function(){e(this).css(a,s(this,t,!0,n)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(void 0!==t)return this.css("zIndex",t);if(this.length)for(var i,s,n=e(this[0]);n.length&&n[0]!==document;){if(i=n.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0}}),e.ui.plugin={add:function(t,i,s){var n,a=e.ui[t].prototype;for(n in s)a.plugins[n]=a.plugins[n]||[],a.plugins[n].push([i,s[n]])},call:function(e,t,i,s){var n,a=e.plugins[t];if(a&&(s||e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType))for(n=0;a.length>n;n++)e.options[a[n][0]]&&a[n][1].apply(e.element,i)}};var l=0,u=Array.prototype.slice;e.cleanData=function(t){return function(i){var s,n,a;for(a=0;null!=(n=i[a]);a++)try{s=e._data(n,"events"),s&&s.remove&&e(n).triggerHandler("remove")}catch(o){}t(i)}}(e.cleanData),e.widget=function(t,i,s){var n,a,o,r,h={},l=t.split(".")[0];return t=t.split(".")[1],n=l+"-"+t,s||(s=i,i=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[l]=e[l]||{},a=e[l][t],o=e[l][t]=function(e,t){return this._createWidget?(arguments.length&&this._createWidget(e,t),void 0):new o(e,t)},e.extend(o,a,{version:s.version,_proto:e.extend({},s),_childConstructors:[]}),r=new i,r.options=e.widget.extend({},r.options),e.each(s,function(t,s){return e.isFunction(s)?(h[t]=function(){var e=function(){return i.prototype[t].apply(this,arguments)},n=function(e){return i.prototype[t].apply(this,e)};return function(){var t,i=this._super,a=this._superApply;return this._super=e,this._superApply=n,t=s.apply(this,arguments),this._super=i,this._superApply=a,t}}(),void 0):(h[t]=s,void 0)}),o.prototype=e.widget.extend(r,{widgetEventPrefix:a?r.widgetEventPrefix||t:t},h,{constructor:o,namespace:l,widgetName:t,widgetFullName:n}),a?(e.each(a._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete a._childConstructors):i._childConstructors.push(o),e.widget.bridge(t,o),o},e.widget.extend=function(t){for(var i,s,n=u.call(arguments,1),a=0,o=n.length;o>a;a++)for(i in n[a])s=n[a][i],n[a].hasOwnProperty(i)&&void 0!==s&&(t[i]=e.isPlainObject(s)?e.isPlainObject(t[i])?e.widget.extend({},t[i],s):e.widget.extend({},s):s);return t},e.widget.bridge=function(t,i){var s=i.prototype.widgetFullName||t;e.fn[t]=function(n){var a="string"==typeof n,o=u.call(arguments,1),r=this;return a?this.each(function(){var i,a=e.data(this,s);return"instance"===n?(r=a,!1):a?e.isFunction(a[n])&&"_"!==n.charAt(0)?(i=a[n].apply(a,o),i!==a&&void 0!==i?(r=i&&i.jquery?r.pushStack(i.get()):i,!1):void 0):e.error("no such method '"+n+"' for "+t+" widget instance"):e.error("cannot call methods on "+t+" prior to initialization; "+"attempted to call method '"+n+"'")}):(o.length&&(n=e.widget.extend.apply(null,[n].concat(o))),this.each(function(){var t=e.data(this,s);t?(t.option(n||{}),t._init&&t._init()):e.data(this,s,new i(n,this))})),r}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(t,i){i=e(i||this.defaultElement||this)[0],this.element=e(i),this.uuid=l++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=e(),this.hoverable=e(),this.focusable=e(),i!==this&&(e.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===i&&this.destroy()}}),this.document=e(i.style?i.ownerDocument:i.document||i),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,i){var s,n,a,o=t;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof t)if(o={},s=t.split("."),t=s.shift(),s.length){for(n=o[t]=e.widget.extend({},this.options[t]),a=0;s.length-1>a;a++)n[s[a]]=n[s[a]]||{},n=n[s[a]];if(t=s.pop(),1===arguments.length)return void 0===n[t]?null:n[t];n[t]=i}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=i}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!t),t&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(t,i,s){var n,a=this;"boolean"!=typeof t&&(s=i,i=t,t=!1),s?(i=n=e(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),e.each(s,function(s,o){function r(){return t||a.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?a[o]:o).apply(a,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||e.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+a.eventNamespace,u=h[2];u?n.delegate(u,l,r):i.bind(l,r)})},_off:function(t,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(i).undelegate(i),this.bindings=e(this.bindings.not(t).get()),this.focusable=e(this.focusable.not(t).get()),this.hoverable=e(this.hoverable.not(t).get())},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,o=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var o,r=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),o=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),o&&e.effects&&e.effects.effect[r]?s[t](n):r!==t&&s[r]?s[r](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}}),e.widget;var d=!1;e(document).mouseup(function(){d=!1}),e.widget("ui.mouse",{version:"1.11.4",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(t){if(!d){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(t),this._mouseDownEvent=t;var i=this,s=1===t.which,n="string"==typeof this.options.cancel&&t.target.nodeName?e(t.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(t)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(t)!==!1,!this._mouseStarted)?(t.preventDefault(),!0):(!0===e.data(t.target,this.widgetName+".preventClickEvent")&&e.removeData(t.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return i._mouseMove(e)},this._mouseUpDelegate=function(e){return i._mouseUp(e)},this.document.bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),t.preventDefault(),d=!0,!0)):!0}},_mouseMove:function(t){if(this._mouseMoved){if(e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button)return this._mouseUp(t);if(!t.which)return this._mouseUp(t)}return(t.which||t.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),d=!1,!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),function(){function t(e,t,i){return[parseFloat(e[0])*(p.test(e[0])?t/100:1),parseFloat(e[1])*(p.test(e[1])?i/100:1)]}function i(t,i){return parseInt(e.css(t,i),10)||0}function s(t){var i=t[0];return 9===i.nodeType?{width:t.width(),height:t.height(),offset:{top:0,left:0}}:e.isWindow(i)?{width:t.width(),height:t.height(),offset:{top:t.scrollTop(),left:t.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:t.outerWidth(),height:t.outerHeight(),offset:t.offset()}}e.ui=e.ui||{};var n,a,o=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,u=/top|center|bottom/,d=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,p=/%$/,f=e.fn.position;e.position={scrollbarWidth:function(){if(void 0!==n)return n;var t,i,s=e("
"),a=s.children()[0];return e("body").append(s),t=a.offsetWidth,s.css("overflow","scroll"),i=a.offsetWidth,t===i&&(i=s[0].clientWidth),s.remove(),n=t-i},getScrollInfo:function(t){var i=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),s=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),n="scroll"===i||"auto"===i&&t.widthi?"left":t>0?"right":"center",vertical:0>a?"top":s>0?"bottom":"middle"};d>m&&m>r(t+i)&&(h.horizontal="center"),c>g&&g>r(s+a)&&(h.vertical="middle"),h.important=o(r(t),r(i))>o(r(s),r(a))?"horizontal":"vertical",n.using.call(this,e,h)}),u.offset(e.extend(M,{using:l}))})},e.ui.position={fit:{left:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=e.left-t.collisionPosition.marginLeft,h=n-r,l=r+t.collisionWidth-a-n;t.collisionWidth>a?h>0&&0>=l?(i=e.left+h+t.collisionWidth-a-n,e.left+=h-i):e.left=l>0&&0>=h?n:h>l?n+a-t.collisionWidth:n:h>0?e.left+=h:l>0?e.left-=l:e.left=o(e.left-r,e.left)},top:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollTop:s.offset.top,a=t.within.height,r=e.top-t.collisionPosition.marginTop,h=n-r,l=r+t.collisionHeight-a-n;t.collisionHeight>a?h>0&&0>=l?(i=e.top+h+t.collisionHeight-a-n,e.top+=h-i):e.top=l>0&&0>=h?n:h>l?n+a-t.collisionHeight:n:h>0?e.top+=h:l>0?e.top-=l:e.top=o(e.top-r,e.top)}},flip:{left:function(e,t){var i,s,n=t.within,a=n.offset.left+n.scrollLeft,o=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=e.left-t.collisionPosition.marginLeft,u=l-h,d=l+t.collisionWidth-o-h,c="left"===t.my[0]?-t.elemWidth:"right"===t.my[0]?t.elemWidth:0,p="left"===t.at[0]?t.targetWidth:"right"===t.at[0]?-t.targetWidth:0,f=-2*t.offset[0];0>u?(i=e.left+c+p+f+t.collisionWidth-o-a,(0>i||r(u)>i)&&(e.left+=c+p+f)):d>0&&(s=e.left-t.collisionPosition.marginLeft+c+p+f-h,(s>0||d>r(s))&&(e.left+=c+p+f))},top:function(e,t){var i,s,n=t.within,a=n.offset.top+n.scrollTop,o=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=e.top-t.collisionPosition.marginTop,u=l-h,d=l+t.collisionHeight-o-h,c="top"===t.my[1],p=c?-t.elemHeight:"bottom"===t.my[1]?t.elemHeight:0,f="top"===t.at[1]?t.targetHeight:"bottom"===t.at[1]?-t.targetHeight:0,m=-2*t.offset[1];0>u?(s=e.top+p+f+m+t.collisionHeight-o-a,(0>s||r(u)>s)&&(e.top+=p+f+m)):d>0&&(i=e.top-t.collisionPosition.marginTop+p+f+m-h,(i>0||d>r(i))&&(e.top+=p+f+m))}},flipfit:{left:function(){e.ui.position.flip.left.apply(this,arguments),e.ui.position.fit.left.apply(this,arguments)},top:function(){e.ui.position.flip.top.apply(this,arguments),e.ui.position.fit.top.apply(this,arguments)}}},function(){var t,i,s,n,o,r=document.getElementsByTagName("body")[0],h=document.createElement("div");t=document.createElement(r?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},r&&e.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)t.style[o]=s[o];t.appendChild(h),i=r||document.documentElement,i.insertBefore(t,i.firstChild),h.style.cssText="position: absolute; left: 10.7432222px;",n=e(h).offset().left,a=n>10&&11>n,t.innerHTML="",i.removeChild(t)}()}(),e.ui.position,e.widget("ui.accordion",{version:"1.11.4",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var t=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),t.collapsible||t.active!==!1&&null!=t.active||(t.active=0),this._processPanels(),0>t.active&&(t.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").removeUniqueId(),this._destroyIcons(),e=this.headers.next().removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").css("display","").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&e.css("height","")},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):("event"===e&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),"collapsible"!==e||t||this.options.active!==!1||this._activate(0),"icons"===e&&(this._destroyIcons(),t&&this._createIcons()),"disabled"===e&&(this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)),void 0)},_keydown:function(t){if(!t.altKey&&!t.ctrlKey){var i=e.ui.keyCode,s=this.headers.length,n=this.headers.index(t.target),a=!1;switch(t.keyCode){case i.RIGHT:case i.DOWN:a=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:a=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(t);break;case i.HOME:a=this.headers[0];break;case i.END:a=this.headers[s-1]}a&&(e(t.target).attr("tabIndex",-1),e(a).attr("tabIndex",0),a.focus(),t.preventDefault())}},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t=this.options;this._processPanels(),t.active===!1&&t.collapsible===!0||!this.headers.length?(t.active=!1,this.active=e()):t.active===!1?this._activate(0):this.active.length&&!e.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(t.active=!1,this.active=e()):this._activate(Math.max(0,t.active-1)):t.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var e=this.headers,t=this.panels;this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-state-default ui-corner-all"),this.panels=this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide(),t&&(this._off(e.not(this.headers)),this._off(t.not(this.panels)))},_refresh:function(){var t,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(){var t=e(this),i=t.uniqueId().attr("id"),s=t.next(),n=s.uniqueId().attr("id");t.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(i.event),"fill"===s?(t=n.height(),this.element.siblings(":visible").each(function(){var i=e(this),s=i.css("position");"absolute"!==s&&"fixed"!==s&&(t-=i.outerHeight(!0))}),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===s&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).css("height","").height())}).height(t))},_activate:function(t){var i=this._findActive(t)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return"number"==typeof t?this.headers.eq(t):e()},_setupEvents:function(t){var i={keydown:"_keydown"};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n[0]===s[0],o=a&&i.collapsible,r=o?e():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:o?e():n,newPanel:r};t.preventDefault(),a&&!i.collapsible||this._trigger("beforeActivate",t,l)===!1||(i.active=o?!1:this.headers.index(n),this.active=a?e():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),a||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(t){var i=t.newPanel,s=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,t):(s.hide(),i.show(),this._toggleComplete(t)),s.attr({"aria-hidden":"true"}),s.prev().attr({"aria-selected":"false","aria-expanded":"false"}),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===parseInt(e(this).attr("tabIndex"),10)}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_animate:function(e,t,i){var s,n,a,o=this,r=0,h=e.css("box-sizing"),l=e.length&&(!t.length||e.index()",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},items:"> *",menus:"ul",position:{my:"left-1 top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item":function(e){e.preventDefault()},"click .ui-menu-item":function(t){var i=e(t.target);!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&e(this.document[0].activeElement).closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){if(!this.previousFilter){var i=e(t.currentTarget); +i.siblings(".ui-state-active").removeClass("ui-state-active"),this.focus(t,i)}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(e,t){var i=this.active||this.element.find(this.options.items).eq(0);t||this.focus(e,i)},blur:function(t){this._delay(function(){e.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){this._closeOnDocumentClick(e)&&this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-menu-icons ui-front").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").removeUniqueId().removeClass("ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var t=e(this);t.data("ui-menu-submenu-carat")&&t.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(t){var i,s,n,a,o=!0;switch(t.keyCode){case e.ui.keyCode.PAGE_UP:this.previousPage(t);break;case e.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case e.ui.keyCode.HOME:this._move("first","first",t);break;case e.ui.keyCode.END:this._move("last","last",t);break;case e.ui.keyCode.UP:this.previous(t);break;case e.ui.keyCode.DOWN:this.next(t);break;case e.ui.keyCode.LEFT:this.collapse(t);break;case e.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case e.ui.keyCode.ENTER:case e.ui.keyCode.SPACE:this._activate(t);break;case e.ui.keyCode.ESCAPE:this.collapse(t);break;default:o=!1,s=this.previousFilter||"",n=String.fromCharCode(t.keyCode),a=!1,clearTimeout(this.filterTimer),n===s?a=!0:n=s+n,i=this._filterMenuItems(n),i=a&&-1!==i.index(this.active.next())?this.active.nextAll(".ui-menu-item"):i,i.length||(n=String.fromCharCode(t.keyCode),i=this._filterMenuItems(n)),i.length?(this.focus(t,i),this.previousFilter=n,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}o&&t.preventDefault()},_activate:function(e){this.active.is(".ui-state-disabled")||(this.active.is("[aria-haspopup='true']")?this.expand(e):this.select(e))},refresh:function(){var t,i,s=this,n=this.options.icons.submenu,a=this.element.find(this.options.menus);this.element.toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length),a.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-front").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=e(this),i=t.parent(),s=e("").addClass("ui-menu-icon ui-icon "+n).data("ui-menu-submenu-carat",!0);i.attr("aria-haspopup","true").prepend(s),t.attr("aria-labelledby",i.attr("id"))}),t=a.add(this.element),i=t.find(this.options.items),i.not(".ui-menu-item").each(function(){var t=e(this);s._isDivider(t)&&t.addClass("ui-widget-content ui-menu-divider")}),i.not(".ui-menu-item, .ui-menu-divider").addClass("ui-menu-item").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),i.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!e.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(e,t){"icons"===e&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(t.submenu),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},focus:function(e,t){var i,s;this.blur(e,e&&"focus"===e.type),this._scrollIntoView(t),this.active=t.first(),s=this.active.addClass("ui-state-focus").removeClass("ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").addClass("ui-state-active"),e&&"keydown"===e.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=t.children(".ui-menu"),i.length&&e&&/^mouse/.test(e.type)&&this._startOpening(i),this.activeMenu=t.parent(),this._trigger("focus",e,{item:t})},_scrollIntoView:function(t){var i,s,n,a,o,r;this._hasScroll()&&(i=parseFloat(e.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(e.css(this.activeMenu[0],"paddingTop"))||0,n=t.offset().top-this.activeMenu.offset().top-i-s,a=this.activeMenu.scrollTop(),o=this.activeMenu.height(),r=t.outerHeight(),0>n?this.activeMenu.scrollTop(a+n):n+r>o&&this.activeMenu.scrollTop(a+n-o+r))},blur:function(e,t){t||clearTimeout(this.timer),this.active&&(this.active.removeClass("ui-state-focus"),this.active=null,this._trigger("blur",e,{item:this.active}))},_startOpening:function(e){clearTimeout(this.timer),"true"===e.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(e)},this.delay))},_open:function(t){var i=e.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(t,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:e(t&&t.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(t),this.activeMenu=s},this.delay)},_close:function(e){e||(e=this.active?this.active.parent():this.element),e.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find(".ui-state-active").not(".ui-state-focus").removeClass("ui-state-active")},_closeOnDocumentClick:function(t){return!e(t.target).closest(".ui-menu").length},_isDivider:function(e){return!/[^\-\u2014\u2013\s]/.test(e.text())},collapse:function(e){var t=this.active&&this.active.parent().closest(".ui-menu-item",this.element);t&&t.length&&(this._close(),this.focus(e,t))},expand:function(e){var t=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();t&&t.length&&(this._open(t.parent()),this._delay(function(){this.focus(e,t)}))},next:function(e){this._move("next","first",e)},previous:function(e){this._move("prev","last",e)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(e,t,i){var s;this.active&&(s="first"===e||"last"===e?this.active["first"===e?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[e+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.find(this.options.items)[t]()),this.focus(i,s)},nextPage:function(t){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=e(this),0>i.offset().top-s-n}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items)[this.active?"last":"first"]())),void 0):(this.next(t),void 0)},previousPage:function(t){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=e(this),i.offset().top-s+n>0}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items).first())),void 0):(this.next(t),void 0)},_hasScroll:function(){return this.element.outerHeight()",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var t,i,s,n=this.element[0].nodeName.toLowerCase(),a="textarea"===n,o="input"===n;this.isMultiLine=a?!0:o?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[a||o?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return t=!0,s=!0,i=!0,void 0;t=!1,s=!1,i=!1;var a=e.ui.keyCode;switch(n.keyCode){case a.PAGE_UP:t=!0,this._move("previousPage",n);break;case a.PAGE_DOWN:t=!0,this._move("nextPage",n);break;case a.UP:t=!0,this._keyEvent("previous",n);break;case a.DOWN:t=!0,this._keyEvent("next",n);break;case a.ENTER:this.menu.active&&(t=!0,n.preventDefault(),this.menu.select(n));break;case a.TAB:this.menu.active&&this.menu.select(n);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(t)return t=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),void 0;if(!i){var n=e.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(e){return s?(s=!1,e.preventDefault(),void 0):(this._searchTimeout(e),void 0)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(clearTimeout(this.searching),this.close(e),this._change(e),void 0)}}),this._initSource(),this.menu=e("
    ").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({role:null}).hide().menu("instance"),this._on(this.menu.element,{mousedown:function(t){t.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];e(t.target).closest(".ui-menu-item").length||this._delay(function(){var t=this;this.document.one("mousedown",function(s){s.target===t.element[0]||s.target===i||e.contains(i,s.target)||t.close()})})},menufocus:function(t,i){var s,n;return this.isNewMenu&&(this.isNewMenu=!1,t.originalEvent&&/^mouse/.test(t.originalEvent.type))?(this.menu.blur(),this.document.one("mousemove",function(){e(t.target).trigger(t.originalEvent)}),void 0):(n=i.item.data("ui-autocomplete-item"),!1!==this._trigger("focus",t,{item:n})&&t.originalEvent&&/^key/.test(t.originalEvent.type)&&this._value(n.value),s=i.item.attr("aria-label")||n.value,s&&e.trim(s).length&&(this.liveRegion.children().hide(),e("
    ").text(s).appendTo(this.liveRegion)),void 0)},menuselect:function(e,t){var i=t.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",e,{item:i})&&this._value(i.value),this.term=this._value(),this.close(e),this.selectedItem=i}}),this.liveRegion=e("",{role:"status","aria-live":"assertive","aria-relevant":"additions"}).addClass("ui-helper-hidden-accessible").appendTo(this.document[0].body),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(e,t){this._super(e,t),"source"===e&&this._initSource(),"appendTo"===e&&this.menu.element.appendTo(this._appendTo()),"disabled"===e&&t&&this.xhr&&this.xhr.abort()},_appendTo:function(){var t=this.options.appendTo;return t&&(t=t.jquery||t.nodeType?e(t):this.document.find(t).eq(0)),t&&t[0]||(t=this.element.closest(".ui-front")),t.length||(t=this.document[0].body),t},_initSource:function(){var t,i,s=this;e.isArray(this.options.source)?(t=this.options.source,this.source=function(i,s){s(e.ui.autocomplete.filter(t,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(t,n){s.xhr&&s.xhr.abort(),s.xhr=e.ajax({url:i,data:t,dataType:"json",success:function(e){n(e)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(e){clearTimeout(this.searching),this.searching=this._delay(function(){var t=this.term===this._value(),i=this.menu.element.is(":visible"),s=e.altKey||e.ctrlKey||e.metaKey||e.shiftKey;(!t||t&&!i&&!s)&&(this.selectedItem=null,this.search(null,e))},this.options.delay)},search:function(e,t){return e=null!=e?e:this._value(),this.term=this._value(),e.length").text(i.label).appendTo(t)},_move:function(e,t){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(e)||this.menu.isLastItem()&&/^next/.test(e)?(this.isMultiLine||this._value(this.term),this.menu.blur(),void 0):(this.menu[e](t),void 0):(this.search(null,t),void 0)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(e,t){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(e,t),t.preventDefault())}}),e.extend(e.ui.autocomplete,{escapeRegex:function(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(t,i){var s=RegExp(e.ui.autocomplete.escapeRegex(i),"i");return e.grep(t,function(e){return s.test(e.label||e.value||e)})}}),e.widget("ui.autocomplete",e.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(e){return e+(e>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var i;this._superApply(arguments),this.options.disabled||this.cancelSearch||(i=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,this.liveRegion.children().hide(),e("
    ").text(i).appendTo(this.liveRegion))}}),e.ui.autocomplete;var c,p="ui-button ui-widget ui-state-default ui-corner-all",f="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",m=function(){var t=e(this);setTimeout(function(){t.find(":ui-button").button("refresh")},1)},g=function(t){var i=t.name,s=t.form,n=e([]);return i&&(i=i.replace(/'/g,"\\'"),n=s?e(s).find("[name='"+i+"'][type=radio]"):e("[name='"+i+"'][type=radio]",t.ownerDocument).filter(function(){return!this.form})),n};e.widget("ui.button",{version:"1.11.4",defaultElement:"").addClass(this._triggerClass).html(a?e("").attr({src:a,alt:n,title:n}):n)),t[r?"before":"after"](i.trigger),i.trigger.click(function(){return e.datepicker._datepickerShowing&&e.datepicker._lastInput===t[0]?e.datepicker._hideDatepicker():e.datepicker._datepickerShowing&&e.datepicker._lastInput!==t[0]?(e.datepicker._hideDatepicker(),e.datepicker._showDatepicker(t[0])):e.datepicker._showDatepicker(t[0]),!1}))},_autoSize:function(e){if(this._get(e,"autoSize")&&!e.inline){var t,i,s,n,a=new Date(2009,11,20),o=this._get(e,"dateFormat");o.match(/[DM]/)&&(t=function(e){for(i=0,s=0,n=0;e.length>n;n++)e[n].length>i&&(i=e[n].length,s=n);return s},a.setMonth(t(this._get(e,o.match(/MM/)?"monthNames":"monthNamesShort"))),a.setDate(t(this._get(e,o.match(/DD/)?"dayNames":"dayNamesShort"))+20-a.getDay())),e.input.attr("size",this._formatDate(e,a).length)}},_inlineDatepicker:function(t,i){var s=e(t);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),e.data(t,"datepicker",i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(t),i.dpDiv.css("display","block"))},_dialogDatepicker:function(t,i,s,n,a){var o,h,l,u,d,c=this._dialogInst;return c||(this.uuid+=1,o="dp"+this.uuid,this._dialogInput=e(""),this._dialogInput.keydown(this._doKeyDown),e("body").append(this._dialogInput),c=this._dialogInst=this._newInst(this._dialogInput,!1),c.settings={},e.data(this._dialogInput[0],"datepicker",c)),r(c.settings,n||{}),i=i&&i.constructor===Date?this._formatDate(c,i):i,this._dialogInput.val(i),this._pos=a?a.length?a:[a.pageX,a.pageY]:null,this._pos||(h=document.documentElement.clientWidth,l=document.documentElement.clientHeight,u=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[h/2-100+u,l/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),c.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),e.blockUI&&e.blockUI(this.dpDiv),e.data(this._dialogInput[0],"datepicker",c),this},_destroyDatepicker:function(t){var i,s=e(t),n=e.data(t,"datepicker");s.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),e.removeData(t,"datepicker"),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty(),v===n&&(v=null))},_enableDatepicker:function(t){var i,s,n=e(t),a=e.data(t,"datepicker");n.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),"input"===i?(t.disabled=!1,a.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=e.map(this._disabledInputs,function(e){return e===t?null:e}))},_disableDatepicker:function(t){var i,s,n=e(t),a=e.data(t,"datepicker");n.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),"input"===i?(t.disabled=!0,a.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=e.map(this._disabledInputs,function(e){return e===t?null:e}),this._disabledInputs[this._disabledInputs.length]=t)},_isDisabledDatepicker:function(e){if(!e)return!1;for(var t=0;this._disabledInputs.length>t;t++)if(this._disabledInputs[t]===e)return!0;return!1},_getInst:function(t){try{return e.data(t,"datepicker")}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(t,i,s){var n,a,o,h,l=this._getInst(t);return 2===arguments.length&&"string"==typeof i?"defaults"===i?e.extend({},e.datepicker._defaults):l?"all"===i?e.extend({},l.settings):this._get(l,i):null:(n=i||{},"string"==typeof i&&(n={},n[i]=s),l&&(this._curInst===l&&this._hideDatepicker(),a=this._getDateDatepicker(t,!0),o=this._getMinMaxDate(l,"min"),h=this._getMinMaxDate(l,"max"),r(l.settings,n),null!==o&&void 0!==n.dateFormat&&void 0===n.minDate&&(l.settings.minDate=this._formatDate(l,o)),null!==h&&void 0!==n.dateFormat&&void 0===n.maxDate&&(l.settings.maxDate=this._formatDate(l,h)),"disabled"in n&&(n.disabled?this._disableDatepicker(t):this._enableDatepicker(t)),this._attachments(e(t),l),this._autoSize(l),this._setDate(l,a),this._updateAlternate(l),this._updateDatepicker(l)),void 0)},_changeDatepicker:function(e,t,i){this._optionDatepicker(e,t,i)},_refreshDatepicker:function(e){var t=this._getInst(e);t&&this._updateDatepicker(t)},_setDateDatepicker:function(e,t){var i=this._getInst(e);i&&(this._setDate(i,t),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(e,t){var i=this._getInst(e);return i&&!i.inline&&this._setDateFromField(i,t),i?this._getDate(i):null},_doKeyDown:function(t){var i,s,n,a=e.datepicker._getInst(t.target),o=!0,r=a.dpDiv.is(".ui-datepicker-rtl");if(a._keyEvent=!0,e.datepicker._datepickerShowing)switch(t.keyCode){case 9:e.datepicker._hideDatepicker(),o=!1;break;case 13:return n=e("td."+e.datepicker._dayOverClass+":not(."+e.datepicker._currentClass+")",a.dpDiv),n[0]&&e.datepicker._selectDay(t.target,a.selectedMonth,a.selectedYear,n[0]),i=e.datepicker._get(a,"onSelect"),i?(s=e.datepicker._formatDate(a),i.apply(a.input?a.input[0]:null,[s,a])):e.datepicker._hideDatepicker(),!1;case 27:e.datepicker._hideDatepicker();break;case 33:e.datepicker._adjustDate(t.target,t.ctrlKey?-e.datepicker._get(a,"stepBigMonths"):-e.datepicker._get(a,"stepMonths"),"M");break;case 34:e.datepicker._adjustDate(t.target,t.ctrlKey?+e.datepicker._get(a,"stepBigMonths"):+e.datepicker._get(a,"stepMonths"),"M");break;case 35:(t.ctrlKey||t.metaKey)&&e.datepicker._clearDate(t.target),o=t.ctrlKey||t.metaKey;break;case 36:(t.ctrlKey||t.metaKey)&&e.datepicker._gotoToday(t.target),o=t.ctrlKey||t.metaKey;break;case 37:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,r?1:-1,"D"),o=t.ctrlKey||t.metaKey,t.originalEvent.altKey&&e.datepicker._adjustDate(t.target,t.ctrlKey?-e.datepicker._get(a,"stepBigMonths"):-e.datepicker._get(a,"stepMonths"),"M");break;case 38:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,-7,"D"),o=t.ctrlKey||t.metaKey;break;case 39:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,r?-1:1,"D"),o=t.ctrlKey||t.metaKey,t.originalEvent.altKey&&e.datepicker._adjustDate(t.target,t.ctrlKey?+e.datepicker._get(a,"stepBigMonths"):+e.datepicker._get(a,"stepMonths"),"M");break;case 40:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,7,"D"),o=t.ctrlKey||t.metaKey;break;default:o=!1}else 36===t.keyCode&&t.ctrlKey?e.datepicker._showDatepicker(this):o=!1;o&&(t.preventDefault(),t.stopPropagation())},_doKeyPress:function(t){var i,s,n=e.datepicker._getInst(t.target); +return e.datepicker._get(n,"constrainInput")?(i=e.datepicker._possibleChars(e.datepicker._get(n,"dateFormat")),s=String.fromCharCode(null==t.charCode?t.keyCode:t.charCode),t.ctrlKey||t.metaKey||" ">s||!i||i.indexOf(s)>-1):void 0},_doKeyUp:function(t){var i,s=e.datepicker._getInst(t.target);if(s.input.val()!==s.lastVal)try{i=e.datepicker.parseDate(e.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,e.datepicker._getFormatConfig(s)),i&&(e.datepicker._setDateFromField(s),e.datepicker._updateAlternate(s),e.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(t){if(t=t.target||t,"input"!==t.nodeName.toLowerCase()&&(t=e("input",t.parentNode)[0]),!e.datepicker._isDisabledDatepicker(t)&&e.datepicker._lastInput!==t){var i,n,a,o,h,l,u;i=e.datepicker._getInst(t),e.datepicker._curInst&&e.datepicker._curInst!==i&&(e.datepicker._curInst.dpDiv.stop(!0,!0),i&&e.datepicker._datepickerShowing&&e.datepicker._hideDatepicker(e.datepicker._curInst.input[0])),n=e.datepicker._get(i,"beforeShow"),a=n?n.apply(t,[t,i]):{},a!==!1&&(r(i.settings,a),i.lastVal=null,e.datepicker._lastInput=t,e.datepicker._setDateFromField(i),e.datepicker._inDialog&&(t.value=""),e.datepicker._pos||(e.datepicker._pos=e.datepicker._findPos(t),e.datepicker._pos[1]+=t.offsetHeight),o=!1,e(t).parents().each(function(){return o|="fixed"===e(this).css("position"),!o}),h={left:e.datepicker._pos[0],top:e.datepicker._pos[1]},e.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),e.datepicker._updateDatepicker(i),h=e.datepicker._checkOffset(i,h,o),i.dpDiv.css({position:e.datepicker._inDialog&&e.blockUI?"static":o?"fixed":"absolute",display:"none",left:h.left+"px",top:h.top+"px"}),i.inline||(l=e.datepicker._get(i,"showAnim"),u=e.datepicker._get(i,"duration"),i.dpDiv.css("z-index",s(e(t))+1),e.datepicker._datepickerShowing=!0,e.effects&&e.effects.effect[l]?i.dpDiv.show(l,e.datepicker._get(i,"showOptions"),u):i.dpDiv[l||"show"](l?u:null),e.datepicker._shouldFocusInput(i)&&i.input.focus(),e.datepicker._curInst=i))}},_updateDatepicker:function(t){this.maxRows=4,v=t,t.dpDiv.empty().append(this._generateHTML(t)),this._attachHandlers(t);var i,s=this._getNumberOfMonths(t),n=s[1],a=17,r=t.dpDiv.find("."+this._dayOverClass+" a");r.length>0&&o.apply(r.get(0)),t.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&t.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),t.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),t.dpDiv[(this._get(t,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),t===e.datepicker._curInst&&e.datepicker._datepickerShowing&&e.datepicker._shouldFocusInput(t)&&t.input.focus(),t.yearshtml&&(i=t.yearshtml,setTimeout(function(){i===t.yearshtml&&t.yearshtml&&t.dpDiv.find("select.ui-datepicker-year:first").replaceWith(t.yearshtml),i=t.yearshtml=null},0))},_shouldFocusInput:function(e){return e.input&&e.input.is(":visible")&&!e.input.is(":disabled")&&!e.input.is(":focus")},_checkOffset:function(t,i,s){var n=t.dpDiv.outerWidth(),a=t.dpDiv.outerHeight(),o=t.input?t.input.outerWidth():0,r=t.input?t.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:e(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:e(document).scrollTop());return i.left-=this._get(t,"isRTL")?n-o:0,i.left-=s&&i.left===t.input.offset().left?e(document).scrollLeft():0,i.top-=s&&i.top===t.input.offset().top+r?e(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+a>l&&l>a?Math.abs(a+r):0),i},_findPos:function(t){for(var i,s=this._getInst(t),n=this._get(s,"isRTL");t&&("hidden"===t.type||1!==t.nodeType||e.expr.filters.hidden(t));)t=t[n?"previousSibling":"nextSibling"];return i=e(t).offset(),[i.left,i.top]},_hideDatepicker:function(t){var i,s,n,a,o=this._curInst;!o||t&&o!==e.data(t,"datepicker")||this._datepickerShowing&&(i=this._get(o,"showAnim"),s=this._get(o,"duration"),n=function(){e.datepicker._tidyDialog(o)},e.effects&&(e.effects.effect[i]||e.effects[i])?o.dpDiv.hide(i,e.datepicker._get(o,"showOptions"),s,n):o.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,a=this._get(o,"onClose"),a&&a.apply(o.input?o.input[0]:null,[o.input?o.input.val():"",o]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),e.blockUI&&(e.unblockUI(),e("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(e){e.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(t){if(e.datepicker._curInst){var i=e(t.target),s=e.datepicker._getInst(i[0]);(i[0].id!==e.datepicker._mainDivId&&0===i.parents("#"+e.datepicker._mainDivId).length&&!i.hasClass(e.datepicker.markerClassName)&&!i.closest("."+e.datepicker._triggerClass).length&&e.datepicker._datepickerShowing&&(!e.datepicker._inDialog||!e.blockUI)||i.hasClass(e.datepicker.markerClassName)&&e.datepicker._curInst!==s)&&e.datepicker._hideDatepicker()}},_adjustDate:function(t,i,s){var n=e(t),a=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(a,i+("M"===s?this._get(a,"showCurrentAtPos"):0),s),this._updateDatepicker(a))},_gotoToday:function(t){var i,s=e(t),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(t,i,s){var n=e(t),a=this._getInst(n[0]);a["selected"+("M"===s?"Month":"Year")]=a["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(a),this._adjustDate(n)},_selectDay:function(t,i,s,n){var a,o=e(t);e(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(o[0])||(a=this._getInst(o[0]),a.selectedDay=a.currentDay=e("a",n).html(),a.selectedMonth=a.currentMonth=i,a.selectedYear=a.currentYear=s,this._selectDate(t,this._formatDate(a,a.currentDay,a.currentMonth,a.currentYear)))},_clearDate:function(t){var i=e(t);this._selectDate(i,"")},_selectDate:function(t,i){var s,n=e(t),a=this._getInst(n[0]);i=null!=i?i:this._formatDate(a),a.input&&a.input.val(i),this._updateAlternate(a),s=this._get(a,"onSelect"),s?s.apply(a.input?a.input[0]:null,[i,a]):a.input&&a.input.trigger("change"),a.inline?this._updateDatepicker(a):(this._hideDatepicker(),this._lastInput=a.input[0],"object"!=typeof a.input[0]&&a.input.focus(),this._lastInput=null)},_updateAlternate:function(t){var i,s,n,a=this._get(t,"altField");a&&(i=this._get(t,"altFormat")||this._get(t,"dateFormat"),s=this._getDate(t),n=this.formatDate(i,s,this._getFormatConfig(t)),e(a).each(function(){e(this).val(n)}))},noWeekends:function(e){var t=e.getDay();return[t>0&&6>t,""]},iso8601Week:function(e){var t,i=new Date(e.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),t=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((t-i)/864e5)/7)+1},parseDate:function(t,i,s){if(null==t||null==i)throw"Invalid arguments";if(i="object"==typeof i?""+i:i+"",""===i)return null;var n,a,o,r,h=0,l=(s?s.shortYearCutoff:null)||this._defaults.shortYearCutoff,u="string"!=typeof l?l:(new Date).getFullYear()%100+parseInt(l,10),d=(s?s.dayNamesShort:null)||this._defaults.dayNamesShort,c=(s?s.dayNames:null)||this._defaults.dayNames,p=(s?s.monthNamesShort:null)||this._defaults.monthNamesShort,f=(s?s.monthNames:null)||this._defaults.monthNames,m=-1,g=-1,v=-1,y=-1,b=!1,_=function(e){var i=t.length>n+1&&t.charAt(n+1)===e;return i&&n++,i},x=function(e){var t=_(e),s="@"===e?14:"!"===e?20:"y"===e&&t?4:"o"===e?3:2,n="y"===e?s:1,a=RegExp("^\\d{"+n+","+s+"}"),o=i.substring(h).match(a);if(!o)throw"Missing number at position "+h;return h+=o[0].length,parseInt(o[0],10)},w=function(t,s,n){var a=-1,o=e.map(_(t)?n:s,function(e,t){return[[t,e]]}).sort(function(e,t){return-(e[1].length-t[1].length)});if(e.each(o,function(e,t){var s=t[1];return i.substr(h,s.length).toLowerCase()===s.toLowerCase()?(a=t[0],h+=s.length,!1):void 0}),-1!==a)return a+1;throw"Unknown name at position "+h},k=function(){if(i.charAt(h)!==t.charAt(n))throw"Unexpected literal at position "+h;h++};for(n=0;t.length>n;n++)if(b)"'"!==t.charAt(n)||_("'")?k():b=!1;else switch(t.charAt(n)){case"d":v=x("d");break;case"D":w("D",d,c);break;case"o":y=x("o");break;case"m":g=x("m");break;case"M":g=w("M",p,f);break;case"y":m=x("y");break;case"@":r=new Date(x("@")),m=r.getFullYear(),g=r.getMonth()+1,v=r.getDate();break;case"!":r=new Date((x("!")-this._ticksTo1970)/1e4),m=r.getFullYear(),g=r.getMonth()+1,v=r.getDate();break;case"'":_("'")?k():b=!0;break;default:k()}if(i.length>h&&(o=i.substr(h),!/^\s+/.test(o)))throw"Extra/unparsed characters found in date: "+o;if(-1===m?m=(new Date).getFullYear():100>m&&(m+=(new Date).getFullYear()-(new Date).getFullYear()%100+(u>=m?0:-100)),y>-1)for(g=1,v=y;;){if(a=this._getDaysInMonth(m,g-1),a>=v)break;g++,v-=a}if(r=this._daylightSavingAdjust(new Date(m,g-1,v)),r.getFullYear()!==m||r.getMonth()+1!==g||r.getDate()!==v)throw"Invalid date";return r},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(e,t,i){if(!t)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,a=(i?i.dayNames:null)||this._defaults.dayNames,o=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(t){var i=e.length>s+1&&e.charAt(s+1)===t;return i&&s++,i},l=function(e,t,i){var s=""+t;if(h(e))for(;i>s.length;)s="0"+s;return s},u=function(e,t,i,s){return h(e)?s[t]:i[t]},d="",c=!1;if(t)for(s=0;e.length>s;s++)if(c)"'"!==e.charAt(s)||h("'")?d+=e.charAt(s):c=!1;else switch(e.charAt(s)){case"d":d+=l("d",t.getDate(),2);break;case"D":d+=u("D",t.getDay(),n,a);break;case"o":d+=l("o",Math.round((new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime()-new Date(t.getFullYear(),0,0).getTime())/864e5),3);break;case"m":d+=l("m",t.getMonth()+1,2);break;case"M":d+=u("M",t.getMonth(),o,r);break;case"y":d+=h("y")?t.getFullYear():(10>t.getYear()%100?"0":"")+t.getYear()%100;break;case"@":d+=t.getTime();break;case"!":d+=1e4*t.getTime()+this._ticksTo1970;break;case"'":h("'")?d+="'":c=!0;break;default:d+=e.charAt(s)}return d},_possibleChars:function(e){var t,i="",s=!1,n=function(i){var s=e.length>t+1&&e.charAt(t+1)===i;return s&&t++,s};for(t=0;e.length>t;t++)if(s)"'"!==e.charAt(t)||n("'")?i+=e.charAt(t):s=!1;else switch(e.charAt(t)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=e.charAt(t)}return i},_get:function(e,t){return void 0!==e.settings[t]?e.settings[t]:this._defaults[t]},_setDateFromField:function(e,t){if(e.input.val()!==e.lastVal){var i=this._get(e,"dateFormat"),s=e.lastVal=e.input?e.input.val():null,n=this._getDefaultDate(e),a=n,o=this._getFormatConfig(e);try{a=this.parseDate(i,s,o)||n}catch(r){s=t?"":s}e.selectedDay=a.getDate(),e.drawMonth=e.selectedMonth=a.getMonth(),e.drawYear=e.selectedYear=a.getFullYear(),e.currentDay=s?a.getDate():0,e.currentMonth=s?a.getMonth():0,e.currentYear=s?a.getFullYear():0,this._adjustInstDate(e)}},_getDefaultDate:function(e){return this._restrictMinMax(e,this._determineDate(e,this._get(e,"defaultDate"),new Date))},_determineDate:function(t,i,s){var n=function(e){var t=new Date;return t.setDate(t.getDate()+e),t},a=function(i){try{return e.datepicker.parseDate(e.datepicker._get(t,"dateFormat"),i,e.datepicker._getFormatConfig(t))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?e.datepicker._getDate(t):null)||new Date,a=n.getFullYear(),o=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":o+=parseInt(l[1],10),r=Math.min(r,e.datepicker._getDaysInMonth(a,o));break;case"y":case"Y":a+=parseInt(l[1],10),r=Math.min(r,e.datepicker._getDaysInMonth(a,o))}l=h.exec(i)}return new Date(a,o,r)},o=null==i||""===i?s:"string"==typeof i?a(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return o=o&&"Invalid Date"==""+o?s:o,o&&(o.setHours(0),o.setMinutes(0),o.setSeconds(0),o.setMilliseconds(0)),this._daylightSavingAdjust(o)},_daylightSavingAdjust:function(e){return e?(e.setHours(e.getHours()>12?e.getHours()+2:0),e):null},_setDate:function(e,t,i){var s=!t,n=e.selectedMonth,a=e.selectedYear,o=this._restrictMinMax(e,this._determineDate(e,t,new Date));e.selectedDay=e.currentDay=o.getDate(),e.drawMonth=e.selectedMonth=e.currentMonth=o.getMonth(),e.drawYear=e.selectedYear=e.currentYear=o.getFullYear(),n===e.selectedMonth&&a===e.selectedYear||i||this._notifyChange(e),this._adjustInstDate(e),e.input&&e.input.val(s?"":this._formatDate(e))},_getDate:function(e){var t=!e.currentYear||e.input&&""===e.input.val()?null:this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return t},_attachHandlers:function(t){var i=this._get(t,"stepMonths"),s="#"+t.id.replace(/\\\\/g,"\\");t.dpDiv.find("[data-handler]").map(function(){var t={prev:function(){e.datepicker._adjustDate(s,-i,"M")},next:function(){e.datepicker._adjustDate(s,+i,"M")},hide:function(){e.datepicker._hideDatepicker()},today:function(){e.datepicker._gotoToday(s)},selectDay:function(){return e.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return e.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return e.datepicker._selectMonthYear(s,this,"Y"),!1}};e(this).bind(this.getAttribute("data-event"),t[this.getAttribute("data-handler")])})},_generateHTML:function(e){var t,i,s,n,a,o,r,h,l,u,d,c,p,f,m,g,v,y,b,_,x,w,k,T,D,S,M,C,N,A,P,I,H,z,F,E,O,j,W,L=new Date,R=this._daylightSavingAdjust(new Date(L.getFullYear(),L.getMonth(),L.getDate())),Y=this._get(e,"isRTL"),B=this._get(e,"showButtonPanel"),J=this._get(e,"hideIfNoPrevNext"),q=this._get(e,"navigationAsDateFormat"),K=this._getNumberOfMonths(e),V=this._get(e,"showCurrentAtPos"),U=this._get(e,"stepMonths"),Q=1!==K[0]||1!==K[1],G=this._daylightSavingAdjust(e.currentDay?new Date(e.currentYear,e.currentMonth,e.currentDay):new Date(9999,9,9)),X=this._getMinMaxDate(e,"min"),$=this._getMinMaxDate(e,"max"),Z=e.drawMonth-V,et=e.drawYear;if(0>Z&&(Z+=12,et--),$)for(t=this._daylightSavingAdjust(new Date($.getFullYear(),$.getMonth()-K[0]*K[1]+1,$.getDate())),t=X&&X>t?X:t;this._daylightSavingAdjust(new Date(et,Z,1))>t;)Z--,0>Z&&(Z=11,et--);for(e.drawMonth=Z,e.drawYear=et,i=this._get(e,"prevText"),i=q?this.formatDate(i,this._daylightSavingAdjust(new Date(et,Z-U,1)),this._getFormatConfig(e)):i,s=this._canAdjustMonth(e,-1,et,Z)?""+i+"":J?"":""+i+"",n=this._get(e,"nextText"),n=q?this.formatDate(n,this._daylightSavingAdjust(new Date(et,Z+U,1)),this._getFormatConfig(e)):n,a=this._canAdjustMonth(e,1,et,Z)?""+n+"":J?"":""+n+"",o=this._get(e,"currentText"),r=this._get(e,"gotoCurrent")&&e.currentDay?G:R,o=q?this.formatDate(o,r,this._getFormatConfig(e)):o,h=e.inline?"":"",l=B?"
    "+(Y?h:"")+(this._isInRange(e,r)?"":"")+(Y?"":h)+"
    ":"",u=parseInt(this._get(e,"firstDay"),10),u=isNaN(u)?0:u,d=this._get(e,"showWeek"),c=this._get(e,"dayNames"),p=this._get(e,"dayNamesMin"),f=this._get(e,"monthNames"),m=this._get(e,"monthNamesShort"),g=this._get(e,"beforeShowDay"),v=this._get(e,"showOtherMonths"),y=this._get(e,"selectOtherMonths"),b=this._getDefaultDate(e),_="",w=0;K[0]>w;w++){for(k="",this.maxRows=4,T=0;K[1]>T;T++){if(D=this._daylightSavingAdjust(new Date(et,Z,e.selectedDay)),S=" ui-corner-all",M="",Q){if(M+="
    "}for(M+="
    "+(/all|left/.test(S)&&0===w?Y?a:s:"")+(/all|right/.test(S)&&0===w?Y?s:a:"")+this._generateMonthYearHeader(e,Z,et,X,$,w>0||T>0,f,m)+"
    "+"",C=d?"":"",x=0;7>x;x++)N=(x+u)%7,C+="";for(M+=C+"",A=this._getDaysInMonth(et,Z),et===e.selectedYear&&Z===e.selectedMonth&&(e.selectedDay=Math.min(e.selectedDay,A)),P=(this._getFirstDayOfMonth(et,Z)-u+7)%7,I=Math.ceil((P+A)/7),H=Q?this.maxRows>I?this.maxRows:I:I,this.maxRows=H,z=this._daylightSavingAdjust(new Date(et,Z,1-P)),F=0;H>F;F++){for(M+="",E=d?"":"",x=0;7>x;x++)O=g?g.apply(e.input?e.input[0]:null,[z]):[!0,""],j=z.getMonth()!==Z,W=j&&!y||!O[0]||X&&X>z||$&&z>$,E+="",z.setDate(z.getDate()+1),z=this._daylightSavingAdjust(z);M+=E+""}Z++,Z>11&&(Z=0,et++),M+="
    "+this._get(e,"weekHeader")+"=5?" class='ui-datepicker-week-end'":"")+">"+""+p[N]+"
    "+this._get(e,"calculateWeek")(z)+""+(j&&!v?" ":W?""+z.getDate()+"":""+z.getDate()+"")+"
    "+(Q?"
    "+(K[0]>0&&T===K[1]-1?"
    ":""):""),k+=M}_+=k}return _+=l,e._keyEvent=!1,_},_generateMonthYearHeader:function(e,t,i,s,n,a,o,r){var h,l,u,d,c,p,f,m,g=this._get(e,"changeMonth"),v=this._get(e,"changeYear"),y=this._get(e,"showMonthAfterYear"),b="
    ",_="";if(a||!g)_+=""+o[t]+"";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,_+=""}if(y||(b+=_+(!a&&g&&v?"":" ")),!e.yearshtml)if(e.yearshtml="",a||!v)b+=""+i+"";else{for(d=this._get(e,"yearRange").split(":"),c=(new Date).getFullYear(),p=function(e){var t=e.match(/c[+\-].*/)?i+parseInt(e.substring(1),10):e.match(/[+\-].*/)?c+parseInt(e,10):parseInt(e,10);return isNaN(t)?c:t},f=p(d[0]),m=Math.max(f,p(d[1]||"")),f=s?Math.max(f,s.getFullYear()):f,m=n?Math.min(m,n.getFullYear()):m,e.yearshtml+="",b+=e.yearshtml,e.yearshtml=null}return b+=this._get(e,"yearSuffix"),y&&(b+=(!a&&g&&v?"":" ")+_),b+="
    "},_adjustInstDate:function(e,t,i){var s=e.drawYear+("Y"===i?t:0),n=e.drawMonth+("M"===i?t:0),a=Math.min(e.selectedDay,this._getDaysInMonth(s,n))+("D"===i?t:0),o=this._restrictMinMax(e,this._daylightSavingAdjust(new Date(s,n,a)));e.selectedDay=o.getDate(),e.drawMonth=e.selectedMonth=o.getMonth(),e.drawYear=e.selectedYear=o.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(e)},_restrictMinMax:function(e,t){var i=this._getMinMaxDate(e,"min"),s=this._getMinMaxDate(e,"max"),n=i&&i>t?i:t;return s&&n>s?s:n},_notifyChange:function(e){var t=this._get(e,"onChangeMonthYear");t&&t.apply(e.input?e.input[0]:null,[e.selectedYear,e.selectedMonth+1,e])},_getNumberOfMonths:function(e){var t=this._get(e,"numberOfMonths");return null==t?[1,1]:"number"==typeof t?[1,t]:t},_getMinMaxDate:function(e,t){return this._determineDate(e,this._get(e,t+"Date"),null)},_getDaysInMonth:function(e,t){return 32-this._daylightSavingAdjust(new Date(e,t,32)).getDate()},_getFirstDayOfMonth:function(e,t){return new Date(e,t,1).getDay()},_canAdjustMonth:function(e,t,i,s){var n=this._getNumberOfMonths(e),a=this._daylightSavingAdjust(new Date(i,s+(0>t?t:n[0]*n[1]),1));return 0>t&&a.setDate(this._getDaysInMonth(a.getFullYear(),a.getMonth())),this._isInRange(e,a)},_isInRange:function(e,t){var i,s,n=this._getMinMaxDate(e,"min"),a=this._getMinMaxDate(e,"max"),o=null,r=null,h=this._get(e,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),o=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(o+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||t.getTime()>=n.getTime())&&(!a||t.getTime()<=a.getTime())&&(!o||t.getFullYear()>=o)&&(!r||r>=t.getFullYear())},_getFormatConfig:function(e){var t=this._get(e,"shortYearCutoff");return t="string"!=typeof t?t:(new Date).getFullYear()%100+parseInt(t,10),{shortYearCutoff:t,dayNamesShort:this._get(e,"dayNamesShort"),dayNames:this._get(e,"dayNames"),monthNamesShort:this._get(e,"monthNamesShort"),monthNames:this._get(e,"monthNames")}},_formatDate:function(e,t,i,s){t||(e.currentDay=e.selectedDay,e.currentMonth=e.selectedMonth,e.currentYear=e.selectedYear);var n=t?"object"==typeof t?t:this._daylightSavingAdjust(new Date(s,i,t)):this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return this.formatDate(this._get(e,"dateFormat"),n,this._getFormatConfig(e))}}),e.fn.datepicker=function(t){if(!this.length)return this;e.datepicker.initialized||(e(document).mousedown(e.datepicker._checkExternalClick),e.datepicker.initialized=!0),0===e("#"+e.datepicker._mainDivId).length&&e("body").append(e.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof t||"isDisabled"!==t&&"getDate"!==t&&"widget"!==t?"option"===t&&2===arguments.length&&"string"==typeof arguments[1]?e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof t?e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this].concat(i)):e.datepicker._attachDatepicker(this,t)}):e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this[0]].concat(i))},e.datepicker=new n,e.datepicker.initialized=!1,e.datepicker.uuid=(new Date).getTime(),e.datepicker.version="1.11.4",e.datepicker,e.widget("ui.draggable",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._setHandleClassName(),this._mouseInit()},_setOption:function(e,t){this._super(e,t),"handle"===e&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(t){var i=this.options;return this._blurActiveElement(t),this.helper||i.disabled||e(t.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(t),this.handle?(this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(t){this.iframeBlocks=this.document.find(t).map(function(){var t=e(this);return e("
    ").css("position","absolute").appendTo(t.parent()).outerWidth(t.outerWidth()).outerHeight(t.outerHeight()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(t){var i=this.document[0];if(this.handleElement.is(t.target))try{i.activeElement&&"body"!==i.activeElement.nodeName.toLowerCase()&&e(i.activeElement).blur()}catch(s){}},_mouseStart:function(t){var i=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===e(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(t),this.originalPosition=this.position=this._generatePosition(t,!1),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._normalizeRightBottom(),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_refreshOffsets:function(e){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:e.pageX-this.offset.left,top:e.pageY-this.offset.top}},_mouseDrag:function(t,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(t,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",t,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var i=this,s=!1;return e.ui.ddmanager&&!this.options.dropBehaviour&&(s=e.ui.ddmanager.drop(this,t)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",t)!==!1&&i._clear()}):this._trigger("stop",t)!==!1&&this._clear(),!1},_mouseUp:function(t){return this._unblockFrames(),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),this.handleElement.is(t.target)&&this.element.focus(),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this.handleElement.addClass("ui-draggable-handle")},_removeHandleClassName:function(){this.handleElement.removeClass("ui-draggable-handle")},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper),n=s?e(i.helper.apply(this.element[0],[t])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_isRootNode:function(e){return/(html|body)/i.test(e.tagName)||e===this.document[0]},_getParentOffset:function(){var t=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var e=this.element.position(),t=this._isRootNode(this.scrollParent[0]);return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+(t?0:this.scrollParent.scrollTop()),left:e.left-(parseInt(this.helper.css("left"),10)||0)+(t?0:this.scrollParent.scrollLeft())}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options,a=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,e(window).scrollLeft()+e(window).width()-this.helperProportions.width-this.margins.left,e(window).scrollTop()+(e(window).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,e(a).width()-this.helperProportions.width-this.margins.left,(e(a).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=e(n.containment),s=i[0],s&&(t=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(t?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0) +},_convertPositionTo:function(e,t){t||(t=this.position);var i="absolute"===e?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:t.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:t.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(e,t){var i,s,n,a,o=this.options,r=this._isRootNode(this.scrollParent[0]),h=e.pageX,l=e.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),t&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.lefti[2]&&(h=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,h=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a),"y"===o.axis&&(h=this.originalPageX),"x"===o.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_normalizeRightBottom:function(){"y"!==this.options.axis&&"auto"!==this.helper.css("right")&&(this.helper.width(this.helper.width()),this.helper.css("right","auto")),"x"!==this.options.axis&&"auto"!==this.helper.css("bottom")&&(this.helper.height(this.helper.height()),this.helper.css("bottom","auto"))},_trigger:function(t,i,s){return s=s||this._uiHash(),e.ui.plugin.call(this,t,[i,s,this],!0),/^(drag|start|stop)/.test(t)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),e.Widget.prototype._trigger.call(this,t,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,i,s){var n=e.extend({},i,{item:s.element});s.sortables=[],e(s.options.connectToSortable).each(function(){var i=e(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",t,n))})},stop:function(t,i,s){var n=e.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,e.each(s.sortables,function(){var e=this;e.isOver?(e.isOver=0,s.cancelHelperRemoval=!0,e.cancelHelperRemoval=!1,e._storedCSS={position:e.placeholder.css("position"),top:e.placeholder.css("top"),left:e.placeholder.css("left")},e._mouseStop(t),e.options.helper=e.options._helper):(e.cancelHelperRemoval=!0,e._trigger("deactivate",t,n))})},drag:function(t,i,s){e.each(s.sortables,function(){var n=!1,a=this;a.positionAbs=s.positionAbs,a.helperProportions=s.helperProportions,a.offset.click=s.offset.click,a._intersectsWith(a.containerCache)&&(n=!0,e.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==a&&this._intersectsWith(this.containerCache)&&e.contains(a.element[0],this.element[0])&&(n=!1),n})),n?(a.isOver||(a.isOver=1,s._parent=i.helper.parent(),a.currentItem=i.helper.appendTo(a.element).data("ui-sortable-item",!0),a.options._helper=a.options.helper,a.options.helper=function(){return i.helper[0]},t.target=a.currentItem[0],a._mouseCapture(t,!0),a._mouseStart(t,!0,!0),a.offset.click.top=s.offset.click.top,a.offset.click.left=s.offset.click.left,a.offset.parent.left-=s.offset.parent.left-a.offset.parent.left,a.offset.parent.top-=s.offset.parent.top-a.offset.parent.top,s._trigger("toSortable",t),s.dropped=a.element,e.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,a.fromOutside=s),a.currentItem&&(a._mouseDrag(t),i.position=a.position)):a.isOver&&(a.isOver=0,a.cancelHelperRemoval=!0,a.options._revert=a.options.revert,a.options.revert=!1,a._trigger("out",t,a._uiHash(a)),a._mouseStop(t,!0),a.options.revert=a.options._revert,a.options.helper=a.options._helper,a.placeholder&&a.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(t),i.position=s._generatePosition(t,!0),s._trigger("fromSortable",t),s.dropped=!1,e.each(s.sortables,function(){this.refreshPositions()}))})}}),e.ui.plugin.add("draggable","cursor",{start:function(t,i,s){var n=e("body"),a=s.options;n.css("cursor")&&(a._cursor=n.css("cursor")),n.css("cursor",a.cursor)},stop:function(t,i,s){var n=s.options;n._cursor&&e("body").css("cursor",n._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,i,s){var n=e(i.helper),a=s.options;n.css("opacity")&&(a._opacity=n.css("opacity")),n.css("opacity",a.opacity)},stop:function(t,i,s){var n=s.options;n._opacity&&e(i.helper).css("opacity",n._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(e,t,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(t,i,s){var n=s.options,a=!1,o=s.scrollParentNotHidden[0],r=s.document[0];o!==r&&"HTML"!==o.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+o.offsetHeight-t.pageY=0;c--)h=s.snapElements[c].left-s.margins.left,l=h+s.snapElements[c].width,u=s.snapElements[c].top-s.margins.top,d=u+s.snapElements[c].height,h-m>v||g>l+m||u-m>b||y>d+m||!e.contains(s.snapElements[c].item.ownerDocument,s.snapElements[c].item)?(s.snapElements[c].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=!1):("inner"!==f.snapMode&&(n=m>=Math.abs(u-b),a=m>=Math.abs(d-y),o=m>=Math.abs(h-v),r=m>=Math.abs(l-g),n&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:d,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||a||o||r,"outer"!==f.snapMode&&(n=m>=Math.abs(u-y),a=m>=Math.abs(d-b),o=m>=Math.abs(h-g),r=m>=Math.abs(l-v),n&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:d-s.helperProportions.height,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[c].snapping&&(n||a||o||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=n||a||o||r||p)}}),e.ui.plugin.add("draggable","stack",{start:function(t,i,s){var n,a=s.options,o=e.makeArray(e(a.stack)).sort(function(t,i){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(i).css("zIndex"),10)||0)});o.length&&(n=parseInt(e(o[0]).css("zIndex"),10)||0,e(o).each(function(t){e(this).css("zIndex",n+t)}),this.css("zIndex",n+o.length))}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,i,s){var n=e(i.helper),a=s.options;n.css("zIndex")&&(a._zIndex=n.css("zIndex")),n.css("zIndex",a.zIndex)},stop:function(t,i,s){var n=s.options;n._zIndex&&e(i.helper).css("zIndex",n._zIndex)}}),e.ui.draggable,e.widget("ui.resizable",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(e){return parseInt(e,10)||0},_isNumber:function(e){return!isNaN(parseInt(e,10))},_hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return t[s]>0?!0:(t[s]=1,n=t[s]>0,t[s]=0,n)},_create:function(){var t,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(e("
    ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=e(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),t=this.handles.split(","),this.handles={},i=0;t.length>i;i++)s=e.trim(t[i]),a="ui-resizable-"+s,n=e("
    "),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(t){var i,s,n,a;t=t||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=e(this.handles[i]),this._on(this.handles[i],{mousedown:o._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=e(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),t.css(n,a),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(e(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(e(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t,i=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),t=this.element,this.originalElement.css({position:t.css("position"),width:t.outerWidth(),height:t.outerHeight(),top:t.css("top"),left:t.css("left")}).insertAfter(t),t.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(t){var i,s,n=!1;for(i in this.handles)s=e(this.handles[i])[0],(s===t.target||e.contains(s,t.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(t){var i,s,n,a=this.options,o=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),a.containment&&(i+=e(a.containment).scrollLeft()||0,s+=e(a.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:o.width(),height:o.height()},this.originalSize=this._helper?{width:o.outerWidth(),height:o.outerHeight()}:{width:o.width(),height:o.height()},this.sizeDiff={width:o.outerWidth()-o.width(),height:o.outerHeight()-o.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof a.aspectRatio?a.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=e(".ui-resizable-"+this.axis).css("cursor"),e("body").css("cursor","auto"===n?this.axis+"-resize":n),o.addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var i,s,n=this.originalMousePosition,a=this.axis,o=t.pageX-n.left||0,r=t.pageY-n.top||0,h=this._change[a];return this._updatePrevProperties(),h?(i=h.apply(this,[t,o,r]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(i=this._updateRatio(i,t)),i=this._respectSize(i,t),this._updateCache(i),this._propagate("resize",t),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),e.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(t){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(e.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var e={};return this.position.top!==this.prevPosition.top&&(e.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(e.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(e.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(e.height=this.size.height+"px"),this.helper.css(e),e},_updateVirtualBoundaries:function(e){var t,i,s,n,a,o=this.options;a={minWidth:this._isNumber(o.minWidth)?o.minWidth:0,maxWidth:this._isNumber(o.maxWidth)?o.maxWidth:1/0,minHeight:this._isNumber(o.minHeight)?o.minHeight:0,maxHeight:this._isNumber(o.maxHeight)?o.maxHeight:1/0},(this._aspectRatio||e)&&(t=a.minHeight*this.aspectRatio,s=a.minWidth/this.aspectRatio,i=a.maxHeight*this.aspectRatio,n=a.maxWidth/this.aspectRatio,t>a.minWidth&&(a.minWidth=t),s>a.minHeight&&(a.minHeight=s),a.maxWidth>i&&(a.maxWidth=i),a.maxHeight>n&&(a.maxHeight=n)),this._vBoundaries=a},_updateCache:function(e){this.offset=this.helper.offset(),this._isNumber(e.left)&&(this.position.left=e.left),this._isNumber(e.top)&&(this.position.top=e.top),this._isNumber(e.height)&&(this.size.height=e.height),this._isNumber(e.width)&&(this.size.width=e.width)},_updateRatio:function(e){var t=this.position,i=this.size,s=this.axis;return this._isNumber(e.height)?e.width=e.height*this.aspectRatio:this._isNumber(e.width)&&(e.height=e.width/this.aspectRatio),"sw"===s&&(e.left=t.left+(i.width-e.width),e.top=null),"nw"===s&&(e.top=t.top+(i.height-e.height),e.left=t.left+(i.width-e.width)),e},_respectSize:function(e){var t=this._vBoundaries,i=this.axis,s=this._isNumber(e.width)&&t.maxWidth&&t.maxWidthe.width,o=this._isNumber(e.height)&&t.minHeight&&t.minHeight>e.height,r=this.originalPosition.left+this.originalSize.width,h=this.position.top+this.size.height,l=/sw|nw|w/.test(i),u=/nw|ne|n/.test(i);return a&&(e.width=t.minWidth),o&&(e.height=t.minHeight),s&&(e.width=t.maxWidth),n&&(e.height=t.maxHeight),a&&l&&(e.left=r-t.minWidth),s&&l&&(e.left=r-t.maxWidth),o&&u&&(e.top=h-t.minHeight),n&&u&&(e.top=h-t.maxHeight),e.width||e.height||e.left||!e.top?e.width||e.height||e.top||!e.left||(e.left=null):e.top=null,e},_getPaddingPlusBorderDimensions:function(e){for(var t=0,i=[],s=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],n=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];4>t;t++)i[t]=parseInt(s[t],10)||0,i[t]+=parseInt(n[t],10)||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var e,t=0,i=this.helper||this.element;this._proportionallyResizeElements.length>t;t++)e=this._proportionallyResizeElements[t],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(e)),e.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var t=this.element,i=this.options;this.elementOffset=t.offset(),this._helper?(this.helper=this.helper||e("
    "),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(e,t){return{width:this.originalSize.width+t}},w:function(e,t){var i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(e,t,i){return{height:this.originalSize.height+i}},se:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},sw:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,i,s]))},ne:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},nw:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,i,s]))}},_propagate:function(t,i){e.ui.plugin.call(this,t,[i,this.ui()]),"resize"!==t&&this._trigger(t,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","animate",{stop:function(t){var i=e(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(e.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&e(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(){var t,i,s,n,a,o,r,h=e(this).resizable("instance"),l=h.options,u=h.element,d=l.containment,c=d instanceof e?d.get(0):/parent/.test(d)?u.parent().get(0):d;c&&(h.containerElement=e(c),/document/.test(d)||d===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}):(t=e(c),i=[],e(["Top","Right","Left","Bottom"]).each(function(e,s){i[e]=h._num(t.css("padding"+s))}),h.containerOffset=t.offset(),h.containerPosition=t.position(),h.containerSize={height:t.innerHeight()-i[3],width:t.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,a=h.containerSize.width,o=h._hasScroll(c,"left")?c.scrollWidth:a,r=h._hasScroll(c)?c.scrollHeight:n,h.parentData={element:c,left:s.left,top:s.top,width:o,height:r}))},resize:function(t){var i,s,n,a,o=e(this).resizable("instance"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||t.shiftKey,d={top:0,left:0},c=o.containerElement,p=!0;c[0]!==document&&/static/.test(c.css("position"))&&(d=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-d.left),u&&(o.size.height=o.size.width/o.aspectRatio,p=!1),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio,p=!1),o.position.top=o._helper?h.top:0),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a?(o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top):(o.offset.left=o.element.offset().left,o.offset.top=o.element.offset().top),i=Math.abs(o.sizeDiff.width+(o._helper?o.offset.left-d.left:o.offset.left-h.left)),s=Math.abs(o.sizeDiff.height+(o._helper?o.offset.top-d.top:o.offset.top-h.top)),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio,p=!1)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio,p=!1)),p||(o.position.left=o.prevPosition.left,o.position.top=o.prevPosition.top,o.size.width=o.prevSize.width,o.size.height=o.prevSize.height)},stop:function(){var t=e(this).resizable("instance"),i=t.options,s=t.containerOffset,n=t.containerPosition,a=t.containerElement,o=e(t.helper),r=o.offset(),h=o.outerWidth()-t.sizeDiff.width,l=o.outerHeight()-t.sizeDiff.height;t._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l}),t._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),e.ui.plugin.add("resizable","alsoResize",{start:function(){var t=e(this).resizable("instance"),i=t.options;e(i.alsoResize).each(function(){var t=e(this);t.data("ui-resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})},resize:function(t,i){var s=e(this).resizable("instance"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0};e(n.alsoResize).each(function(){var t=e(this),s=e(this).data("ui-resizable-alsoresize"),n={},a=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(a,function(e,t){var i=(s[t]||0)+(r[t]||0);i&&i>=0&&(n[t]=i||null)}),t.css(n)})},stop:function(){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","ghost",{start:function(){var t=e(this).resizable("instance"),i=t.options,s=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),t.ghost.appendTo(t.helper)},resize:function(){var t=e(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=e(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(){var t,i=e(this).resizable("instance"),s=i.options,n=i.size,a=i.originalSize,o=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,u=h[1]||1,d=Math.round((n.width-a.width)/l)*l,c=Math.round((n.height-a.height)/u)*u,p=a.width+d,f=a.height+c,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,v=s.minWidth&&s.minWidth>p,y=s.minHeight&&s.minHeight>f;s.grid=h,v&&(p+=l),y&&(f+=u),m&&(p-=l),g&&(f-=u),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=o.top-c):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=o.left-d):((0>=f-u||0>=p-l)&&(t=i._getPaddingPlusBorderDimensions(this)),f-u>0?(i.size.height=f,i.position.top=o.top-c):(f=u-t.height,i.size.height=f,i.position.top=o.top+a.height-f),p-l>0?(i.size.width=p,i.position.left=o.left-d):(p=l-t.width,i.size.width=p,i.position.left=o.left+a.width-p))}}),e.ui.resizable,e.widget("ui.dialog",{version:"1.11.4",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"Close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(t){var i=e(this).css(t).offset().top;0>i&&e(this).css("top",t.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},sizeRelatedOptions:{buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},resizableRelatedOptions:{maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&e.fn.draggable&&this._makeDraggable(),this.options.resizable&&e.fn.resizable&&this._makeResizable(),this._isOpen=!1,this._trackFocus()},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var t=this.options.appendTo;return t&&(t.jquery||t.nodeType)?e(t):this.document.find(t||"body").eq(0)},_destroy:function(){var e,t=this.originalPosition;this._untrackInstance(),this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),e=t.parent.children().eq(t.index),e.length&&e[0]!==this.element[0]?e.before(this.element):t.parent.append(this.element)},widget:function(){return this.uiDialog},disable:e.noop,enable:e.noop,close:function(t){var i,s=this;if(this._isOpen&&this._trigger("beforeClose",t)!==!1){if(this._isOpen=!1,this._focusedElement=null,this._destroyOverlay(),this._untrackInstance(),!this.opener.filter(":focusable").focus().length)try{i=this.document[0].activeElement,i&&"body"!==i.nodeName.toLowerCase()&&e(i).blur()}catch(n){}this._hide(this.uiDialog,this.options.hide,function(){s._trigger("close",t)})}},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(t,i){var s=!1,n=this.uiDialog.siblings(".ui-front:visible").map(function(){return+e(this).css("z-index")}).get(),a=Math.max.apply(null,n);return a>=+this.uiDialog.css("z-index")&&(this.uiDialog.css("z-index",a+1),s=!0),s&&!i&&this._trigger("focus",t),s},open:function(){var t=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=e(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){t._focusTabbable(),t._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var e=this._focusedElement;e||(e=this.element.find("[autofocus]")),e.length||(e=this.element.find(":tabbable")),e.length||(e=this.uiDialogButtonPane.find(":tabbable")),e.length||(e=this.uiDialogTitlebarClose.filter(":tabbable")),e.length||(e=this.uiDialog),e.eq(0).focus()},_keepFocus:function(t){function i(){var t=this.document[0].activeElement,i=this.uiDialog[0]===t||e.contains(this.uiDialog[0],t);i||this._focusTabbable()}t.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=e("
    ").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(t){if(this.options.closeOnEscape&&!t.isDefaultPrevented()&&t.keyCode&&t.keyCode===e.ui.keyCode.ESCAPE)return t.preventDefault(),this.close(t),void 0; +if(t.keyCode===e.ui.keyCode.TAB&&!t.isDefaultPrevented()){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");t.target!==n[0]&&t.target!==this.uiDialog[0]||t.shiftKey?t.target!==s[0]&&t.target!==this.uiDialog[0]||!t.shiftKey||(this._delay(function(){n.focus()}),t.preventDefault()):(this._delay(function(){s.focus()}),t.preventDefault())}},mousedown:function(e){this._moveToTop(e)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var t;this.uiDialogTitlebar=e("
    ").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(t){e(t.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=e("").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(e){e.preventDefault(),this.close(e)}}),t=e("").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(t),this.uiDialog.attr({"aria-labelledby":t.attr("id")})},_title:function(e){this.options.title||e.html(" "),e.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=e("
    ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=e("
    ").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var t=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),e.isEmptyObject(i)||e.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),void 0):(e.each(i,function(i,s){var n,a;s=e.isFunction(s)?{click:s,text:i}:s,s=e.extend({type:"button"},s),n=s.click,s.click=function(){n.apply(t.element[0],arguments)},a={icons:s.icons,text:s.showText},delete s.icons,delete s.showText,e("",s).button(a).appendTo(t.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function t(e){return{position:e.position,offset:e.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){e(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,t(n))},drag:function(e,s){i._trigger("drag",e,t(s))},stop:function(n,a){var o=a.offset.left-i.document.scrollLeft(),r=a.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(o>=0?"+":"")+o+" "+"top"+(r>=0?"+":"")+r,of:i.window},e(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,t(a))}})},_makeResizable:function(){function t(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}var i=this,s=this.options,n=s.resizable,a=this.uiDialog.css("position"),o="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:o,start:function(s,n){e(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,t(n))},resize:function(e,s){i._trigger("resize",e,t(s))},stop:function(n,a){var o=i.uiDialog.offset(),r=o.left-i.document.scrollLeft(),h=o.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(h>=0?"+":"")+h,of:i.window},e(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,t(a))}}).css("position",a)},_trackFocus:function(){this._on(this.widget(),{focusin:function(t){this._makeFocusTarget(),this._focusedElement=e(t.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var t=this._trackingInstances(),i=e.inArray(this,t);-1!==i&&t.splice(i,1)},_trackingInstances:function(){var e=this.document.data("ui-dialog-instances");return e||(e=[],this.document.data("ui-dialog-instances",e)),e},_minHeight:function(){var e=this.options;return"auto"===e.height?e.minHeight:Math.min(e.minHeight,e.height)},_position:function(){var e=this.uiDialog.is(":visible");e||this.uiDialog.show(),this.uiDialog.position(this.options.position),e||this.uiDialog.hide()},_setOptions:function(t){var i=this,s=!1,n={};e.each(t,function(e,t){i._setOption(e,t),e in i.sizeRelatedOptions&&(s=!0),e in i.resizableRelatedOptions&&(n[e]=t)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,t){var i,s,n=this.uiDialog;"dialogClass"===e&&n.removeClass(this.options.dialogClass).addClass(t),"disabled"!==e&&(this._super(e,t),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:""+t}),"draggable"===e&&(i=n.is(":data(ui-draggable)"),i&&!t&&n.draggable("destroy"),!i&&t&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(s=n.is(":data(ui-resizable)"),s&&!t&&n.resizable("destroy"),s&&"string"==typeof t&&n.resizable("option","handles",t),s||t===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var e,t,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),e=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),t=Math.max(0,s.minHeight-e),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-e):"none","auto"===s.height?this.element.css({minHeight:t,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-e)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var t=e(this);return e("
    ").css({position:"absolute",width:t.outerWidth(),height:t.outerHeight()}).appendTo(t.parent()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(t){return e(t.target).closest(".ui-dialog").length?!0:!!e(t.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var t=!0;this._delay(function(){t=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(e){t||this._allowInteraction(e)||(e.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=e("
    ").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var e=this.document.data("ui-dialog-overlays")-1;e?this.document.data("ui-dialog-overlays",e):this.document.unbind("focusin").removeData("ui-dialog-overlays"),this.overlay.remove(),this.overlay=null}}}),e.widget("ui.droppable",{version:"1.11.4",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var t,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=e.isFunction(s)?s:function(e){return e.is(s)},this.proportions=function(){return arguments.length?(t=arguments[0],void 0):t?t:t={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this.element.addClass("ui-droppable")},_addToManager:function(t){e.ui.ddmanager.droppables[t]=e.ui.ddmanager.droppables[t]||[],e.ui.ddmanager.droppables[t].push(this)},_splice:function(e){for(var t=0;e.length>t;t++)e[t]===this&&e.splice(t,1)},_destroy:function(){var t=e.ui.ddmanager.droppables[this.options.scope];this._splice(t),this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(t,i){if("accept"===t)this.accept=e.isFunction(i)?i:function(e){return e.is(i)};else if("scope"===t){var s=e.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(t,i)},_activate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",t,this.ui(i))},_deactivate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",t,this.ui(i))},_over:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",t,this.ui(i)))},_out:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",t,this.ui(i)))},_drop:function(t,i){var s=i||e.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=e(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&e.ui.intersect(s,e.extend(i,{offset:i.element.offset()}),i.options.tolerance,t)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",t,this.ui(s)),this.element):!1):!1},ui:function(e){return{draggable:e.currentItem||e.element,helper:e.helper,position:e.position,offset:e.positionAbs}}}),e.ui.intersect=function(){function e(e,t,i){return e>=t&&t+i>e}return function(t,i,s,n){if(!i.offset)return!1;var a=(t.positionAbs||t.position.absolute).left+t.margins.left,o=(t.positionAbs||t.position.absolute).top+t.margins.top,r=a+t.helperProportions.width,h=o+t.helperProportions.height,l=i.offset.left,u=i.offset.top,d=l+i.proportions().width,c=u+i.proportions().height;switch(s){case"fit":return a>=l&&d>=r&&o>=u&&c>=h;case"intersect":return a+t.helperProportions.width/2>l&&d>r-t.helperProportions.width/2&&o+t.helperProportions.height/2>u&&c>h-t.helperProportions.height/2;case"pointer":return e(n.pageY,u,i.proportions().height)&&e(n.pageX,l,i.proportions().width);case"touch":return(o>=u&&c>=o||h>=u&&c>=h||u>o&&h>c)&&(a>=l&&d>=a||r>=l&&d>=r||l>a&&r>d);default:return!1}}}(),e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,i){var s,n,a=e.ui.ddmanager.droppables[t.options.scope]||[],o=i?i.type:null,r=(t.currentItem||t.element).find(":data(ui-droppable)").addBack();e:for(s=0;a.length>s;s++)if(!(a[s].options.disabled||t&&!a[s].accept.call(a[s].element[0],t.currentItem||t.element))){for(n=0;r.length>n;n++)if(r[n]===a[s].element[0]){a[s].proportions().height=0;continue e}a[s].visible="none"!==a[s].element.css("display"),a[s].visible&&("mousedown"===o&&a[s]._activate.call(a[s],i),a[s].offset=a[s].element.offset(),a[s].proportions({width:a[s].element[0].offsetWidth,height:a[s].element[0].offsetHeight}))}},drop:function(t,i){var s=!1;return e.each((e.ui.ddmanager.droppables[t.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&e.ui.intersect(t,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],t.currentItem||t.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(t,i){t.element.parentsUntil("body").bind("scroll.droppable",function(){t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)})},drag:function(t,i){t.options.refreshPositions&&e.ui.ddmanager.prepareOffsets(t,i),e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,a,o=e.ui.intersect(t,this,this.options.tolerance,i),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,a=this.element.parents(":data(ui-droppable)").filter(function(){return e(this).droppable("instance").options.scope===n}),a.length&&(s=e(a[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(t,i){t.element.parentsUntil("body").unbind("scroll.droppable"),t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)}},e.ui.droppable;var y="ui-effects-",b=e;e.effects={effect:{}},function(e,t){function i(e,t,i){var s=d[t.type]||{};return null==e?i||!t.def?null:t.def:(e=s.floor?~~e:parseFloat(e),isNaN(e)?t.def:s.mod?(e+s.mod)%s.mod:0>e?0:e>s.max?s.max:e)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(e,a){var o,r=a.re.exec(i),h=r&&a.parse(r),l=a.space||"rgba";return h?(o=s[l](h),s[u[l].cache]=o[u[l].cache],n=s._rgba=o._rgba,!1):t}),n.length?("0,0,0,0"===n.join()&&e.extend(n,a.transparent),s):a[i]}function n(e,t,i){return i=(i+1)%1,1>6*i?e+6*(t-e)*i:1>2*i?t:2>3*i?e+6*(t-e)*(2/3-i):e}var a,o="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(e){return[e[1],e[2],e[3],e[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(e){return[2.55*e[1],2.55*e[2],2.55*e[3],e[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(e){return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(e){return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(e){return[e[1],e[2]/100,e[3]/100,e[4]]}}],l=e.Color=function(t,i,s,n){return new e.Color.fn.parse(t,i,s,n)},u={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},d={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},c=l.support={},p=e("

    ")[0],f=e.each;p.style.cssText="background-color:rgba(1,1,1,.5)",c.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(u,function(e,t){t.cache="_"+e,t.props.alpha={idx:3,type:"percent",def:1}}),l.fn=e.extend(l.prototype,{parse:function(n,o,r,h){if(n===t)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=e(n).css(o),o=t);var d=this,c=e.type(n),p=this._rgba=[];return o!==t&&(n=[n,o,r,h],c="array"),"string"===c?this.parse(s(n)||a._default):"array"===c?(f(u.rgba.props,function(e,t){p[t.idx]=i(n[t.idx],t)}),this):"object"===c?(n instanceof l?f(u,function(e,t){n[t.cache]&&(d[t.cache]=n[t.cache].slice())}):f(u,function(t,s){var a=s.cache;f(s.props,function(e,t){if(!d[a]&&s.to){if("alpha"===e||null==n[e])return;d[a]=s.to(d._rgba)}d[a][t.idx]=i(n[e],t,!0)}),d[a]&&0>e.inArray(null,d[a].slice(0,3))&&(d[a][3]=1,s.from&&(d._rgba=s.from(d[a])))}),this):t},is:function(e){var i=l(e),s=!0,n=this;return f(u,function(e,a){var o,r=i[a.cache];return r&&(o=n[a.cache]||a.to&&a.to(n._rgba)||[],f(a.props,function(e,i){return null!=r[i.idx]?s=r[i.idx]===o[i.idx]:t})),s}),s},_space:function(){var e=[],t=this;return f(u,function(i,s){t[s.cache]&&e.push(i)}),e.pop()},transition:function(e,t){var s=l(e),n=s._space(),a=u[n],o=0===this.alpha()?l("transparent"):this,r=o[a.cache]||a.to(o._rgba),h=r.slice();return s=s[a.cache],f(a.props,function(e,n){var a=n.idx,o=r[a],l=s[a],u=d[n.type]||{};null!==l&&(null===o?h[a]=l:(u.mod&&(l-o>u.mod/2?o+=u.mod:o-l>u.mod/2&&(o-=u.mod)),h[a]=i((l-o)*t+o,n)))}),this[n](h)},blend:function(t){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(t)._rgba;return l(e.map(i,function(e,t){return(1-s)*n[t]+s*e}))},toRgbaString:function(){var t="rgba(",i=e.map(this._rgba,function(e,t){return null==e?t>2?1:0:e});return 1===i[3]&&(i.pop(),t="rgb("),t+i.join()+")"},toHslaString:function(){var t="hsla(",i=e.map(this.hsla(),function(e,t){return null==e&&(e=t>2?1:0),t&&3>t&&(e=Math.round(100*e)+"%"),e});return 1===i[3]&&(i.pop(),t="hsl("),t+i.join()+")"},toHexString:function(t){var i=this._rgba.slice(),s=i.pop();return t&&i.push(~~(255*s)),"#"+e.map(i,function(e){return e=(e||0).toString(16),1===e.length?"0"+e:e}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,u.hsla.to=function(e){if(null==e[0]||null==e[1]||null==e[2])return[null,null,null,e[3]];var t,i,s=e[0]/255,n=e[1]/255,a=e[2]/255,o=e[3],r=Math.max(s,n,a),h=Math.min(s,n,a),l=r-h,u=r+h,d=.5*u;return t=h===r?0:s===r?60*(n-a)/l+360:n===r?60*(a-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=d?l/u:l/(2-u),[Math.round(t)%360,i,d,null==o?1:o]},u.hsla.from=function(e){if(null==e[0]||null==e[1]||null==e[2])return[null,null,null,e[3]];var t=e[0]/360,i=e[1],s=e[2],a=e[3],o=.5>=s?s*(1+i):s+i-s*i,r=2*s-o;return[Math.round(255*n(r,o,t+1/3)),Math.round(255*n(r,o,t)),Math.round(255*n(r,o,t-1/3)),a]},f(u,function(s,n){var a=n.props,o=n.cache,h=n.to,u=n.from;l.fn[s]=function(s){if(h&&!this[o]&&(this[o]=h(this._rgba)),s===t)return this[o].slice();var n,r=e.type(s),d="array"===r||"object"===r?s:arguments,c=this[o].slice();return f(a,function(e,t){var s=d["object"===r?e:t.idx];null==s&&(s=c[t.idx]),c[t.idx]=i(s,t)}),u?(n=l(u(c)),n[o]=c,n):l(c)},f(a,function(t,i){l.fn[t]||(l.fn[t]=function(n){var a,o=e.type(n),h="alpha"===t?this._hsla?"hsla":"rgba":s,l=this[h](),u=l[i.idx];return"undefined"===o?u:("function"===o&&(n=n.call(this,u),o=e.type(n)),null==n&&i.empty?this:("string"===o&&(a=r.exec(n),a&&(n=u+parseFloat(a[2])*("+"===a[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(t){var i=t.split(" ");f(i,function(t,i){e.cssHooks[i]={set:function(t,n){var a,o,r="";if("transparent"!==n&&("string"!==e.type(n)||(a=s(n)))){if(n=l(a||n),!c.rgba&&1!==n._rgba[3]){for(o="backgroundColor"===i?t.parentNode:t;(""===r||"transparent"===r)&&o&&o.style;)try{r=e.css(o,"backgroundColor"),o=o.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{t.style[i]=n}catch(h){}}},e.fx.step[i]=function(t){t.colorInit||(t.start=l(t.elem,i),t.end=l(t.end),t.colorInit=!0),e.cssHooks[i].set(t.elem,t.start.transition(t.end,t.pos))}})},l.hook(o),e.cssHooks.borderColor={expand:function(e){var t={};return f(["Top","Right","Bottom","Left"],function(i,s){t["border"+s+"Color"]=e}),t}},a=e.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(b),function(){function t(t){var i,s,n=t.ownerDocument.defaultView?t.ownerDocument.defaultView.getComputedStyle(t,null):t.currentStyle,a={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(a[e.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(a[i]=n[i]);return a}function i(t,i){var s,a,o={};for(s in i)a=i[s],t[s]!==a&&(n[s]||(e.fx.step[s]||!isNaN(parseFloat(a)))&&(o[s]=a));return o}var s=["add","remove","toggle"],n={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};e.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(t,i){e.fx.step[i]=function(e){("none"!==e.end&&!e.setAttr||1===e.pos&&!e.setAttr)&&(b.style(e.elem,i,e.end),e.setAttr=!0)}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e.effects.animateClass=function(n,a,o,r){var h=e.speed(a,o,r);return this.queue(function(){var a,o=e(this),r=o.attr("class")||"",l=h.children?o.find("*").addBack():o;l=l.map(function(){var i=e(this);return{el:i,start:t(this)}}),a=function(){e.each(s,function(e,t){n[t]&&o[t+"Class"](n[t])})},a(),l=l.map(function(){return this.end=t(this.el[0]),this.diff=i(this.start,this.end),this}),o.attr("class",r),l=l.map(function(){var t=this,i=e.Deferred(),s=e.extend({},h,{queue:!1,complete:function(){i.resolve(t)}});return this.el.animate(this.diff,s),i.promise()}),e.when.apply(e,l.get()).done(function(){a(),e.each(arguments,function(){var t=this.el;e.each(this.diff,function(e){t.css(e,"")})}),h.complete.call(o[0])})})},e.fn.extend({addClass:function(t){return function(i,s,n,a){return s?e.effects.animateClass.call(this,{add:i},s,n,a):t.apply(this,arguments)}}(e.fn.addClass),removeClass:function(t){return function(i,s,n,a){return arguments.length>1?e.effects.animateClass.call(this,{remove:i},s,n,a):t.apply(this,arguments)}}(e.fn.removeClass),toggleClass:function(t){return function(i,s,n,a,o){return"boolean"==typeof s||void 0===s?n?e.effects.animateClass.call(this,s?{add:i}:{remove:i},n,a,o):t.apply(this,arguments):e.effects.animateClass.call(this,{toggle:i},s,n,a)}}(e.fn.toggleClass),switchClass:function(t,i,s,n,a){return e.effects.animateClass.call(this,{add:i,remove:t},s,n,a)}})}(),function(){function t(t,i,s,n){return e.isPlainObject(t)&&(i=t,t=t.effect),t={effect:t},null==i&&(i={}),e.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||e.fx.speeds[i])&&(n=s,s=i,i={}),e.isFunction(s)&&(n=s,s=null),i&&e.extend(t,i),s=s||i.duration,t.duration=e.fx.off?0:"number"==typeof s?s:s in e.fx.speeds?e.fx.speeds[s]:e.fx.speeds._default,t.complete=n||i.complete,t}function i(t){return!t||"number"==typeof t||e.fx.speeds[t]?!0:"string"!=typeof t||e.effects.effect[t]?e.isFunction(t)?!0:"object"!=typeof t||t.effect?!1:!0:!0}e.extend(e.effects,{version:"1.11.4",save:function(e,t){for(var i=0;t.length>i;i++)null!==t[i]&&e.data(y+t[i],e[0].style[t[i]])},restore:function(e,t){var i,s;for(s=0;t.length>s;s++)null!==t[s]&&(i=e.data(y+t[s]),void 0===i&&(i=""),e.css(t[s],i))},setMode:function(e,t){return"toggle"===t&&(t=e.is(":hidden")?"show":"hide"),t},getBaseline:function(e,t){var i,s;switch(e[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=e[0]/t.height}switch(e[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=e[1]/t.width}return{x:s,y:i}},createWrapper:function(t){if(t.parent().is(".ui-effects-wrapper"))return t.parent();var i={width:t.outerWidth(!0),height:t.outerHeight(!0),"float":t.css("float")},s=e("

    ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:t.width(),height:t.height()},a=document.activeElement;try{a.id}catch(o){a=document.body}return t.wrap(s),(t[0]===a||e.contains(t[0],a))&&e(a).focus(),s=t.parent(),"static"===t.css("position")?(s.css({position:"relative"}),t.css({position:"relative"})):(e.extend(i,{position:t.css("position"),zIndex:t.css("z-index")}),e.each(["top","left","bottom","right"],function(e,s){i[s]=t.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),t.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),t.css(n),s.css(i).show()},removeWrapper:function(t){var i=document.activeElement;return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),(t[0]===i||e.contains(t[0],i))&&e(i).focus()),t},setTransition:function(t,i,s,n){return n=n||{},e.each(i,function(e,i){var a=t.cssUnit(i);a[0]>0&&(n[i]=a[0]*s+a[1])}),n}}),e.fn.extend({effect:function(){function i(t){function i(){e.isFunction(a)&&a.call(n[0]),e.isFunction(t)&&t()}var n=e(this),a=s.complete,r=s.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),i()):o.call(n[0],s,i)}var s=t.apply(this,arguments),n=s.mode,a=s.queue,o=e.effects.effect[s.effect];return e.fx.off||!o?n?this[n](s.duration,s.complete):this.each(function(){s.complete&&s.complete.call(this)}):a===!1?this.each(i):this.queue(a||"fx",i)},show:function(e){return function(s){if(i(s))return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="show",this.effect.call(this,n)}}(e.fn.show),hide:function(e){return function(s){if(i(s))return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="hide",this.effect.call(this,n)}}(e.fn.hide),toggle:function(e){return function(s){if(i(s)||"boolean"==typeof s)return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)}}(e.fn.toggle),cssUnit:function(t){var i=this.css(t),s=[];return e.each(["em","px","%","pt"],function(e,t){i.indexOf(t)>0&&(s=[parseFloat(i),t])}),s}})}(),function(){var t={};e.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,i){t[i]=function(t){return Math.pow(t,e+2)}}),e.extend(t,{Sine:function(e){return 1-Math.cos(e*Math.PI/2)},Circ:function(e){return 1-Math.sqrt(1-e*e)},Elastic:function(e){return 0===e||1===e?e:-Math.pow(2,8*(e-1))*Math.sin((80*(e-1)-7.5)*Math.PI/15)},Back:function(e){return e*e*(3*e-2)},Bounce:function(e){for(var t,i=4;((t=Math.pow(2,--i))-1)/11>e;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*t-2)/22-e,2)}}),e.each(t,function(t,i){e.easing["easeIn"+t]=i,e.easing["easeOut"+t]=function(e){return 1-i(1-e)},e.easing["easeInOut"+t]=function(e){return.5>e?i(2*e)/2:1-i(-2*e+2)/2}})}(),e.effects,e.effects.effect.blind=function(t,i){var s,n,a,o=e(this),r=/up|down|vertical/,h=/up|left|vertical|horizontal/,l=["position","top","bottom","left","right","height","width"],u=e.effects.setMode(o,t.mode||"hide"),d=t.direction||"up",c=r.test(d),p=c?"height":"width",f=c?"top":"left",m=h.test(d),g={},v="show"===u;o.parent().is(".ui-effects-wrapper")?e.effects.save(o.parent(),l):e.effects.save(o,l),o.show(),s=e.effects.createWrapper(o).css({overflow:"hidden"}),n=s[p](),a=parseFloat(s.css(f))||0,g[p]=v?n:0,m||(o.css(c?"bottom":"right",0).css(c?"top":"left","auto").css({position:"absolute"}),g[f]=v?a:n+a),v&&(s.css(p,0),m||s.css(f,a+n)),s.animate(g,{duration:t.duration,easing:t.easing,queue:!1,complete:function(){"hide"===u&&o.hide(),e.effects.restore(o,l),e.effects.removeWrapper(o),i()}})},e.effects.effect.bounce=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","height","width"],h=e.effects.setMode(o,t.mode||"effect"),l="hide"===h,u="show"===h,d=t.direction||"up",c=t.distance,p=t.times||5,f=2*p+(u||l?1:0),m=t.duration/f,g=t.easing,v="up"===d||"down"===d?"top":"left",y="up"===d||"left"===d,b=o.queue(),_=b.length;for((u||l)&&r.push("opacity"),e.effects.save(o,r),o.show(),e.effects.createWrapper(o),c||(c=o["top"===v?"outerHeight":"outerWidth"]()/3),u&&(a={opacity:1},a[v]=0,o.css("opacity",0).css(v,y?2*-c:2*c).animate(a,m,g)),l&&(c/=Math.pow(2,p-1)),a={},a[v]=0,s=0;p>s;s++)n={},n[v]=(y?"-=":"+=")+c,o.animate(n,m,g).animate(a,m,g),c=l?2*c:c/2;l&&(n={opacity:0},n[v]=(y?"-=":"+=")+c,o.animate(n,m,g)),o.queue(function(){l&&o.hide(),e.effects.restore(o,r),e.effects.removeWrapper(o),i()}),_>1&&b.splice.apply(b,[1,0].concat(b.splice(_,f+1))),o.dequeue()},e.effects.effect.clip=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","height","width"],h=e.effects.setMode(o,t.mode||"hide"),l="show"===h,u=t.direction||"vertical",d="vertical"===u,c=d?"height":"width",p=d?"top":"left",f={};e.effects.save(o,r),o.show(),s=e.effects.createWrapper(o).css({overflow:"hidden"}),n="IMG"===o[0].tagName?s:o,a=n[c](),l&&(n.css(c,0),n.css(p,a/2)),f[c]=l?a:0,f[p]=l?0:a/2,n.animate(f,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){l||o.hide(),e.effects.restore(o,r),e.effects.removeWrapper(o),i()}})},e.effects.effect.drop=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","opacity","height","width"],o=e.effects.setMode(n,t.mode||"hide"),r="show"===o,h=t.direction||"left",l="up"===h||"down"===h?"top":"left",u="up"===h||"left"===h?"pos":"neg",d={opacity:r?1:0};e.effects.save(n,a),n.show(),e.effects.createWrapper(n),s=t.distance||n["top"===l?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(l,"pos"===u?-s:s),d[l]=(r?"pos"===u?"+=":"-=":"pos"===u?"-=":"+=")+s,n.animate(d,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}})},e.effects.effect.explode=function(t,i){function s(){b.push(this),b.length===d*c&&n()}function n(){p.css({visibility:"visible"}),e(b).remove(),m||p.hide(),i()}var a,o,r,h,l,u,d=t.pieces?Math.round(Math.sqrt(t.pieces)):3,c=d,p=e(this),f=e.effects.setMode(p,t.mode||"hide"),m="show"===f,g=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/c),y=Math.ceil(p.outerHeight()/d),b=[];for(a=0;d>a;a++)for(h=g.top+a*y,u=a-(d-1)/2,o=0;c>o;o++)r=g.left+o*v,l=o-(c-1)/2,p.clone().appendTo("body").wrap("
    ").css({position:"absolute",visibility:"visible",left:-o*v,top:-a*y}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:y,left:r+(m?l*v:0),top:h+(m?u*y:0),opacity:m?0:1}).animate({left:r+(m?0:l*v),top:h+(m?0:u*y),opacity:m?1:0},t.duration||500,t.easing,s)},e.effects.effect.fade=function(t,i){var s=e(this),n=e.effects.setMode(s,t.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:t.duration,easing:t.easing,complete:i})},e.effects.effect.fold=function(t,i){var s,n,a=e(this),o=["position","top","bottom","left","right","height","width"],r=e.effects.setMode(a,t.mode||"hide"),h="show"===r,l="hide"===r,u=t.size||15,d=/([0-9]+)%/.exec(u),c=!!t.horizFirst,p=h!==c,f=p?["width","height"]:["height","width"],m=t.duration/2,g={},v={};e.effects.save(a,o),a.show(),s=e.effects.createWrapper(a).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],d&&(u=parseInt(d[1],10)/100*n[l?0:1]),h&&s.css(c?{height:0,width:u}:{height:u,width:0}),g[f[0]]=h?n[0]:u,v[f[1]]=h?n[1]:0,s.animate(g,m,t.easing).animate(v,m,t.easing,function(){l&&a.hide(),e.effects.restore(a,o),e.effects.removeWrapper(a),i()})},e.effects.effect.highlight=function(t,i){var s=e(this),n=["backgroundImage","backgroundColor","opacity"],a=e.effects.setMode(s,t.mode||"show"),o={backgroundColor:s.css("backgroundColor")};"hide"===a&&(o.opacity=0),e.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:t.color||"#ffff99"}).animate(o,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===a&&s.hide(),e.effects.restore(s,n),i()}})},e.effects.effect.size=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],h=["position","top","bottom","left","right","overflow","opacity"],l=["width","height","overflow"],u=["fontSize"],d=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],c=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=e.effects.setMode(o,t.mode||"effect"),f=t.restore||"effect"!==p,m=t.scale||"both",g=t.origin||["middle","center"],v=o.css("position"),y=f?r:h,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&o.show(),s={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},"toggle"===t.mode&&"show"===p?(o.from=t.to||b,o.to=t.from||s):(o.from=t.from||("show"===p?b:s),o.to=t.to||("hide"===p?b:s)),a={from:{y:o.from.height/s.height,x:o.from.width/s.width},to:{y:o.to.height/s.height,x:o.to.width/s.width}},("box"===m||"both"===m)&&(a.from.y!==a.to.y&&(y=y.concat(d),o.from=e.effects.setTransition(o,d,a.from.y,o.from),o.to=e.effects.setTransition(o,d,a.to.y,o.to)),a.from.x!==a.to.x&&(y=y.concat(c),o.from=e.effects.setTransition(o,c,a.from.x,o.from),o.to=e.effects.setTransition(o,c,a.to.x,o.to))),("content"===m||"both"===m)&&a.from.y!==a.to.y&&(y=y.concat(u).concat(l),o.from=e.effects.setTransition(o,u,a.from.y,o.from),o.to=e.effects.setTransition(o,u,a.to.y,o.to)),e.effects.save(o,y),o.show(),e.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),g&&(n=e.effects.getBaseline(g,s),o.from.top=(s.outerHeight-o.outerHeight())*n.y,o.from.left=(s.outerWidth-o.outerWidth())*n.x,o.to.top=(s.outerHeight-o.to.outerHeight)*n.y,o.to.left=(s.outerWidth-o.to.outerWidth)*n.x),o.css(o.from),("content"===m||"both"===m)&&(d=d.concat(["marginTop","marginBottom"]).concat(u),c=c.concat(["marginLeft","marginRight"]),l=r.concat(d).concat(c),o.find("*[width]").each(function(){var i=e(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()}; +f&&e.effects.save(i,l),i.from={height:s.height*a.from.y,width:s.width*a.from.x,outerHeight:s.outerHeight*a.from.y,outerWidth:s.outerWidth*a.from.x},i.to={height:s.height*a.to.y,width:s.width*a.to.x,outerHeight:s.height*a.to.y,outerWidth:s.width*a.to.x},a.from.y!==a.to.y&&(i.from=e.effects.setTransition(i,d,a.from.y,i.from),i.to=e.effects.setTransition(i,d,a.to.y,i.to)),a.from.x!==a.to.x&&(i.from=e.effects.setTransition(i,c,a.from.x,i.from),i.to=e.effects.setTransition(i,c,a.to.x,i.to)),i.css(i.from),i.animate(i.to,t.duration,t.easing,function(){f&&e.effects.restore(i,l)})})),o.animate(o.to,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){0===o.to.opacity&&o.css("opacity",o.from.opacity),"hide"===p&&o.hide(),e.effects.restore(o,y),f||("static"===v?o.css({position:"relative",top:o.to.top,left:o.to.left}):e.each(["top","left"],function(e,t){o.css(t,function(t,i){var s=parseInt(i,10),n=e?o.to.left:o.to.top;return"auto"===i?n+"px":s+n+"px"})})),e.effects.removeWrapper(o),i()}})},e.effects.effect.scale=function(t,i){var s=e(this),n=e.extend(!0,{},t),a=e.effects.setMode(s,t.mode||"effect"),o=parseInt(t.percent,10)||(0===parseInt(t.percent,10)?0:"hide"===a?0:100),r=t.direction||"both",h=t.origin,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},u={y:"horizontal"!==r?o/100:1,x:"vertical"!==r?o/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==a&&(n.origin=h||["middle","center"],n.restore=!0),n.from=t.from||("show"===a?{height:0,width:0,outerHeight:0,outerWidth:0}:l),n.to={height:l.height*u.y,width:l.width*u.x,outerHeight:l.outerHeight*u.y,outerWidth:l.outerWidth*u.x},n.fade&&("show"===a&&(n.from.opacity=0,n.to.opacity=1),"hide"===a&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},e.effects.effect.puff=function(t,i){var s=e(this),n=e.effects.setMode(s,t.mode||"hide"),a="hide"===n,o=parseInt(t.percent,10)||150,r=o/100,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};e.extend(t,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:a?o:100,from:a?h:{height:h.height*r,width:h.width*r,outerHeight:h.outerHeight*r,outerWidth:h.outerWidth*r}}),s.effect(t)},e.effects.effect.pulsate=function(t,i){var s,n=e(this),a=e.effects.setMode(n,t.mode||"show"),o="show"===a,r="hide"===a,h=o||"hide"===a,l=2*(t.times||5)+(h?1:0),u=t.duration/l,d=0,c=n.queue(),p=c.length;for((o||!n.is(":visible"))&&(n.css("opacity",0).show(),d=1),s=1;l>s;s++)n.animate({opacity:d},u,t.easing),d=1-d;n.animate({opacity:d},u,t.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&c.splice.apply(c,[1,0].concat(c.splice(p,l+1))),n.dequeue()},e.effects.effect.shake=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","height","width"],o=e.effects.setMode(n,t.mode||"effect"),r=t.direction||"left",h=t.distance||20,l=t.times||3,u=2*l+1,d=Math.round(t.duration/u),c="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},m={},g={},v=n.queue(),y=v.length;for(e.effects.save(n,a),n.show(),e.effects.createWrapper(n),f[c]=(p?"-=":"+=")+h,m[c]=(p?"+=":"-=")+2*h,g[c]=(p?"-=":"+=")+2*h,n.animate(f,d,t.easing),s=1;l>s;s++)n.animate(m,d,t.easing).animate(g,d,t.easing);n.animate(m,d,t.easing).animate(f,d/2,t.easing).queue(function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}),y>1&&v.splice.apply(v,[1,0].concat(v.splice(y,u+1))),n.dequeue()},e.effects.effect.slide=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","width","height"],o=e.effects.setMode(n,t.mode||"show"),r="show"===o,h=t.direction||"left",l="up"===h||"down"===h?"top":"left",u="up"===h||"left"===h,d={};e.effects.save(n,a),n.show(),s=t.distance||n["top"===l?"outerHeight":"outerWidth"](!0),e.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(l,u?isNaN(s)?"-"+s:-s:s),d[l]=(r?u?"+=":"-=":u?"-=":"+=")+s,n.animate(d,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}})},e.effects.effect.transfer=function(t,i){var s=e(this),n=e(t.to),a="fixed"===n.css("position"),o=e("body"),r=a?o.scrollTop():0,h=a?o.scrollLeft():0,l=n.offset(),u={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},d=s.offset(),c=e("
    ").appendTo(document.body).addClass(t.className).css({top:d.top-r,left:d.left-h,height:s.innerHeight(),width:s.innerWidth(),position:a?"fixed":"absolute"}).animate(u,t.duration,t.easing,function(){c.remove(),i()})},e.widget("ui.progressbar",{version:"1.11.4",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=e("
    ").appendTo(this.element),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(e){return void 0===e?this.options.value:(this.options.value=this._constrainedValue(e),this._refreshValue(),void 0)},_constrainedValue:function(e){return void 0===e&&(e=this.options.value),this.indeterminate=e===!1,"number"!=typeof e&&(e=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,e))},_setOptions:function(e){var t=e.value;delete e.value,this._super(e),this.options.value=this._constrainedValue(t),this._refreshValue()},_setOption:function(e,t){"max"===e&&(t=Math.max(this.min,t)),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var t=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||t>this.min).toggleClass("ui-corner-right",t===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=e("
    ").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":t}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==t&&(this.oldValue=t,this._trigger("change")),t===this.options.max&&this._trigger("complete")}}),e.widget("ui.selectable",e.ui.mouse,{version:"1.11.4",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var t,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){t=e(i.options.filter,i.element[0]),t.addClass("ui-selectee"),t.each(function(){var t=e(this),i=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:i.left,top:i.top,right:i.left+t.outerWidth(),bottom:i.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=t.addClass("ui-selectee"),this._mouseInit(),this.helper=e("
    ")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var i=this,s=this.options;this.opos=[t.pageX,t.pageY],this.options.disabled||(this.selectees=e(s.filter,this.element[0]),this._trigger("start",t),e(s.appendTo).append(this.helper),this.helper.css({left:t.pageX,top:t.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=e.data(this,"selectable-item");s.startselected=!0,t.metaKey||t.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",t,{unselecting:s.element}))}),e(t.target).parents().addBack().each(function(){var s,n=e.data(this,"selectable-item");return n?(s=!t.metaKey&&!t.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",t,{selecting:n.element}):i._trigger("unselecting",t,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(t){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,a=this.opos[0],o=this.opos[1],r=t.pageX,h=t.pageY;return a>r&&(i=r,r=a,a=i),o>h&&(i=h,h=o,o=i),this.helper.css({left:a,top:o,width:r-a,height:h-o}),this.selectees.each(function(){var i=e.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||a>i.right||i.top>h||o>i.bottom):"fit"===n.tolerance&&(l=i.left>a&&r>i.right&&i.top>o&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",t,{selecting:i.element}))):(i.selecting&&((t.metaKey||t.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",t,{unselecting:i.element}))),i.selected&&(t.metaKey||t.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",t,{unselecting:i.element})))))}),!1}},_mouseStop:function(t){var i=this;return this.dragged=!1,e(".ui-unselecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",t,{unselected:s.element})}),e(".ui-selecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",t,{selected:s.element})}),this._trigger("stop",t),this.helper.remove(),!1}}),e.widget("ui.selectmenu",{version:"1.11.4",defaultElement:"",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var t={},i=this.element;return e.each(["min","max","step"],function(e,s){var n=i.attr(s);void 0!==n&&n.length&&(t[s]=n)}),t},_events:{keydown:function(e){this._start(e)&&this._keydown(e)&&e.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",e),void 0)},mousewheel:function(e,t){if(t){if(!this.spinning&&!this._start(e))return!1;this._spin((t>0?1:-1)*this.options.step,e),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(e)},100),e.preventDefault()}},"mousedown .ui-spinner-button":function(t){function i(){var e=this.element[0]===this.document[0].activeElement;e||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),t.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(t)!==!1&&this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(t){return e(t.currentTarget).hasClass("ui-state-active")?this._start(t)===!1?!1:(this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var e=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=e.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*e.height())&&e.height()>0&&e.height(e.height()),this.options.disabled&&this.disable()},_keydown:function(t){var i=this.options,s=e.ui.keyCode;switch(t.keyCode){case s.UP:return this._repeat(null,1,t),!0;case s.DOWN:return this._repeat(null,-1,t),!0;case s.PAGE_UP:return this._repeat(null,i.page,t),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,t),!0}return!1},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""+""+""+""+""},_start:function(e){return this.spinning||this._trigger("start",e)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(e,t,i){e=e||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,t,i)},e),this._spin(t*this.options.step,i)},_spin:function(e,t){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+e*this._increment(this.counter)),this.spinning&&this._trigger("spin",t,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(t){var i=this.options.incremental;return i?e.isFunction(i)?i(t):Math.floor(t*t*t/5e4-t*t/500+17*t/200+1):1},_precision:function(){var e=this._precisionOf(this.options.step);return null!==this.options.min&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=""+e,i=t.indexOf(".");return-1===i?0:t.length-i-1},_adjustValue:function(e){var t,i,s=this.options;return t=null!==s.min?s.min:0,i=e-t,i=Math.round(i/s.step)*s.step,e=t+i,e=parseFloat(e.toFixed(this._precision())),null!==s.max&&e>s.max?s.max:null!==s.min&&s.min>e?s.min:e},_stop:function(e){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",e))},_setOption:function(e,t){if("culture"===e||"numberFormat"===e){var i=this._parse(this.element.val());return this.options[e]=t,this.element.val(this._format(i)),void 0}("max"===e||"min"===e||"step"===e)&&"string"==typeof t&&(t=this._parse(t)),"icons"===e&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(t.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(t.down)),this._super(e,t),"disabled"===e&&(this.widget().toggleClass("ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable"))},_setOptions:h(function(e){this._super(e)}),_parse:function(e){return"string"==typeof e&&""!==e&&(e=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(e,10,this.options.culture):+e),""===e||isNaN(e)?null:e},_format:function(e){return""===e?"":window.Globalize&&this.options.numberFormat?Globalize.format(e,this.options.numberFormat,this.options.culture):e},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var e=this.value();return null===e?!1:e===this._adjustValue(e)},_value:function(e,t){var i;""!==e&&(i=this._parse(e),null!==i&&(t||(i=this._adjustValue(i)),e=this._format(i))),this.element.val(e),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:h(function(e){this._stepUp(e)}),_stepUp:function(e){this._start()&&(this._spin((e||1)*this.options.step),this._stop())},stepDown:h(function(e){this._stepDown(e)}),_stepDown:function(e){this._start()&&(this._spin((e||1)*-this.options.step),this._stop())},pageUp:h(function(e){this._stepUp((e||1)*this.options.page)}),pageDown:h(function(e){this._stepDown((e||1)*this.options.page)}),value:function(e){return arguments.length?(h(this._value).call(this,e),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),e.widget("ui.tabs",{version:"1.11.4",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var e=/#.*$/;return function(t){var i,s;t=t.cloneNode(!1),i=t.href.replace(e,""),s=location.href.replace(e,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return t.hash.length>1&&i===s}}(),_create:function(){var t=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible),this._processTabs(),i.active=this._initialActive(),e.isArray(i.disabled)&&(i.disabled=e.unique(i.disabled.concat(e.map(this.tabs.filter(".ui-state-disabled"),function(e){return t.tabs.index(e)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):e(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var t=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===t&&(s&&this.tabs.each(function(i,n){return e(n).attr("aria-controls")===s?(t=i,!1):void 0}),null===t&&(t=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===t||-1===t)&&(t=this.tabs.length?0:!1)),t!==!1&&(t=this.tabs.index(this.tabs.eq(t)),-1===t&&(t=i?!1:0)),!i&&t===!1&&this.anchors.length&&(t=0),t},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):e()}},_tabKeydown:function(t){var i=e(this.document[0].activeElement).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(t)){switch(t.keyCode){case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:s++;break;case e.ui.keyCode.UP:case e.ui.keyCode.LEFT:n=!1,s--;break;case e.ui.keyCode.END:s=this.anchors.length-1;break;case e.ui.keyCode.HOME:s=0;break;case e.ui.keyCode.SPACE:return t.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case e.ui.keyCode.ENTER:return t.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}t.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),t.ctrlKey||t.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(t){this._handlePageNav(t)||t.ctrlKey&&t.keyCode===e.ui.keyCode.UP&&(t.preventDefault(),this.active.focus())},_handlePageNav:function(t){return t.altKey&&t.keyCode===e.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):t.altKey&&t.keyCode===e.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(t,i){function s(){return t>n&&(t=0),0>t&&(t=n),t}for(var n=this.tabs.length-1;-1!==e.inArray(s(),this.options.disabled);)t=i?t+1:t-1;return t},_focusNextTab:function(e,t){return e=this._findNextTab(e,t),this.tabs.eq(e).focus(),e},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):"disabled"===e?(this._setupDisabled(t),void 0):(this._super(e,t),"collapsible"===e&&(this.element.toggleClass("ui-tabs-collapsible",t),t||this.options.active!==!1||this._activate(0)),"event"===e&&this._setupEvents(t),"heightStyle"===e&&this._setupHeightStyle(t),void 0)},_sanitizeSelector:function(e){return e?e.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var t=this.options,i=this.tablist.children(":has(a[href])");t.disabled=e.map(i.filter(".ui-state-disabled"),function(e){return i.index(e)}),this._processTabs(),t.active!==!1&&this.anchors.length?this.active.length&&!e.contains(this.tablist[0],this.active[0])?this.tabs.length===t.disabled.length?(t.active=!1,this.active=e()):this._activate(this._findNextTab(Math.max(0,t.active-1),!1)):t.active=this.tabs.index(this.active):(t.active=!1,this.active=e()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var t=this,i=this.tabs,s=this.anchors,n=this.panels; +this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist").delegate("> li","mousedown"+this.eventNamespace,function(t){e(this).is(".ui-state-disabled")&&t.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){e(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return e("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=e(),this.anchors.each(function(i,s){var n,a,o,r=e(s).uniqueId().attr("id"),h=e(s).closest("li"),l=h.attr("aria-controls");t._isLocal(s)?(n=s.hash,o=n.substring(1),a=t.element.find(t._sanitizeSelector(n))):(o=h.attr("aria-controls")||e({}).uniqueId()[0].id,n="#"+o,a=t.element.find(n),a.length||(a=t._createPanel(o),a.insertAfter(t.panels[i-1]||t.tablist)),a.attr("aria-live","polite")),a.length&&(t.panels=t.panels.add(a)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":o,"aria-labelledby":r}),a.attr("aria-labelledby",r)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol,ul").eq(0)},_createPanel:function(t){return e("
    ").attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(t){e.isArray(t)&&(t.length?t.length===this.anchors.length&&(t=!0):t=!1);for(var i,s=0;i=this.tabs[s];s++)t===!0||-1!==e.inArray(s,t)?e(i).addClass("ui-state-disabled").attr("aria-disabled","true"):e(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=t},_setupEvents:function(t){var i={};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(e){e.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(t){var i,s=this.element.parent();"fill"===t?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var t=e(this),s=t.css("position");"absolute"!==s&&"fixed"!==s&&(i-=t.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=e(this).outerHeight(!0)}),this.panels.each(function(){e(this).height(Math.max(0,i-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===t&&(i=0,this.panels.each(function(){i=Math.max(i,e(this).height("").height())}).height(i))},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n.closest("li"),o=a[0]===s[0],r=o&&i.collapsible,h=r?e():this._getPanelForTab(a),l=s.length?this._getPanelForTab(s):e(),u={oldTab:s,oldPanel:l,newTab:r?e():a,newPanel:h};t.preventDefault(),a.hasClass("ui-state-disabled")||a.hasClass("ui-tabs-loading")||this.running||o&&!i.collapsible||this._trigger("beforeActivate",t,u)===!1||(i.active=r?!1:this.tabs.index(a),this.active=o?e():a,this.xhr&&this.xhr.abort(),l.length||h.length||e.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(a),t),this._toggle(t,u))},_toggle:function(t,i){function s(){a.running=!1,a._trigger("activate",t,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),o.length&&a.options.show?a._show(o,a.options.show,s):(o.show(),s())}var a=this,o=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),o.length&&r.length?i.oldTab.attr("tabIndex",-1):o.length&&this.tabs.filter(function(){return 0===e(this).attr("tabIndex")}).attr("tabIndex",-1),o.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(t){var i,s=this._findActive(t);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return t===!1?e():this.tabs.eq(t)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+e+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tablist.unbind(this.eventNamespace),this.tabs.add(this.panels).each(function(){e.data(this,"ui-tabs-destroy")?e(this).remove():e(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var t=e(this),i=t.data("ui-tabs-aria-controls");i?t.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):t.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(t){var i=this.options.disabled;i!==!1&&(void 0===t?i=!1:(t=this._getIndex(t),i=e.isArray(i)?e.map(i,function(e){return e!==t?e:null}):e.map(this.tabs,function(e,i){return i!==t?i:null})),this._setupDisabled(i))},disable:function(t){var i=this.options.disabled;if(i!==!0){if(void 0===t)i=!0;else{if(t=this._getIndex(t),-1!==e.inArray(t,i))return;i=e.isArray(i)?e.merge([t],i).sort():[t]}this._setupDisabled(i)}},load:function(t,i){t=this._getIndex(t);var s=this,n=this.tabs.eq(t),a=n.find(".ui-tabs-anchor"),o=this._getPanelForTab(n),r={tab:n,panel:o},h=function(e,t){"abort"===t&&s.panels.stop(!1,!0),n.removeClass("ui-tabs-loading"),o.removeAttr("aria-busy"),e===s.xhr&&delete s.xhr};this._isLocal(a[0])||(this.xhr=e.ajax(this._ajaxSettings(a,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(n.addClass("ui-tabs-loading"),o.attr("aria-busy","true"),this.xhr.done(function(e,t,n){setTimeout(function(){o.html(e),s._trigger("load",i,r),h(n,t)},1)}).fail(function(e,t){setTimeout(function(){h(e,t)},1)})))},_ajaxSettings:function(t,i,s){var n=this;return{url:t.attr("href"),beforeSend:function(t,a){return n._trigger("beforeLoad",i,e.extend({jqXHR:t,ajaxSettings:a},s))}}},_getPanelForTab:function(t){var i=e(t).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),e.widget("ui.tooltip",{version:"1.11.4",options:{content:function(){var t=e(this).attr("title")||"";return e("").text(t).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_addDescribedBy:function(t,i){var s=(t.attr("aria-describedby")||"").split(/\s+/);s.push(i),t.data("ui-tooltip-id",i).attr("aria-describedby",e.trim(s.join(" ")))},_removeDescribedBy:function(t){var i=t.data("ui-tooltip-id"),s=(t.attr("aria-describedby")||"").split(/\s+/),n=e.inArray(i,s);-1!==n&&s.splice(n,1),t.removeData("ui-tooltip-id"),s=e.trim(s.join(" ")),s?t.attr("aria-describedby",s):t.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable(),this.liveRegion=e("
    ").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).addClass("ui-helper-hidden-accessible").appendTo(this.document[0].body)},_setOption:function(t,i){var s=this;return"disabled"===t?(this[i?"_disable":"_enable"](),this.options[t]=i,void 0):(this._super(t,i),"content"===t&&e.each(this.tooltips,function(e,t){s._updateContent(t.element)}),void 0)},_disable:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur");n.target=n.currentTarget=s.element[0],t.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var t=e(this);t.is("[title]")&&t.data("ui-tooltip-title",t.attr("title")).removeAttr("title")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var t=e(this);t.data("ui-tooltip-title")&&t.attr("title",t.data("ui-tooltip-title"))})},open:function(t){var i=this,s=e(t?t.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),t&&"mouseover"===t.type&&s.parents().each(function(){var t,s=e(this);s.data("ui-tooltip-open")&&(t=e.Event("blur"),t.target=t.currentTarget=this,i.close(t,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(t,s),this._updateContent(s,t))},_updateContent:function(e,t){var i,s=this.options.content,n=this,a=t?t.type:null;return"string"==typeof s?this._open(t,e,s):(i=s.call(e[0],function(i){n._delay(function(){e.data("ui-tooltip-open")&&(t&&(t.type=a),this._open(t,e,i))})}),i&&this._open(t,e,i),void 0)},_open:function(t,i,s){function n(e){l.of=e,o.is(":hidden")||o.position(l)}var a,o,r,h,l=e.extend({},this.options.position);if(s){if(a=this._find(i))return a.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(t&&"mouseover"===t.type?i.attr("title",""):i.removeAttr("title")),a=this._tooltip(i),o=a.tooltip,this._addDescribedBy(i,o.attr("id")),o.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),s.clone?(h=s.clone(),h.removeAttr("id").find("[id]").removeAttr("id")):h=s,e("
    ").html(h).appendTo(this.liveRegion),this.options.track&&t&&/^mouse/.test(t.type)?(this._on(this.document,{mousemove:n}),n(t)):o.position(e.extend({of:i},this.options.position)),o.hide(),this._show(o,this.options.show),this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){o.is(":visible")&&(n(l.of),clearInterval(r))},e.fx.interval)),this._trigger("open",t,{tooltip:o})}},_registerCloseHandlers:function(t,i){var s={keyup:function(t){if(t.keyCode===e.ui.keyCode.ESCAPE){var s=e.Event(t);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),t&&"mouseover"!==t.type||(s.mouseleave="close"),t&&"focusin"!==t.type||(s.focusout="close"),this._on(!0,i,s)},close:function(t){var i,s=this,n=e(t?t.currentTarget:this.element),a=this._find(n);return a?(i=a.tooltip,a.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),a.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(e(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),t&&"mouseleave"===t.type&&e.each(this.parents,function(t,i){e(i.element).attr("title",i.title),delete s.parents[t]}),a.closing=!0,this._trigger("close",t,{tooltip:i}),a.hiding||(a.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(t){var i=e("
    ").attr("role","tooltip").addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||"")),s=i.uniqueId().attr("id");return e("
    ").addClass("ui-tooltip-content").appendTo(i),i.appendTo(this.document[0].body),this.tooltips[s]={element:t,tooltip:i}},_find:function(e){var t=e.data("ui-tooltip-id");return t?this.tooltips[t]:null},_removeTooltip:function(e){e.remove(),delete this.tooltips[e.attr("id")]},_destroy:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur"),a=s.element;n.target=n.currentTarget=a[0],t.close(n,!0),e("#"+i).remove(),a.data("ui-tooltip-title")&&(a.attr("title")||a.attr("title",a.data("ui-tooltip-title")),a.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}})}); \ No newline at end of file diff --git a/public/js/rules/create-edit.js b/public/js/rules/create-edit.js new file mode 100644 index 0000000000..13c4027f10 --- /dev/null +++ b/public/js/rules/create-edit.js @@ -0,0 +1,41 @@ +/* + * create-edit.js + * Copyright (C) 2016 Sander Dorigo + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +var triggerCount = 0; +var actionCount = 0; + +$(function () { + "use strict"; + console.log("create-edit"); + +}); + + +function addNewTrigger() { + "use strict"; + triggerCount++; + + $.getJSON('json/trigger', {count: triggerCount}).success(function (data) { + //console.log(data.html); + $('tbody.rule-trigger-tbody').append(data.html); + }).fail(function () { + alert('Cannot get a new trigger.'); + }); +} + +function addNewAction() { + "use strict"; + actionCount++; + + $.getJSON('json/action', {count: actionCount}).success(function (data) { + //console.log(data.html); + $('tbody.rule-action-tbody').append(data.html); + }).fail(function () { + alert('Cannot get a new action.'); + }); +} \ No newline at end of file diff --git a/public/js/rules/create.js b/public/js/rules/create.js new file mode 100644 index 0000000000..e9bf3776bc --- /dev/null +++ b/public/js/rules/create.js @@ -0,0 +1,34 @@ +/* global $, addNewTrigger, addNewAction, actionCount, triggerCount */ +/* + * edit.js + * Copyright (C) 2016 Sander Dorigo + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +// make a line. + +$(function () { + "use strict"; + console.log("edit"); + if (triggerCount === 0) { + addNewTrigger(); + } + if (actionCount === 0) { + addNewAction(); + } + + + $('.add_rule_trigger').click(function () { + addNewTrigger(); + + return false; + }); + + $('.add_rule_action').click(function () { + addNewAction(); + + return false; + }); +}); diff --git a/public/js/rules/index.js b/public/js/rules/index.js new file mode 100644 index 0000000000..25b812fecd --- /dev/null +++ b/public/js/rules/index.js @@ -0,0 +1,70 @@ +/* global comboChart,token, billID */ +/* + * index.js + * Copyright (C) 2016 Sander Dorigo + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +// Return a helper with preserved width of cells +var fixHelper = function (e, tr) { + "use strict"; + var $originals = tr.children(); + var $helper = tr.clone(); + $helper.children().each(function (index) { + // Set helper cell sizes to match the original sizes + $(this).width($originals.eq(index).width()); + }); + return $helper; +}; + +$(function () { + "use strict"; + $('.rule-triggers').sortable({ + helper: fixHelper, + stop: sortStop, + cursor: "move" + + } + ); + + $('.rule-actions').sortable({ + helper: fixHelper, + stop: sortStop, + cursor: "move" + + } + ); + } +); + + +function sortStop(event, ui) { + "use strict"; + var current = $(ui.item); + var parent = current.parent(); + var ruleId = current.parent().data('id'); + var entries = []; + // who am i? + console.log('Rule: #' + current.parent().data('id')); + + $.each(parent.children(), function (i, v) { + var trigger = $(v); + var id = trigger.data('id'); + var order = i + 1; + entries.push(id); + + }); + if (parent.hasClass('rule-triggers')) { + $.post('rules/rules/trigger/reorder/' + ruleId, {_token: token, triggers: entries}).fail(function () { + alert('Could not re-order rule triggers. Please refresh the page.'); + }); + } else { + $.post('rules/rules/action/reorder/' + ruleId, {_token: token, actions: entries}).fail(function () { + alert('Could not re-order rule actions. Please refresh the page.'); + }); + + } + +} diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 6a8cb5a3e1..6143ad0d6d 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -2,477 +2,600 @@ return [ // general stuff: - 'language_incomplete' => 'This language is not yet fully translated', - 'test' => 'You have selected English.', - 'close' => 'Close', - 'pleaseHold' => 'Please hold...', - 'actions' => 'Actions', - 'edit' => 'Edit', - 'delete' => 'Delete', - 'welcomeBack' => 'What\'s playing?', - 'everything' => 'Everything', - 'customRange' => 'Custom range', - 'apply' => 'Apply', - 'cancel' => 'Cancel', - 'from' => 'From', - 'to' => 'To', - 'total_sum' => 'Total sum', - 'period_sum' => 'Sum for period', - 'showEverything' => 'Show everything', - 'never' => 'Never', - 'search_results_for' => 'Search results for ":query"', - 'bounced_error' => 'The message sent to :email bounced, so no access for you.', - 'deleted_error' => 'These credentials do not match our records.', - 'general_blocked_error' => 'Your account has been disabled, so you cannot login.', - 'removed_amount' => 'Removed :amount', - 'added_amount' => 'Added :amount', - 'asset_account_role_help' => 'Any extra options resulting from your choice can be set later.', - 'Opening balance' => 'Opening balance', - 'create_new_stuff' => 'Create new stuff', - 'new_withdrawal' => 'New withdrawal', - 'new_deposit' => 'New deposit', - 'new_transfer' => 'New transfer', - 'new_asset_account' => 'New asset account', - 'new_expense_account' => 'New expense account', - 'new_revenue_account' => 'New revenue account', - 'new_budget' => 'New budget', - 'new_bill' => 'New bill', + 'language_incomplete' => 'This language is not yet fully translated', + 'test' => 'You have selected English.', + 'close' => 'Close', + 'pleaseHold' => 'Please hold...', + 'actions' => 'Actions', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'welcomeBack' => 'What\'s playing?', + 'everything' => 'Everything', + 'customRange' => 'Custom range', + 'apply' => 'Apply', + 'cancel' => 'Cancel', + 'from' => 'From', + 'to' => 'To', + 'total_sum' => 'Total sum', + 'period_sum' => 'Sum for period', + 'showEverything' => 'Show everything', + 'never' => 'Never', + 'search_results_for' => 'Search results for ":query"', + 'bounced_error' => 'The message sent to :email bounced, so no access for you.', + 'deleted_error' => 'These credentials do not match our records.', + 'general_blocked_error' => 'Your account has been disabled, so you cannot login.', + 'removed_amount' => 'Removed :amount', + 'added_amount' => 'Added :amount', + 'asset_account_role_help' => 'Any extra options resulting from your choice can be set later.', + 'Opening balance' => 'Opening balance', + 'create_new_stuff' => 'Create new stuff', + 'new_withdrawal' => 'New withdrawal', + 'new_deposit' => 'New deposit', + 'new_transfer' => 'New transfer', + 'new_asset_account' => 'New asset account', + 'new_expense_account' => 'New expense account', + 'new_revenue_account' => 'New revenue account', + 'new_budget' => 'New budget', + 'new_bill' => 'New bill', + + // rules + 'rules' => 'Rules', + 'rules_explanation' => 'Here you can manage rules. Rules are triggered when a transaction is created or updated. Then, if the transaction has certain properties (called "triggers") Firefly will execute the "actions". Combined, you can make Firefly respond in a certain way to new transactions.', + 'rule_name' => 'Name of rule', + 'rule_triggers' => 'Rule triggers when', + 'rule_actions' => 'Rule will', + 'new_rule' => 'New rule', + 'new_rule_group' => 'New rule group', + 'rule_priority_up' => 'Give rule more priority', + 'rule_priority_down' => 'Give rule less priority', + 'make_new_rule_group' => 'Make new rule group', + 'store_new_rule_group' => 'Store new rule group', + 'created_new_rule_group' => 'New rule group ":title" stored!', + 'updated_rule_group' => 'Successfully updated rule group ":title".', + 'edit_rule_group' => 'Edit rule group ":title"', + 'delete_rule_group' => 'Delete rule group ":title"', + 'deleted_rule_group' => 'Deleted rule group ":title"', + 'update_rule_group' => 'Update rule group', + 'no_rules_in_group' => 'There are no rules in this group', + 'move_rule_group_up' => 'Move rule group up', + 'move_rule_group_down' => 'Move rule group down', + 'save_rules_by_moving' => 'Save these rule(s) by moving them to another rule group:', + 'make_new_rule' => 'Make new rule in rule group ":title"', + 'rule_help_stop_processing' => 'When you check this box, later rules in this group will not be executed.', + 'rule_help_active' => 'Inactive rules will never fire.', + 'stored_new_rule' => 'Stored new rule with title ":title"', + 'deleted_rule' => 'Deleted rule with title ":title"', + 'store_new_rule' => 'Store new rule', + 'updated_rule' => 'Updated rule with title ":title"', + 'default_rule_group_name' => 'Default rules', + 'default_rule_group_description' => 'All your rules not in a particular group.', + 'default_rule_name' => 'Your first default rule', + 'default_rule_description' => 'This rule is an example. You can safely delete it.', + 'default_rule_trigger_description' => 'The Man Who Sold the World', + 'default_rule_trigger_from_account' => 'David Bowie', + 'default_rule_action_prepend' => 'Bought the world from ', + 'default_rule_action_set_category' => 'Large expenses', + + 'trigger' => 'Trigger', + 'trigger_value' => 'Trigger on value', + 'stop_processing_other_triggers' => 'Stop processing other triggers', + 'add_rule_trigger' => 'Add new trigger', + 'action' => 'Action', + 'action_value' => 'Action value', + 'stop_executing_other_actions' => 'Stop executing other actions', + 'add_rule_action' => 'Add new action', + 'edit_rule' => 'Edit rule ":title"', + 'update_rule' => 'Update rule', + + // actions and triggers + 'rule_trigger_user_action' => 'User action is ":trigger_value"', + 'rule_trigger_from_account_starts' => 'Source account starts with ":trigger_value"', + 'rule_trigger_from_account_ends' => 'Source account ends with ":trigger_value"', + 'rule_trigger_from_account_is' => 'Source account is ":trigger_value"', + 'rule_trigger_from_account_contains' => 'Source account contains ":trigger_value"', + 'rule_trigger_to_account_starts' => 'Destination account starts with ":trigger_value"', + 'rule_trigger_to_account_ends' => 'Destination account ends with ":trigger_value"', + 'rule_trigger_to_account_is' => 'Destination account is ":trigger_value"', + 'rule_trigger_to_account_contains' => 'Destination account contains ":trigger_value"', + 'rule_trigger_transaction_type' => 'Transaction is of type ":trigger_value"', + 'rule_trigger_amount_less' => 'Amount is less than :trigger_value', + 'rule_trigger_amount_exactly' => 'Amount is :trigger_value', + 'rule_trigger_amount_more' => 'Amount is more than :trigger_value', + 'rule_trigger_description_starts' => 'Description starts with ":trigger_value"', + 'rule_trigger_description_ends' => 'Description ends with ":trigger_value"', + 'rule_trigger_description_contains' => 'Description contains ":trigger_value"', + 'rule_trigger_description_is' => 'Description is ":trigger_value"', + + 'rule_trigger_from_account_starts_choice' => 'Source account starts with..', + 'rule_trigger_from_account_ends_choice' => 'Source account ends with..', + 'rule_trigger_from_account_is_choice' => 'Source account is..', + 'rule_trigger_from_account_contains_choice' => 'Source account contains..', + 'rule_trigger_to_account_starts_choice' => 'Destination account starts with..', + 'rule_trigger_to_account_ends_choice' => 'Destination account ends with..', + 'rule_trigger_to_account_is_choice' => 'Destination account is..', + 'rule_trigger_to_account_contains_choice' => 'Destination account contains..', + 'rule_trigger_transaction_type_choice' => 'Transaction is of type..', + 'rule_trigger_amount_less_choice' => 'Amount is less than..', + 'rule_trigger_amount_exactly_choice' => 'Amount is..', + 'rule_trigger_amount_more_choice' => 'Amount is more than..', + 'rule_trigger_description_starts_choice' => 'Description starts with..', + 'rule_trigger_description_ends_choice' => 'Description ends with..', + 'rule_trigger_description_contains_choice' => 'Description contains..', + 'rule_trigger_description_is_choice' => 'Description is..', + + 'rule_trigger_store_journal' => 'When a journal is created', + 'rule_trigger_update_journal' => 'When a journal is updated', + + 'rule_action_set_category' => 'Set category to ":action_value"', + 'rule_action_clear_category' => 'Clear category', + 'rule_action_set_budget' => 'Set budget to ":action_value"', + 'rule_action_clear_budget' => 'Clear budget', + 'rule_action_add_tag' => 'Add tag ":action_value"', + 'rule_action_remove_tag' => 'Remove tag ":action_value"', + 'rule_action_remove_all_tags' => 'Remove all tags', + 'rule_action_set_description' => 'Set description to ":action_value"', + 'rule_action_append_description' => 'Append description with ":action_value"', + 'rule_action_prepend_description' => 'Prepend description with ":action_value"', + + 'rule_action_set_category_choice' => 'Set category to..', + 'rule_action_clear_category_choice' => 'Clear any category', + 'rule_action_set_budget_choice' => 'Set budget to..', + 'rule_action_clear_budget_choice' => 'Clear any budget', + 'rule_action_add_tag_choice' => 'Add tag..', + 'rule_action_remove_tag_choice' => 'Remove tag..', + 'rule_action_remove_all_tags_choice' => 'Remove all tags', + 'rule_action_set_description_choice' => 'Set description to..', + 'rule_action_append_description_choice' => 'Append description with..', + 'rule_action_prepend_description_choice' => 'Prepend description with..', // tags - 'store_new_tag' => 'Store new tag', - 'update_tag' => 'Update tag', - 'no_location_set' => 'No location set.', - 'meta_data' => 'Meta data', - 'location' => 'Location', + 'store_new_tag' => 'Store new tag', + 'update_tag' => 'Update tag', + 'no_location_set' => 'No location set.', + 'meta_data' => 'Meta data', + 'location' => 'Location', // preferences - 'pref_home_screen_accounts' => 'Home screen accounts', - 'pref_home_screen_accounts_help' => 'Which accounts should be displayed on the home page?', - 'pref_budget_settings' => 'Budget settings', - 'pref_budget_settings_help' => 'What\'s the maximum amount of money a budget envelope may contain?', - 'pref_view_range' => 'View range', - 'pref_view_range_help' => 'Some charts are automatically grouped in periods. What period would you prefer?', - 'pref_1D' => 'One day', - 'pref_1W' => 'One week', - 'pref_1M' => 'One month', - 'pref_3M' => 'Three months (quarter)', - 'pref_6M' => 'Six months', - 'pref_languages' => 'Languages', - 'pref_languages_help' => 'Firefly III supports several languages. Which one do you prefer?', - 'pref_save_settings' => 'Save settings', + 'pref_home_screen_accounts' => 'Home screen accounts', + 'pref_home_screen_accounts_help' => 'Which accounts should be displayed on the home page?', + 'pref_budget_settings' => 'Budget settings', + 'pref_budget_settings_help' => 'What\'s the maximum amount of money a budget envelope may contain?', + 'pref_view_range' => 'View range', + 'pref_view_range_help' => 'Some charts are automatically grouped in periods. What period would you prefer?', + 'pref_1D' => 'One day', + 'pref_1W' => 'One week', + 'pref_1M' => 'One month', + 'pref_3M' => 'Three months (quarter)', + 'pref_6M' => 'Six months', + 'pref_languages' => 'Languages', + 'pref_languages_help' => 'Firefly III supports several languages. Which one do you prefer?', + 'pref_save_settings' => 'Save settings', // profile: - 'change_your_password' => 'Change your password', - 'delete_account' => 'Delete account', - 'current_password' => 'Current password', - 'new_password' => 'New password', - 'new_password_again' => 'New password (again)', - 'delete_your_account' => 'Delete your account', - 'delete_your_account_help' => 'Deleting your account will also delete any accounts, transactions, anything you might have saved into Firefly III. It\'ll be GONE.', - 'delete_your_account_password' => 'Enter your password to continue.', - 'password' => 'Password', - 'are_you_sure' => 'Are you sure? You cannot undo this.', - 'delete_account_button' => 'DELETE your account', - 'invalid_current_password' => 'Invalid current password!', - 'password_changed' => 'Password changed!', - 'should_change' => 'The idea is to change your password.', - 'invalid_password' => 'Invalid password!', + 'change_your_password' => 'Change your password', + 'delete_account' => 'Delete account', + 'current_password' => 'Current password', + 'new_password' => 'New password', + 'new_password_again' => 'New password (again)', + 'delete_your_account' => 'Delete your account', + 'delete_your_account_help' => 'Deleting your account will also delete any accounts, transactions, anything you might have saved into Firefly III. It\'ll be GONE.', + 'delete_your_account_password' => 'Enter your password to continue.', + 'password' => 'Password', + 'are_you_sure' => 'Are you sure? You cannot undo this.', + 'delete_account_button' => 'DELETE your account', + 'invalid_current_password' => 'Invalid current password!', + 'password_changed' => 'Password changed!', + 'should_change' => 'The idea is to change your password.', + 'invalid_password' => 'Invalid password!', // attachments - 'nr_of_attachments' => 'One attachment|:count attachments', - 'attachments' => 'Attachments', - 'edit_attachment' => 'Edit attachment ":name"', - 'update_attachment' => 'Update attachment', - 'delete_attachment' => 'Delete attachment ":name"', - 'attachment_deleted' => 'Deleted attachment ":name"', - 'upload_max_file_size' => 'Maximum file size: :size', + 'nr_of_attachments' => 'One attachment|:count attachments', + 'attachments' => 'Attachments', + 'edit_attachment' => 'Edit attachment ":name"', + 'update_attachment' => 'Update attachment', + 'delete_attachment' => 'Delete attachment ":name"', + 'attachment_deleted' => 'Deleted attachment ":name"', + 'upload_max_file_size' => 'Maximum file size: :size', // tour: - 'prev' => 'Prev', - 'next' => 'Next', - 'end-tour' => 'End tour', - 'pause' => 'Pause', + 'prev' => 'Prev', + 'next' => 'Next', + 'end-tour' => 'End tour', + 'pause' => 'Pause', // transaction index - 'title_expenses' => 'Expenses', - 'title_withdrawal' => 'Expenses', - 'title_revenue' => 'Revenue / income', - 'title_deposit' => 'Revenue / income', - 'title_transfer' => 'Transfers', - 'title_transfers' => 'Transfers', + 'title_expenses' => 'Expenses', + 'title_withdrawal' => 'Expenses', + 'title_revenue' => 'Revenue / income', + 'title_deposit' => 'Revenue / income', + 'title_transfer' => 'Transfers', + 'title_transfers' => 'Transfers', // csv import: - 'csv_import' => 'Import CSV file', - 'csv' => 'CSV', - 'csv_index_title' => 'Upload and import a CSV file', - 'csv_define_column_roles' => 'Define column roles', - 'csv_map_values' => 'Map found values to existing values', - 'csv_download_config' => 'Download CSV configuration file.', - 'csv_index_text' => 'This form allows you to import a CSV file with transactions into Firefly. It is based on the excellent CSV importer made by the folks at Atlassian. Simply upload your CSV file and follow the instructions. If you would like to learn more, please click on the button at the top of this page.', - 'csv_index_beta_warning' => 'This tool is very much in beta. Please proceed with caution', - 'csv_header_help' => 'Check this box when your CSV file\'s first row consists of column names, not actual data', - 'csv_date_help' => 'Date time format in your CSV. Follow the format like this page indicates. The default value will parse dates that look like this: :dateExample.', - 'csv_csv_file_help' => 'Select the CSV file here. You can only upload one file at a time', - 'csv_csv_config_file_help' => 'Select your CSV import configuration here. If you do not know what this is, ignore it. It will be explained later.', - 'csv_upload_button' => 'Start importing CSV', - 'csv_column_roles_title' => 'Define column roles', - 'csv_column_roles_text' => 'Firefly does not know what each column means. You need to indicate what every column is. Please check out the example data if you\'re not sure yourself. Click on the question mark (top right of the page) to learn what each column means. If you want to map imported data onto existing data in Firefly, use the checkbox. The next step will show you what this button does.', - 'csv_column_roles_table' => 'Column roles', - 'csv_column' => 'CSV column', - 'csv_column_name' => 'CSV column name', - 'csv_column_example' => 'Column example data', - 'csv_column_role' => 'Column contains?', - 'csv_do_map_value' => 'Map value?', - 'csv_continue' => 'Continue to the next step', - 'csv_go_back' => 'Go back to the previous step', - 'csv_map_title' => 'Map found values to existing values', - 'csv_map_text' => 'This page allows you to map the values from the CSV file to existing entries in your database. This ensures that accounts and other things won\'t be created twice.', - 'csv_field_value' => 'Field value from CSV', - 'csv_field_mapped_to' => 'Must be mapped to...', - 'csv_do_not_map' => 'Do not map this value', - 'csv_download_config_title' => 'Download CSV configuration', - 'csv_download_config_text' => 'Everything you\'ve just set up can be downloaded as a configuration file. Click the button to do so.', - 'csv_more_information_text' => 'If the import fails, you can use this configuration file so you don\'t have to start all over again. But, if the import succeeds, it will be easier to upload similar CSV files.', - 'csv_do_download_config' => 'Download configuration file.', - 'csv_empty_description' => '(empty description)', - 'csv_upload_form' => 'CSV upload form', - 'csv_index_unsupported_warning' => 'The CSV importer is yet incapable of doing the following:', - 'csv_unsupported_map' => 'The importer cannot map the column ":columnRole" to existing values in the database.', - 'csv_unsupported_value' => 'The importer does not know how to handle values in columns marked as ":columnRole".', - 'csv_cannot_store_value' => 'The importer has not reserved space for columns marked ":columnRole" and will be incapable of processing them.', - 'csv_process_title' => 'CSV import finished!', - 'csv_process_text' => 'The CSV importer has finished and has processed :rows rows', - 'csv_row' => 'Row', - 'csv_import_with_errors' => 'There was one error.|There were :errors errors.', - 'csv_error_see_logs' => 'Check the log files to see details.', - 'csv_process_new_entries' => 'Firefly has created :imported new transaction(s).', - 'csv_start_over' => 'Import again', - 'csv_to_index' => 'Back home', - 'csv_upload_not_writeable' => 'Cannot write to the path mentioned here. Cannot upload', - 'csv_column__ignore' => '(ignore this column)', - 'csv_column_account-iban' => 'Asset account (IBAN)', - 'csv_column_account-id' => 'Asset account ID (matching Firefly)', - 'csv_column_account-name' => 'Asset account (name)', - 'csv_column_amount' => 'Amount', - 'csv_column_bill-id' => 'Bill ID (matching Firefly)', - 'csv_column_bill-name' => 'Bill name', - 'csv_column_budget-id' => 'Budget ID (matching Firefly)', - 'csv_column_budget-name' => 'Budget name', - 'csv_column_category-id' => 'Category ID (matching Firefly)', - 'csv_column_category-name' => 'Category name', - 'csv_column_currency-code' => 'Currency code (ISO 4217)', - 'csv_column_currency-id' => 'Currency ID (matching Firefly)', - 'csv_column_currency-name' => 'Currency name (matching Firefly)', - 'csv_column_currency-symbol' => 'Currency symbol (matching Firefly)', - 'csv_column_date-rent' => 'Rent calculation date', - 'csv_column_date-transaction' => 'Date', - 'csv_column_description' => 'Description', - 'csv_column_opposing-iban' => 'Opposing account (IBAN)', - 'csv_column_opposing-id' => 'Opposing account ID (matching Firefly)', - 'csv_column_opposing-name' => 'Opposing account (name)', - 'csv_column_rabo-debet-credit' => 'Rabobank specific debet/credit indicator', - 'csv_column_sepa-ct-id' => 'SEPA Credit Transfer end-to-end ID', - 'csv_column_sepa-ct-op' => 'SEPA Credit Transfer opposing account', - 'csv_column_sepa-db' => 'SEPA Direct Debet', - 'csv_column_tags-comma' => 'Tags (comma separated)', - 'csv_column_tags-space' => 'Tags (space separated)', - 'csv_specifix_RabobankDescription' => 'Select this when you\'re importing Rabobank CSV export files.', - 'csv_specifix_Dummy' => 'Checking this has no effect whatsoever.', - 'csv_import_account_help' => 'If your CSV file does NOT contain information about your asset account(s), use this dropdown to select to which account the transactions in the CSV belong to.', - 'csv_date_parse_error' => 'Could not parse a valid date from ":value", using the format ":format". Are you sure your CSV is correct?', + 'csv_import' => 'Import CSV file', + 'csv' => 'CSV', + 'csv_index_title' => 'Upload and import a CSV file', + 'csv_define_column_roles' => 'Define column roles', + 'csv_map_values' => 'Map found values to existing values', + 'csv_download_config' => 'Download CSV configuration file.', + 'csv_index_text' => 'This form allows you to import a CSV file with transactions into Firefly. It is based on the excellent CSV importer made by the folks at Atlassian. Simply upload your CSV file and follow the instructions. If you would like to learn more, please click on the button at the top of this page.', + 'csv_index_beta_warning' => 'This tool is very much in beta. Please proceed with caution', + 'csv_header_help' => 'Check this box when your CSV file\'s first row consists of column names, not actual data', + 'csv_date_help' => 'Date time format in your CSV. Follow the format like this page indicates. The default value will parse dates that look like this: :dateExample.', + 'csv_csv_file_help' => 'Select the CSV file here. You can only upload one file at a time', + 'csv_csv_config_file_help' => 'Select your CSV import configuration here. If you do not know what this is, ignore it. It will be explained later.', + 'csv_upload_button' => 'Start importing CSV', + 'csv_column_roles_title' => 'Define column roles', + 'csv_column_roles_text' => 'Firefly does not know what each column means. You need to indicate what every column is. Please check out the example data if you\'re not sure yourself. Click on the question mark (top right of the page) to learn what each column means. If you want to map imported data onto existing data in Firefly, use the checkbox. The next step will show you what this button does.', + 'csv_column_roles_table' => 'Column roles', + 'csv_column' => 'CSV column', + 'csv_column_name' => 'CSV column name', + 'csv_column_example' => 'Column example data', + 'csv_column_role' => 'Column contains?', + 'csv_do_map_value' => 'Map value?', + 'csv_continue' => 'Continue to the next step', + 'csv_go_back' => 'Go back to the previous step', + 'csv_map_title' => 'Map found values to existing values', + 'csv_map_text' => 'This page allows you to map the values from the CSV file to existing entries in your database. This ensures that accounts and other things won\'t be created twice.', + 'csv_field_value' => 'Field value from CSV', + 'csv_field_mapped_to' => 'Must be mapped to...', + 'csv_do_not_map' => 'Do not map this value', + 'csv_download_config_title' => 'Download CSV configuration', + 'csv_download_config_text' => 'Everything you\'ve just set up can be downloaded as a configuration file. Click the button to do so.', + 'csv_more_information_text' => 'If the import fails, you can use this configuration file so you don\'t have to start all over again. But, if the import succeeds, it will be easier to upload similar CSV files.', + 'csv_do_download_config' => 'Download configuration file.', + 'csv_empty_description' => '(empty description)', + 'csv_upload_form' => 'CSV upload form', + 'csv_index_unsupported_warning' => 'The CSV importer is yet incapable of doing the following:', + 'csv_unsupported_map' => 'The importer cannot map the column ":columnRole" to existing values in the database.', + 'csv_unsupported_value' => 'The importer does not know how to handle values in columns marked as ":columnRole".', + 'csv_cannot_store_value' => 'The importer has not reserved space for columns marked ":columnRole" and will be incapable of processing them.', + 'csv_process_title' => 'CSV import finished!', + 'csv_process_text' => 'The CSV importer has finished and has processed :rows rows', + 'csv_row' => 'Row', + 'csv_import_with_errors' => 'There was one error.|There were :errors errors.', + 'csv_error_see_logs' => 'Check the log files to see details.', + 'csv_process_new_entries' => 'Firefly has created :imported new transaction(s).', + 'csv_start_over' => 'Import again', + 'csv_to_index' => 'Back home', + 'csv_upload_not_writeable' => 'Cannot write to the path mentioned here. Cannot upload', + 'csv_column__ignore' => '(ignore this column)', + 'csv_column_account-iban' => 'Asset account (IBAN)', + 'csv_column_account-id' => 'Asset account ID (matching Firefly)', + 'csv_column_account-name' => 'Asset account (name)', + 'csv_column_amount' => 'Amount', + 'csv_column_amount-comma-separated' => 'Amount (comma as decimal separator)', + 'csv_column_bill-id' => 'Bill ID (matching Firefly)', + 'csv_column_bill-name' => 'Bill name', + 'csv_column_budget-id' => 'Budget ID (matching Firefly)', + 'csv_column_budget-name' => 'Budget name', + 'csv_column_category-id' => 'Category ID (matching Firefly)', + 'csv_column_category-name' => 'Category name', + 'csv_column_currency-code' => 'Currency code (ISO 4217)', + 'csv_column_currency-id' => 'Currency ID (matching Firefly)', + 'csv_column_currency-name' => 'Currency name (matching Firefly)', + 'csv_column_currency-symbol' => 'Currency symbol (matching Firefly)', + 'csv_column_date-rent' => 'Rent calculation date', + 'csv_column_date-transaction' => 'Date', + 'csv_column_description' => 'Description', + 'csv_column_opposing-iban' => 'Opposing account (IBAN)', + 'csv_column_opposing-id' => 'Opposing account ID (matching Firefly)', + 'csv_column_opposing-name' => 'Opposing account (name)', + 'csv_column_rabo-debet-credit' => 'Rabobank specific debet/credit indicator', + 'csv_column_sepa-ct-id' => 'SEPA Credit Transfer end-to-end ID', + 'csv_column_sepa-ct-op' => 'SEPA Credit Transfer opposing account', + 'csv_column_sepa-db' => 'SEPA Direct Debet', + 'csv_column_tags-comma' => 'Tags (comma separated)', + 'csv_column_tags-space' => 'Tags (space separated)', + 'csv_specifix_RabobankDescription' => 'Select this when you\'re importing Rabobank CSV export files.', + 'csv_specifix_AbnAmroDescription' => 'Select this when you\'re importing ABN AMRO CSV export files.', + 'csv_specifix_Dummy' => 'Checking this has no effect whatsoever.', + 'csv_import_account_help' => 'If your CSV file does NOT contain information about your asset account(s), use this dropdown to select to which account the transactions in the CSV belong to.', + 'csv_delimiter_help' => 'Choose the field delimiter that is used in your input file. If not sure, comma is the safest option.', + 'csv_date_parse_error' => 'Could not parse a valid date from ":value", using the format ":format". Are you sure your CSV is correct?', // create new stuff: - 'create_new_withdrawal' => 'Create new withdrawal', - 'create_new_deposit' => 'Create new deposit', - 'create_new_transfer' => 'Create new transfer', - 'create_new_asset' => 'Create new asset account', - 'create_new_expense' => 'Create new expense account', - 'create_new_revenue' => 'Create new revenue account', - 'create_new_piggy_bank' => 'Create new piggy bank', - 'create_new_bill' => 'Create new bill', + 'create_new_withdrawal' => 'Create new withdrawal', + 'create_new_deposit' => 'Create new deposit', + 'create_new_transfer' => 'Create new transfer', + 'create_new_asset' => 'Create new asset account', + 'create_new_expense' => 'Create new expense account', + 'create_new_revenue' => 'Create new revenue account', + 'create_new_piggy_bank' => 'Create new piggy bank', + 'create_new_bill' => 'Create new bill', // currencies: - 'create_currency' => 'Create a new currency', - 'edit_currency' => 'Edit currency ":name"', - 'store_currency' => 'Store new currency', - 'update_currency' => 'Update currency', + 'create_currency' => 'Create a new currency', + 'edit_currency' => 'Edit currency ":name"', + 'store_currency' => 'Store new currency', + 'update_currency' => 'Update currency', + 'new_default_currency' => ':name is now the default currency.', + 'cannot_delete_currency' => 'Cannot delete :name because there are still transactions attached to it!', + 'deleted_currency' => 'Currency :name deleted', + 'created_currency' => 'Currency :name created', + 'updated_currency' => 'Currency :name updated', + 'ask_site_owner' => 'Please ask :owner to add, remove or edit currencies.', + 'currencies_intro' => 'Firefly III supports various currencies which you can set and enable here.', + 'make_default_currency' => 'make default', + 'default_currency' => 'default', // new user: - 'submit' => 'Submit', - 'getting_started' => 'Getting started', - 'to_get_started' => 'To get started with Firefly, please enter your current bank\'s name, and the balance of your checking account:', - 'savings_balance_text' => 'If you have a savings account, please enter the current balance of your savings account:', - 'cc_balance_text' => 'If you have a credit card, please enter your credit card\'s limit.', + 'submit' => 'Submit', + 'getting_started' => 'Getting started', + 'to_get_started' => 'To get started with Firefly, please enter your current bank\'s name, and the balance of your checking account:', + 'savings_balance_text' => 'If you have a savings account, please enter the current balance of your savings account:', + 'cc_balance_text' => 'If you have a credit card, please enter your credit card\'s limit.', // forms: - 'mandatoryFields' => 'Mandatory fields', - 'optionalFields' => 'Optional fields', - 'options' => 'Options', - 'something' => 'Something!', + 'mandatoryFields' => 'Mandatory fields', + 'optionalFields' => 'Optional fields', + 'options' => 'Options', + 'something' => 'Something!', // budgets: - 'create_new_budget' => 'Create a new budget', - 'store_new_budget' => ' Store new budget', - 'availableIn' => 'Available in :date', - 'transactionsWithoutBudget' => 'Expenses without budget', - 'transactionsWithoutBudgetDate' => 'Expenses without budget in :date', - 'createBudget' => 'New budget', - 'inactiveBudgets' => 'Inactive budgets', - 'without_budget_between' => 'Transactions without a budget between :start and :end', - 'budget_in_month' => ':name in :month', - 'delete_budget' => 'Delete budget ":name"', - 'edit_budget' => 'Edit budget ":name"', - 'update_amount' => 'Update amount', - 'update_budget' => 'Update budget', + 'create_new_budget' => 'Create a new budget', + 'store_new_budget' => ' Store new budget', + 'availableIn' => 'Available in :date', + 'transactionsWithoutBudget' => 'Expenses without budget', + 'transactionsWithoutBudgetDate' => 'Expenses without budget in :date', + 'createBudget' => 'New budget', + 'inactiveBudgets' => 'Inactive budgets', + 'without_budget_between' => 'Transactions without a budget between :start and :end', + 'budget_in_month' => ':name in :month', + 'delete_budget' => 'Delete budget ":name"', + 'edit_budget' => 'Edit budget ":name"', + 'update_amount' => 'Update amount', + 'update_budget' => 'Update budget', // bills: - 'delete_bill' => 'Delete bill ":name"', - 'edit_bill' => 'Edit bill ":name"', - 'update_bill' => 'Update bill', - 'store_new_bill' => 'Store new bill', + 'delete_bill' => 'Delete bill ":name"', + 'edit_bill' => 'Edit bill ":name"', + 'update_bill' => 'Update bill', + 'store_new_bill' => 'Store new bill', // accounts: - 'details_for_asset' => 'Details for asset account ":name"', - 'details_for_expense' => 'Details for expense account ":name"', - 'details_for_revenue' => 'Details for revenue account ":name"', - 'details_for_cash' => 'Details for cash account ":name"', - 'store_new_asset_account' => 'Store new asset account', - 'store_new_expense_account' => 'Store new expense account', - 'store_new_revenue_account' => 'Store new revenue account', - 'edit_asset_account' => 'Edit asset account ":name"', - 'edit_expense_account' => 'Edit expense account ":name"', - 'edit_revenue_account' => 'Edit revenue account ":name"', - 'delete_asset_account' => 'Delete asset account ":name"', - 'delete_expense_account' => 'Delete expense account ":name"', - 'delete_revenue_account' => 'Delete revenue account ":name"', - 'asset_deleted' => 'Successfully deleted asset account ":name"', - 'expense_deleted' => 'Successfully deleted expense account ":name"', - 'revenue_deleted' => 'Successfully deleted revenue account ":name"', - 'update_asset_account' => 'Update asset account', - 'update_expense_account' => 'Update expense account', - 'update_revenue_account' => 'Update revenue account', - 'make_new_asset_account' => 'Create a new asset account', - 'make_new_expense_account' => 'Create a new expense account', - 'make_new_revenue_account' => 'Create a new revenue account', - 'asset_accounts' => 'Asset accounts', - 'expense_accounts' => 'Expense accounts', - 'revenue_accounts' => 'Revenue accounts', - 'accountExtraHelp_asset' => '', - 'accountExtraHelp_expense' => '', - 'accountExtraHelp_revenue' => '', - 'account_type' => 'Account type', - 'save_transactions_by_moving' => 'Save these transaction(s) by moving them to another account:', + 'details_for_asset' => 'Details for asset account ":name"', + 'details_for_expense' => 'Details for expense account ":name"', + 'details_for_revenue' => 'Details for revenue account ":name"', + 'details_for_cash' => 'Details for cash account ":name"', + 'store_new_asset_account' => 'Store new asset account', + 'store_new_expense_account' => 'Store new expense account', + 'store_new_revenue_account' => 'Store new revenue account', + 'edit_asset_account' => 'Edit asset account ":name"', + 'edit_expense_account' => 'Edit expense account ":name"', + 'edit_revenue_account' => 'Edit revenue account ":name"', + 'delete_asset_account' => 'Delete asset account ":name"', + 'delete_expense_account' => 'Delete expense account ":name"', + 'delete_revenue_account' => 'Delete revenue account ":name"', + 'asset_deleted' => 'Successfully deleted asset account ":name"', + 'expense_deleted' => 'Successfully deleted expense account ":name"', + 'revenue_deleted' => 'Successfully deleted revenue account ":name"', + 'update_asset_account' => 'Update asset account', + 'update_expense_account' => 'Update expense account', + 'update_revenue_account' => 'Update revenue account', + 'make_new_asset_account' => 'Create a new asset account', + 'make_new_expense_account' => 'Create a new expense account', + 'make_new_revenue_account' => 'Create a new revenue account', + 'asset_accounts' => 'Asset accounts', + 'expense_accounts' => 'Expense accounts', + 'revenue_accounts' => 'Revenue accounts', + 'accountExtraHelp_asset' => '', + 'accountExtraHelp_expense' => '', + 'accountExtraHelp_revenue' => '', + 'account_type' => 'Account type', + 'save_transactions_by_moving' => 'Save these transaction(s) by moving them to another account:', // categories: - 'new_category' => 'New category', - 'create_new_category' => 'Create a new category', - 'without_category' => 'Without a category', - 'update_category' => 'Wijzig categorie', - 'categories' => 'Categories', - 'edit_category' => 'Edit category ":name"', - 'no_category' => '(no category)', - 'category' => 'Category', - 'delete_category' => 'Delete category ":name"', - 'store_category' => 'Store new category', + 'new_category' => 'New category', + 'create_new_category' => 'Create a new category', + 'without_category' => 'Without a category', + 'update_category' => 'Wijzig categorie', + 'categories' => 'Categories', + 'edit_category' => 'Edit category ":name"', + 'no_category' => '(no category)', + 'category' => 'Category', + 'delete_category' => 'Delete category ":name"', + 'store_category' => 'Store new category', + 'without_category_between' => 'Without category between :start and :end', // transactions: - 'update_withdrawal' => 'Update withdrawal', - 'update_deposit' => 'Update deposit', - 'update_transfer' => 'Update transfer', - 'delete_withdrawal' => 'Delete withdrawal ":description"', - 'delete_deposit' => 'Delete deposit ":description"', - 'delete_transfer' => 'Delete transfer ":description"', + 'update_withdrawal' => 'Update withdrawal', + 'update_deposit' => 'Update deposit', + 'update_transfer' => 'Update transfer', + 'delete_withdrawal' => 'Delete withdrawal ":description"', + 'delete_deposit' => 'Delete deposit ":description"', + 'delete_transfer' => 'Delete transfer ":description"', // new user: - 'welcome' => 'Welcome to Firefly!', - 'createNewAsset' => 'Create a new asset account to get started. ' . - 'This will allow you to create transactions and start your financial management', - 'createNewAssetButton' => 'Create new asset account', + 'welcome' => 'Welcome to Firefly!', + 'createNewAsset' => 'Create a new asset account to get started. ' . + 'This will allow you to create transactions and start your financial management', + 'createNewAssetButton' => 'Create new asset account', // home page: - 'yourAccounts' => 'Your accounts', - 'budgetsAndSpending' => 'Budgets and spending', - 'savings' => 'Savings', - 'markAsSavingsToContinue' => 'Mark your asset accounts as "Savings account" to fill this panel', - 'createPiggyToContinue' => 'Create piggy banks to fill this panel.', - 'newWithdrawal' => 'New expense', - 'newDeposit' => 'New deposit', - 'newTransfer' => 'New transfer', - 'moneyIn' => 'Money in', - 'moneyOut' => 'Money out', - 'billsToPay' => 'Bills to pay', - 'billsPaid' => 'Bills paid', - 'viewDetails' => 'View details', - 'divided' => 'divided', - 'toDivide' => 'left to divide', + 'yourAccounts' => 'Your accounts', + 'budgetsAndSpending' => 'Budgets and spending', + 'savings' => 'Savings', + 'markAsSavingsToContinue' => 'Mark your asset accounts as "Savings account" to fill this panel', + 'createPiggyToContinue' => 'Create piggy banks to fill this panel.', + 'newWithdrawal' => 'New expense', + 'newDeposit' => 'New deposit', + 'newTransfer' => 'New transfer', + 'moneyIn' => 'Money in', + 'moneyOut' => 'Money out', + 'billsToPay' => 'Bills to pay', + 'billsPaid' => 'Bills paid', + 'viewDetails' => 'View details', + 'divided' => 'divided', + 'toDivide' => 'left to divide', // menu and titles, should be recycled as often as possible: - 'toggleNavigation' => 'Toggle navigation', - 'currency' => 'Currency', - 'preferences' => 'Preferences', - 'logout' => 'Logout', - 'searchPlaceholder' => 'Search...', - 'dashboard' => 'Dashboard', - 'currencies' => 'Currencies', - 'accounts' => 'Accounts', - 'Asset account' => 'Asset account', - 'Default account' => 'Asset account', - 'Expense account' => 'Expense account', - 'Revenue account' => 'Revenue account', - 'Initial balance account' => 'Initial balance account', - 'budgets' => 'Budgets', - 'tags' => 'Tags', - 'reports' => 'Reports', - 'transactions' => 'Transactions', - 'expenses' => 'Expenses', - 'income' => 'Revenue / income', - 'transfers' => 'Transfers', - 'moneyManagement' => 'Money management', - 'piggyBanks' => 'Piggy banks', - 'bills' => 'Bills', - 'createNew' => 'Create new', - 'withdrawal' => 'Withdrawal', - 'deposit' => 'Deposit', - 'account' => 'Account', - 'transfer' => 'Transfer', - 'Withdrawal' => 'Withdrawal', - 'Deposit' => 'Deposit', - 'Transfer' => 'Transfer', - 'bill' => 'Bill', - 'yes' => 'Yes', - 'no' => 'No', - 'amount' => 'Amount', - 'newBalance' => 'New balance', - 'overview' => 'Overview', - 'saveOnAccount' => 'Save on account', - 'unknown' => 'Unknown', - 'daily' => 'Daily', - 'weekly' => 'Weekly', - 'monthly' => 'Monthly', - 'quarterly' => 'Quarterly', - 'half-year' => 'Every six months', - 'yearly' => 'Yearly', - 'profile' => 'Profile', + 'toggleNavigation' => 'Toggle navigation', + 'currency' => 'Currency', + 'preferences' => 'Preferences', + 'logout' => 'Logout', + 'searchPlaceholder' => 'Search...', + 'dashboard' => 'Dashboard', + 'currencies' => 'Currencies', + 'accounts' => 'Accounts', + 'Asset account' => 'Asset account', + 'Default account' => 'Asset account', + 'Expense account' => 'Expense account', + 'Revenue account' => 'Revenue account', + 'Initial balance account' => 'Initial balance account', + 'budgets' => 'Budgets', + 'tags' => 'Tags', + 'reports' => 'Reports', + 'transactions' => 'Transactions', + 'expenses' => 'Expenses', + 'income' => 'Revenue / income', + 'transfers' => 'Transfers', + 'moneyManagement' => 'Money management', + 'piggyBanks' => 'Piggy banks', + 'bills' => 'Bills', + 'createNew' => 'Create new', + 'withdrawal' => 'Withdrawal', + 'deposit' => 'Deposit', + 'account' => 'Account', + 'transfer' => 'Transfer', + 'Withdrawal' => 'Withdrawal', + 'Deposit' => 'Deposit', + 'Transfer' => 'Transfer', + 'bill' => 'Bill', + 'yes' => 'Yes', + 'no' => 'No', + 'amount' => 'Amount', + 'newBalance' => 'New balance', + 'overview' => 'Overview', + 'saveOnAccount' => 'Save on account', + 'unknown' => 'Unknown', + 'daily' => 'Daily', + 'weekly' => 'Weekly', + 'monthly' => 'Monthly', + 'quarterly' => 'Quarterly', + 'half-year' => 'Every six months', + 'yearly' => 'Yearly', + 'profile' => 'Profile', // reports: - 'report_default' => 'Default financial report for :start until :end', - 'quick_link_reports' => 'Quick links', - 'quick_link_default_report' => 'Default financial report', - 'report_this_month_quick' => 'Current month, all accounts', - 'report_this_year_quick' => 'Current year, all accounts', - 'report_all_time_quick' => 'All-time, all accounts', - 'reports_can_bookmark' => 'Remember that reports can be bookmarked.', - 'incomeVsExpenses' => 'Income vs. expenses', - 'accountBalances' => 'Account balances', - 'balanceStartOfYear' => 'Balance at start of year', - 'balanceEndOfYear' => 'Balance at end of year', - 'balanceStartOfMonth' => 'Balance at start of month', - 'balanceEndOfMonth' => 'Balance at end of month', - 'balanceStart' => 'Balance at start of period', - 'balanceEnd' => 'Balance at end of period', - 'reportsOwnAccounts' => 'Reports for your own accounts', - 'reportsOwnAccountsAndShared' => 'Reports for your own accounts and shared accounts', - 'splitByAccount' => 'Split by account', - 'balancedByTransfersAndTags' => 'Balanced by transfers and tags', - 'coveredWithTags' => 'Covered with tags', - 'leftUnbalanced' => 'Left unbalanced', - 'expectedBalance' => 'Expected balance', - 'outsideOfBudgets' => 'Outside of budgets', - 'leftInBudget' => 'Left in budget', - 'sumOfSums' => 'Sum of sums', - 'noCategory' => '(no category)', - 'notCharged' => 'Not charged (yet)', - 'inactive' => 'Inactive', - 'difference' => 'Difference', - 'in' => 'In', - 'out' => 'Out', - 'topX' => 'top :number', - 'showTheRest' => 'Show everything', - 'hideTheRest' => 'Show only the top :number', - 'sum_of_year' => 'Sum of year', - 'sum_of_years' => 'Sum of years', - 'average_of_year' => 'Average of year', - 'average_of_years' => 'Average of years', - 'categories_earned_in_year' => 'Categories (by earnings)', - 'categories_spent_in_year' => 'Categories (by spendings)', - 'report_type' => 'Report type', - 'report_type_default' => 'Default financial report', - 'report_included_accounts' => 'Included accounts', - 'report_date_range' => 'Date range', - 'report_include_help' => 'In all cases, transfers to shared accounts count as expenses, and transfers from shared accounts count as income.', - 'report_preset_ranges' => 'Pre-set ranges', - 'shared' => 'Shared', + 'report_default' => 'Default financial report for :start until :end', + 'quick_link_reports' => 'Quick links', + 'quick_link_default_report' => 'Default financial report', + 'report_this_month_quick' => 'Current month, all accounts', + 'report_this_year_quick' => 'Current year, all accounts', + 'report_all_time_quick' => 'All-time, all accounts', + 'reports_can_bookmark' => 'Remember that reports can be bookmarked.', + 'incomeVsExpenses' => 'Income vs. expenses', + 'accountBalances' => 'Account balances', + 'balanceStartOfYear' => 'Balance at start of year', + 'balanceEndOfYear' => 'Balance at end of year', + 'balanceStartOfMonth' => 'Balance at start of month', + 'balanceEndOfMonth' => 'Balance at end of month', + 'balanceStart' => 'Balance at start of period', + 'balanceEnd' => 'Balance at end of period', + 'reportsOwnAccounts' => 'Reports for your own accounts', + 'reportsOwnAccountsAndShared' => 'Reports for your own accounts and shared accounts', + 'splitByAccount' => 'Split by account', + 'balancedByTransfersAndTags' => 'Balanced by transfers and tags', + 'coveredWithTags' => 'Covered with tags', + 'leftUnbalanced' => 'Left unbalanced', + 'expectedBalance' => 'Expected balance', + 'outsideOfBudgets' => 'Outside of budgets', + 'leftInBudget' => 'Left in budget', + 'sumOfSums' => 'Sum of sums', + 'noCategory' => '(no category)', + 'notCharged' => 'Not charged (yet)', + 'inactive' => 'Inactive', + 'difference' => 'Difference', + 'in' => 'In', + 'out' => 'Out', + 'topX' => 'top :number', + 'showTheRest' => 'Show everything', + 'hideTheRest' => 'Show only the top :number', + 'sum_of_year' => 'Sum of year', + 'sum_of_years' => 'Sum of years', + 'average_of_year' => 'Average of year', + 'average_of_years' => 'Average of years', + 'categories_earned_in_year' => 'Categories (by earnings)', + 'categories_spent_in_year' => 'Categories (by spendings)', + 'report_type' => 'Report type', + 'report_type_default' => 'Default financial report', + 'report_included_accounts' => 'Included accounts', + 'report_date_range' => 'Date range', + 'report_include_help' => 'In all cases, transfers to shared accounts count as expenses, and transfers from shared accounts count as income.', + 'report_preset_ranges' => 'Pre-set ranges', + 'shared' => 'Shared', // charts: - 'dayOfMonth' => 'Day of the month', - 'month' => 'Month', - 'budget' => 'Budget', - 'spent' => 'Spent', - 'earned' => 'Earned', - 'overspent' => 'Overspent', - 'left' => 'Left', - 'noBudget' => '(no budget)', - 'maxAmount' => 'Maximum amount', - 'minAmount' => 'Minumum amount', - 'billEntry' => 'Current bill entry', - 'name' => 'Name', - 'date' => 'Date', - 'paid' => 'Paid', - 'unpaid' => 'Unpaid', - 'day' => 'Day', - 'budgeted' => 'Budgeted', - 'period' => 'Period', - 'balance' => 'Balance', - 'summary' => 'Summary', - 'sum' => 'Sum', - 'average' => 'Average', - 'balanceFor' => 'Balance for :name', + 'dayOfMonth' => 'Day of the month', + 'month' => 'Month', + 'budget' => 'Budget', + 'spent' => 'Spent', + 'earned' => 'Earned', + 'overspent' => 'Overspent', + 'left' => 'Left', + 'noBudget' => '(no budget)', + 'maxAmount' => 'Maximum amount', + 'minAmount' => 'Minumum amount', + 'billEntry' => 'Current bill entry', + 'name' => 'Name', + 'date' => 'Date', + 'paid' => 'Paid', + 'unpaid' => 'Unpaid', + 'day' => 'Day', + 'budgeted' => 'Budgeted', + 'period' => 'Period', + 'balance' => 'Balance', + 'summary' => 'Summary', + 'sum' => 'Sum', + 'average' => 'Average', + 'balanceFor' => 'Balance for :name', // piggy banks: - 'piggy_bank' => 'Piggy bank', - 'new_piggy_bank' => 'Create new piggy bank', - 'store_piggy_bank' => 'Store new piggy bank', - 'account_status' => 'Account status', - 'left_for_piggy_banks' => 'Left for piggy banks', - 'sum_of_piggy_banks' => 'Sum of piggy banks', - 'saved_so_far' => 'Saved so far', - 'left_to_save' => 'Left to save', - 'add_money_to_piggy_title' => 'Add money to piggy bank ":name"', - 'remove_money_from_piggy_title' => 'Remove money from piggy bank ":name"', - 'add' => 'Add', - 'remove' => 'Remove', - 'max_amount_add' => 'The maximum amount you can add is', - 'max_amount_remove' => 'The maximum amount you can remove is', - 'update_piggy_button' => 'Update piggy bank', - 'update_piggy_title' => 'Update piggy bank ":name"', - 'details' => 'Details', - 'events' => 'Events', - 'target_amount' => 'Target amount', - 'start_date' => 'Start date', - 'target_date' => 'Target date', - 'no_target_date' => 'No target date', - 'todo' => 'to do', - 'table' => 'Table', - 'piggy_bank_not_exists' => 'Piggy bank no longer exists.', - 'add_any_amount_to_piggy' => 'Add money to this piggy bank to reach your target of :amount.', - 'add_set_amount_to_piggy' => 'Add :amount to fill this piggy bank on :date', - 'delete_piggy_bank' => 'Delete piggy bank ":name"', + 'piggy_bank' => 'Piggy bank', + 'new_piggy_bank' => 'Create new piggy bank', + 'store_piggy_bank' => 'Store new piggy bank', + 'account_status' => 'Account status', + 'left_for_piggy_banks' => 'Left for piggy banks', + 'sum_of_piggy_banks' => 'Sum of piggy banks', + 'saved_so_far' => 'Saved so far', + 'left_to_save' => 'Left to save', + 'add_money_to_piggy_title' => 'Add money to piggy bank ":name"', + 'remove_money_from_piggy_title' => 'Remove money from piggy bank ":name"', + 'add' => 'Add', + 'remove' => 'Remove', + 'max_amount_add' => 'The maximum amount you can add is', + 'max_amount_remove' => 'The maximum amount you can remove is', + 'update_piggy_button' => 'Update piggy bank', + 'update_piggy_title' => 'Update piggy bank ":name"', + 'details' => 'Details', + 'events' => 'Events', + 'target_amount' => 'Target amount', + 'start_date' => 'Start date', + 'target_date' => 'Target date', + 'no_target_date' => 'No target date', + 'todo' => 'to do', + 'table' => 'Table', + 'piggy_bank_not_exists' => 'Piggy bank no longer exists.', + 'add_any_amount_to_piggy' => 'Add money to this piggy bank to reach your target of :amount.', + 'add_set_amount_to_piggy' => 'Add :amount to fill this piggy bank on :date', + 'delete_piggy_bank' => 'Delete piggy bank ":name"', // tags - 'regular_tag' => 'Just a regular tag.', - 'balancing_act' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.', - 'advance_payment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.', - 'delete_tag' => 'Delete tag ":tag"', - 'new_tag' => 'Make new tag', - 'edit_tag' => 'Edit tag ":tag"', - 'no_year' => 'No year set', - 'no_month' => 'No month set', - 'tag_title_nothing' => 'Default tags', - 'tag_title_balancingAct' => 'Balancing act tags', - 'tag_title_advancePayment' => 'Advance payment tags', - 'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like expensive, bill or for-party. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called Christmas dinner with friends and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.', - 'tags_group' => 'Tags group transactions together, which makes it possible to store reimbursements (in case you front money for others) and other "balancing acts" where expenses are summed up (the payments on your new TV) or where expenses and deposits are cancelling each other out (buying something with saved money). It\'s all up to you. Using tags the old-fashioned way is of course always possible.', - 'tags_start' => 'Create a tag to get started or enter tags when creating new transactions.', + 'regular_tag' => 'Just a regular tag.', + 'balancing_act' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.', + 'advance_payment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.', + 'delete_tag' => 'Delete tag ":tag"', + 'new_tag' => 'Make new tag', + 'edit_tag' => 'Edit tag ":tag"', + 'no_year' => 'No year set', + 'no_month' => 'No month set', + 'tag_title_nothing' => 'Default tags', + 'tag_title_balancingAct' => 'Balancing act tags', + 'tag_title_advancePayment' => 'Advance payment tags', + 'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like expensive, bill or for-party. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called Christmas dinner with friends and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.', + 'tags_group' => 'Tags group transactions together, which makes it possible to store reimbursements (in case you front money for others) and other "balancing acts" where expenses are summed up (the payments on your new TV) or where expenses and deposits are cancelling each other out (buying something with saved money). It\'s all up to you. Using tags the old-fashioned way is of course always possible.', + 'tags_start' => 'Create a tag to get started or enter tags when creating new transactions.', ]; diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index b76eac684f..d1d398ebc2 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -53,6 +53,7 @@ return [ 'csv_config' => 'CSV import configuration', 'specifix' => 'Bank- or file specific fixes', 'csv_import_account' => 'Default import account', + 'csv_delimiter' => 'CSV field delimiter', 'attachments[]' => 'Attachments', 'store_new_withdrawal' => 'Store new withdrawal', 'store_new_deposit' => 'Store new deposit', @@ -67,6 +68,12 @@ return [ 'filename' => 'File name', 'mime' => 'Mime type', 'size' => 'Size', + 'trigger' => 'Trigger', + 'stop_processing' => 'Stop processing', + + 'csv_comma' => 'A comma (,)', + 'csv_semicolon' => 'A semicolon (;)', + 'csv_tab' => 'A tab (invisible)', 'delete_account' => 'Delete account ":name"', @@ -76,10 +83,14 @@ return [ 'delete_currency' => 'Delete currency ":name"', 'delete_journal' => 'Delete transaction with description ":description"', 'delete_attachment' => 'Delete attachment ":name"', + 'delete_rule' => 'Delete rule ":title"', + 'delete_rule_group' => 'Delete rule group ":title"', 'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?', 'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?', 'bill_areYouSure' => 'Are you sure you want to delete the bill named ":name"?', + 'rule_areYouSure' => 'Are you sure you want to delete the rule titled ":title"?', + 'ruleGroup_areYouSure' => 'Are you sure you want to delete the rule group titled ":title"?', 'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?', 'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?', 'currency_areYouSure' => 'Are you sure you want to delete the currency named ":name"?', @@ -89,6 +100,7 @@ return [ 'permDeleteWarning' => 'Deleting stuff from Firely is permanent and cannot be undone.', 'also_delete_transactions' => 'The only transaction connected to this account will be deleted as well.|All :count transactions connected to this account will be deleted as well.', + 'also_delete_rules' => 'The only rule connected to this rule group will be deleted as well.|All :count rules connected to this rule group will be deleted as well.', 'also_delete_piggyBanks' => 'The only piggy bank connected to this account will be deleted as well.|All :count piggy bank connected to this account will be deleted as well.', 'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.|All :count transactions connected to this bill will spared deletion.', 'budget_keep_transactions' => 'The only transaction connected to this budget will not be deleted.|All :count transactions connected to this budget will spared deletion.', diff --git a/resources/lang/en_US/passwords.php b/resources/lang/en_US/passwords.php index f248128198..125f093fa8 100644 --- a/resources/lang/en_US/passwords.php +++ b/resources/lang/en_US/passwords.php @@ -17,6 +17,6 @@ return [ "token" => "This password reset token is invalid.", "sent" => "We have e-mailed your password reset link!", "reset" => "Your password has been reset!", - 'blocked' => 'Nice try though.' + 'blocked' => 'Nice try though.', ]; diff --git a/resources/lang/en_US/validation.php b/resources/lang/en_US/validation.php index 21dbc4ed0e..88e58d3a19 100644 --- a/resources/lang/en_US/validation.php +++ b/resources/lang/en_US/validation.php @@ -1,6 +1,8 @@ 'This value is invalid for the selected trigger.', + 'rule_action_value' => 'This value is invalid for the selected action.', 'invalid_domain' => 'Due to security constraints, you cannot register from this domain.', 'file_already_attached' => 'Uploaded file ":name" is already attached to this object.', 'file_attached' => 'Succesfully uploaded file ":name".', diff --git a/resources/lang/fr_FR/breadcrumbs.php b/resources/lang/fr_FR/breadcrumbs.php old mode 100644 new mode 100755 diff --git a/resources/lang/fr_FR/config.php b/resources/lang/fr_FR/config.php old mode 100644 new mode 100755 diff --git a/resources/lang/fr_FR/firefly.php b/resources/lang/fr_FR/firefly.php old mode 100644 new mode 100755 index d9dfa8daff..b28d430ad5 --- a/resources/lang/fr_FR/firefly.php +++ b/resources/lang/fr_FR/firefly.php @@ -1,487 +1,593 @@ 'Vous avez choisi Anglais', - 'close' => 'Fermer', - 'pleaseHold' => 'Veuillew patienter...', - 'actions' => 'Actions', - 'edit' => 'Editer', - 'delete' => 'Supprimer', - 'welcomeBack' => 'What\'s playing?', - 'everything' => 'Everything', - 'customRange' => 'Custom range', - 'apply' => 'Apply', - 'cancel' => 'Cancel', - 'from' => 'From', - 'to' => 'To', - 'total_sum' => 'Total sum', - 'period_sum' => 'Sum for period', - 'showEverything' => 'Show everything', - 'never' => 'Never', - 'search_results_for' => 'Search results for ":query"', - 'bounced_error' => 'The message sent to :email bounced, so no access for you.', - 'deleted_error' => 'These credentials do not match our records.', - 'general_blocked_error' => 'Your account has been disabled, so you cannot login.', - 'removed_amount' => 'Removed :amount', - 'added_amount' => 'Added :amount', - 'asset_account_role_help' => 'Any extra options resulting from your choice can be set later.', - 'Opening balance' => 'Opening balance', - 'create_new_stuff' => 'Create new stuff', - 'new_withdrawal' => 'New withdrawal', - 'new_deposit' => 'New deposit', - 'new_transfer' => 'New transfer', - 'new_asset_account' => 'New asset account', - 'new_expense_account' => 'New expense account', - 'new_revenue_account' => 'New revenue account', - 'new_budget' => 'New budget', - 'new_bill' => 'New bill', + // general stuff: + 'language_incomplete' => 'Cette langue n\'est pas encore complètement traduite', + 'test' => 'Vous avez choisi Anglais', + 'close' => 'Fermer', + 'pleaseHold' => 'Veuillew patienter...', + 'actions' => 'Actions', + 'edit' => 'Editer', + 'delete' => 'Supprimer', + 'welcomeBack' => 'What\'s playing?', + 'everything' => 'Tout', + 'customRange' => 'Plage personnalisée', + 'apply' => 'Appliquer', + 'cancel' => 'Annuler', + 'from' => 'Depuis', + 'to' => 'To', + 'total_sum' => 'Montant total ', + 'period_sum' => 'Somme pour la période', + 'showEverything' => 'Tout Afficher', + 'never' => 'Jamais', + 'search_results_for' => 'Résultats de recherche pour ":query"', + 'bounced_error' => 'Le message envoyé à :email a été rejeté, donc pas d\'accès pour vous.', + 'deleted_error' => 'These credentials do not match our records.', + 'general_blocked_error' => 'Your account has been disabled, so you cannot login.', + 'removed_amount' => 'Supprimé :amount', + 'added_amount' => 'Ajouté :amount', + 'asset_account_role_help' => 'Any extra options resulting from your choice can be set later.', + 'Opening balance' => 'Solde initial', + 'create_new_stuff' => 'Create new stuff', + 'new_withdrawal' => 'Nouveau retrait', + 'new_deposit' => 'Nouveau dépôt', + 'new_transfer' => 'Nouveau transfert', + 'new_asset_account' => 'New asset account', + 'new_expense_account' => 'New expense account', + 'new_revenue_account' => 'Nouveau compte de recettes', + 'new_budget' => 'Nouveau budget', + 'new_bill' => 'Nouvelle facture', + + // rules + 'rules' => 'Rules', + 'rules_explanation' => 'Here you can manage rules. Rules are triggered when a transaction is created or updated. Then, if the transaction has certain properties (called "triggers") Firefly will execute the "actions". Combined, you can make Firefly respond in a certain way to new transactions.', + 'rule_name' => 'Name of rule', + 'rule_triggers' => 'Rule triggers when', + 'rule_actions' => 'Rule will', + 'new_rule' => 'New rule', + 'new_rule_group' => 'New rule group', + 'rule_priority_up' => 'Give rule more priority', + 'rule_priority_down' => 'Give rule less priority', + 'make_new_rule_group' => 'Make new rule group', + 'store_new_rule_group' => 'Store new rule group', + 'created_new_rule_group' => 'New rule group ":title" stored!', + 'updated_rule_group' => 'Successfully updated rule group ":title".', + 'edit_rule_group' => 'Edit rule group ":title"', + 'delete_rule_group' => 'Delete rule group ":title"', + 'deleted_rule_group' => 'Deleted rule group ":title"', + 'update_rule_group' => 'Update rule group', + 'no_rules_in_group' => 'There are no rules in this group', + 'move_rule_group_up' => 'Move rule group up', + 'move_rule_group_down' => 'Move rule group down', + 'save_rules_by_moving' => 'Save these rule(s) by moving them to another rule group:', + 'make_new_rule' => 'Make new rule in rule group ":title"', + 'rule_help_stop_processing' => 'When you check this box, later rules in this group will not be executed.', + 'rule_help_active' => 'Inactive rules will never fire.', + 'stored_new_rule' => 'Stored new rule with title ":title"', + 'deleted_rule' => 'Deleted rule with title ":title"', + 'store_new_rule' => 'Store new rule', + 'updated_rule' => 'Updated rule with title ":title"', + + 'trigger' => 'Trigger', + 'trigger_value' => 'Trigger on value', + 'stop_processing_other_triggers' => 'Stop processing other triggers', + 'add_rule_trigger' => 'Add new trigger', + 'action' => 'Action', + 'action_value' => 'Action value', + 'stop_executing_other_actions' => 'Stop executing other actions', + 'add_rule_action' => 'Add new action', + 'edit_rule' => 'Edit rule ":title"', + 'update_rule' => 'Update rule', + + // actions and triggers + 'rule_trigger_user_action' => 'User action is ":trigger_value"', + 'rule_trigger_from_account_starts' => 'Source account starts with ":trigger_value"', + 'rule_trigger_from_account_ends' => 'Source account ends with ":trigger_value"', + 'rule_trigger_from_account_is' => 'Source account is ":trigger_value"', + 'rule_trigger_from_account_contains' => 'Source account contains ":trigger_value"', + 'rule_trigger_to_account_starts' => 'Destination account starts with ":trigger_value"', + 'rule_trigger_to_account_ends' => 'Destination account ends with ":trigger_value"', + 'rule_trigger_to_account_is' => 'Destination account is ":trigger_value"', + 'rule_trigger_to_account_contains' => 'Destination account contains ":trigger_value"', + 'rule_trigger_transaction_type' => 'Transaction is of type ":trigger_value"', + 'rule_trigger_amount_less' => 'Amount is less than :trigger_value', + 'rule_trigger_amount_exactly' => 'Amount is :trigger_value', + 'rule_trigger_amount_more' => 'Amount is more than :trigger_value', + 'rule_trigger_description_starts' => 'Description starts with ":trigger_value"', + 'rule_trigger_description_ends' => 'Description ends with ":trigger_value"', + 'rule_trigger_description_contains' => 'Description contains ":trigger_value"', + 'rule_trigger_description_is' => 'Description is ":trigger_value"', + + 'rule_trigger_from_account_starts_choice' => 'Source account starts with..', + 'rule_trigger_from_account_ends_choice' => 'Source account ends with..', + 'rule_trigger_from_account_is_choice' => 'Source account is..', + 'rule_trigger_from_account_contains_choice' => 'Source account contains..', + 'rule_trigger_to_account_starts_choice' => 'Destination account starts with..', + 'rule_trigger_to_account_ends_choice' => 'Destination account ends with..', + 'rule_trigger_to_account_is_choice' => 'Destination account is..', + 'rule_trigger_to_account_contains_choice' => 'Destination account contains..', + 'rule_trigger_transaction_type_choice' => 'Transaction is of type..', + 'rule_trigger_amount_less_choice' => 'Amount is less than..', + 'rule_trigger_amount_exactly_choice' => 'Amount is..', + 'rule_trigger_amount_more_choice' => 'Amount is more than..', + 'rule_trigger_description_starts_choice' => 'Description starts with..', + 'rule_trigger_description_ends_choice' => 'Description ends with..', + 'rule_trigger_description_contains_choice' => 'Description contains..', + 'rule_trigger_description_is_choice' => 'Description is..', + + 'rule_trigger_store_journal' => 'When a journal is created', + 'rule_trigger_update_journal' => 'When a journal is updated', + + 'rule_action_set_category' => 'Set category to ":action_value"', + 'rule_action_clear_category' => 'Clear category', + 'rule_action_set_budget' => 'Set budget to ":action_value"', + 'rule_action_clear_budget' => 'Clear budget', + 'rule_action_add_tag' => 'Add tag ":action_value"', + 'rule_action_remove_tag' => 'Remove tag ":action_value"', + 'rule_action_remove_all_tags' => 'Remove all tags', + 'rule_action_set_description' => 'Set description to ":action_value"', + 'rule_action_append_description' => 'Append description with ":action_value"', + 'rule_action_prepend_description' => 'Prepend description with ":action_value"', + + 'rule_action_set_category_choice' => 'Set category to..', + 'rule_action_clear_category_choice' => 'Clear any category', + 'rule_action_set_budget_choice' => 'Set budget to..', + 'rule_action_clear_budget_choice' => 'Clear any budget', + 'rule_action_add_tag_choice' => 'Add tag..', + 'rule_action_remove_tag_choice' => 'Remove tag..', + 'rule_action_remove_all_tags_choice' => 'Remove all tags', + 'rule_action_set_description_choice' => 'Set description to..', + 'rule_action_append_description_choice' => 'Append description with..', + 'rule_action_prepend_description_choice' => 'Prepend description with..', // tags - 'store_new_tag' => 'Store new tag', - 'update_tag' => 'Update tag', - 'no_location_set' => 'No location set.', - 'meta_data' => 'Meta data', - 'location' => 'Location', + 'store_new_tag' => 'Créer un nouveau tag', + 'update_tag' => 'Mettre à jour le tag', + 'no_location_set' => 'Aucun emplacement défini.', + 'meta_data' => 'Meta-données', + 'location' => 'Emplacement', // preferences - 'pref_home_screen_accounts' => 'Home screen accounts', - 'pref_home_screen_accounts_help' => 'Which accounts should be displayed on the home page?', - 'pref_budget_settings' => 'Budget settings', - 'pref_budget_settings_help' => 'What\'s the maximum amount of money a budget envelope may contain?', - 'pref_view_range' => 'View range', - 'pref_view_range_help' => 'Some charts are automatically grouped in periods. What period would you prefer?', - 'pref_1D' => 'One day', - 'pref_1W' => 'One week', - 'pref_1M' => 'One month', - 'pref_3M' => 'Three months (quarter)', - 'pref_6M' => 'Six months', - 'pref_languages' => 'Languages', - 'pref_languages_help' => 'Firefly III supports several languages. Which one do you prefer?', - 'pref_save_settings' => 'Save settings', + 'pref_home_screen_accounts' => 'Home screen accounts', + 'pref_home_screen_accounts_help' => 'Which accounts should be displayed on the home page?', + 'pref_budget_settings' => 'Paramètres de budget', + 'pref_budget_settings_help' => 'What\'s the maximum amount of money a budget envelope may contain?', + 'pref_view_range' => 'View range', + 'pref_view_range_help' => 'Some charts are automatically grouped in periods. What period would you prefer?', + 'pref_1D' => 'One day', + 'pref_1W' => 'One week', + 'pref_1M' => 'One month', + 'pref_3M' => 'Three months (quarter)', + 'pref_6M' => 'Six months', + 'pref_languages' => 'Languages', + 'pref_languages_help' => 'Firefly III supports several languages. Which one do you prefer?', + 'pref_save_settings' => 'Save settings', - // profile - 'change_your_password' => 'Change your password', - 'delete_account' => 'Delete account', - 'current_password' => 'Current password', - 'new_password' => 'New password', - 'new_password_again' => 'New password (again)', - 'delete_your_account' => 'Delete your account', - 'delete_your_account_help' => 'Deleting your account will also delete any accounts, transactions, anything you might have saved into Firefly III. It\'ll be GONE.', - 'delete_your_account_password' => 'Enter your password to continue.', - 'password' => 'Password', - 'are_you_sure' => 'Are you sure? You cannot undo this.', - 'delete_account_button' => 'DELETE your account', - 'invalid_current_password' => 'Invalid current password!', - 'password_changed' => 'Password changed!', - 'should_change' => 'The idea is to change your password.', - 'invalid_password' => 'Invalid password!', + // profile: + 'change_your_password' => 'Change your password', + 'delete_account' => 'Delete account', + 'current_password' => 'Current password', + 'new_password' => 'New password', + 'new_password_again' => 'New password (again)', + 'delete_your_account' => 'Delete your account', + 'delete_your_account_help' => 'Deleting your account will also delete any accounts, transactions, anything you might have saved into Firefly III. It\'ll be GONE.', + 'delete_your_account_password' => 'Enter your password to continue.', + 'password' => 'Password', + 'are_you_sure' => 'Are you sure? You cannot undo this.', + 'delete_account_button' => 'DELETE your account', + 'invalid_current_password' => 'Invalid current password!', + 'password_changed' => 'Password changed!', + 'should_change' => 'The idea is to change your password.', + 'invalid_password' => 'Invalid password!', // attachments - 'nr_of_attachments' => 'One attachment|:count attachments', - 'attachments' => 'Attachments', - 'edit_attachment' => 'Edit attachment ":name"', - 'update_attachment' => 'Update attachment', - 'delete_attachment' => 'Delete attachment ":name"', - 'attachment_deleted' => 'Deleted attachment ":name"', - 'upload_max_file_size' => 'Maximum file size: :size', + 'nr_of_attachments' => 'One attachment|:count attachments', + 'attachments' => 'Attachments', + 'edit_attachment' => 'Edit attachment ":name"', + 'update_attachment' => 'Update attachment', + 'delete_attachment' => 'Delete attachment ":name"', + 'attachment_deleted' => 'Deleted attachment ":name"', + 'upload_max_file_size' => 'Maximum file size: :size', - // tour - 'prev' => 'Prev', - 'next' => 'Next', - 'end-tour' => 'End tour', - 'pause' => 'Pause', + // tour: + 'prev' => 'Prev', + 'next' => 'Next', + 'end-tour' => 'End tour', + 'pause' => 'Pause', // transaction index - 'title_expenses' => 'Expenses', - 'title_withdrawal' => 'Expenses', - 'title_revenue' => 'Revenue / income', - 'title_deposit' => 'Revenue / income', - 'title_transfer' => 'Transferts', - 'title_transfers' => 'Transferts', + 'title_expenses' => 'Expenses', + 'title_withdrawal' => 'Expenses', + 'title_revenue' => 'Revenue / income', + 'title_deposit' => 'Revenue / income', + 'title_transfer' => 'Transferts', + 'title_transfers' => 'Transferts', - // csv import - 'csv_import' => 'Import CSV file', - 'csv' => 'CSV', - 'csv_index_title' => 'Upload and import a CSV file', - 'csv_define_column_roles' => 'Define column roles', - 'csv_map_values' => 'Map found values to existing values', - 'csv_download_config' => 'Download CSV configuration file.', - 'csv_index_text' => 'This form allows you to import a CSV file with transactions into Firefly. It is based on the excellent CSV importer made by the folks at Atlassian. Simply upload your CSV file and follow the instructions. If you would like to learn more, please click on the button at the top of this page.', - 'csv_index_beta_warning' => 'This tool is very much in beta. Please proceed with caution', - 'csv_header_help' => 'Check this box when your CSV file\'s first row consists of column names, not actual data', - 'csv_date_help' => 'Date time format in your CSV. Follow the format like this page indicates. The default value will parse dates that look like this: 20151201', - 'csv_csv_file_help' => 'Select the CSV file here. You can only upload one file at a time', - 'csv_csv_config_file_help' => 'Select your CSV import configuration here. If you do not know what this is, ignore it. It will be explained later.', - 'csv_upload_button' => 'Start importing CSV', - 'csv_column_roles_title' => 'Define column roles', - 'csv_column_roles_text' => 'Firefly does not know what each column means. You need to indicate what every column is. Please check out the example data if you\'re not sure yourself. Click on the question mark (top right of the page) to learn what each column means. If you want to map imported data onto existing data in Firefly, use the checkbox. The next step will show you what this button does.', - 'csv_column_roles_table' => 'Column roles', - 'csv_column' => 'CSV column', - 'csv_column_name' => 'CSV column name', - 'csv_column_example' => 'Column example data', - 'csv_column_role' => 'Column contains?', - 'csv_do_map_value' => 'Map value?', - 'csv_continue' => 'Continue to the next step', - 'csv_go_back' => 'Go back to the previous step', - 'csv_map_title' => 'Map found values to existing values', - 'csv_map_text' => 'This page allows you to map the values from the CSV file to existing entries in your database. This ensures that accounts and other things won\'t be created twice.', - 'csv_field_value' => 'Field value from CSV', - 'csv_field_mapped_to' => 'Must be mapped to...', - 'csv_do_not_map' => 'Do not map this value', - 'csv_download_config_title' => 'Download CSV configuration', - 'csv_download_config_text' => 'Everything you\'ve just set up can be downloaded as a configuration file. Click the button to do so.', - 'csv_more_information_text' => 'If the import fails, you can use this configuration file so you don\'t have to start all over again. But, if the import succeeds, it will be easier to upload similar CSV files.', - 'csv_do_download_config' => 'Download configuration file.', - 'csv_empty_description' => '(empty description)', - 'csv_upload_form' => 'CSV upload form', - 'csv_index_unsupported_warning' => 'The CSV importer is yet incapable of doing the following:', - 'csv_unsupported_map' => 'The importer cannot map the column ":columnRole" to existing values in the database.', - 'csv_unsupported_value' => 'The importer does not know how to handle values in columns marked as ":columnRole".', - 'csv_cannot_store_value' => 'The importer has not reserved space for columns marked ":columnRole" and will be incapable of processing them.', - 'csv_process_title' => 'CSV import finished!', - 'csv_process_text' => 'The CSV importer has finished and has processed :rows rows', - 'csv_row' => 'Row', - 'csv_import_with_errors' => 'There was one error.|There were :errors errors.', - 'csv_error_see_logs' => 'Check the log files to see details.', - 'csv_process_new_entries' => 'Firefly has created :imported new transaction(s).', - 'csv_start_over' => 'Import again', - 'csv_to_index' => 'Back home', - 'csv_upload_not_writeable' => 'Cannot write to the path mentioned here. Cannot upload', - 'csv_column__ignore' => '(ignore this column)', - 'csv_column_account-iban' => 'Asset account (IBAN)', - 'csv_column_account-id' => 'Asset account ID (matching Firefly)', - 'csv_column_account-name' => 'Asset account (name)', - 'csv_column_amount' => 'Amount', - 'csv_column_bill-id' => 'Bill ID (matching Firefly)', - 'csv_column_bill-name' => 'Bill name', - 'csv_column_budget-id' => 'Budget ID (matching Firefly)', - 'csv_column_budget-name' => 'Budget name', - 'csv_column_category-id' => 'Category ID (matching Firefly)', - 'csv_column_category-name' => 'Category name', - 'csv_column_currency-code' => 'Currency code (ISO 4217)', - 'csv_column_currency-id' => 'Currency ID (matching Firefly)', - 'csv_column_currency-name' => 'Currency name (matching Firefly)', - 'csv_column_currency-symbol' => 'Currency symbol (matching Firefly)', - 'csv_column_date-rent' => 'Rent calculation date', - 'csv_column_date-transaction' => 'Date', - 'csv_column_description' => 'Description', - 'csv_column_opposing-iban' => 'Opposing account (IBAN)', - 'csv_column_opposing-id' => 'Opposing account ID (matching Firefly)', - 'csv_column_opposing-name' => 'Opposing account (name)', - 'csv_column_rabo-debet-credit' => 'Rabobank specific debet/credit indicator', - 'csv_column_sepa-ct-id' => 'SEPA Credit Transfer end-to-end ID', - 'csv_column_sepa-ct-op' => 'SEPA Credit Transfer opposing account', - 'csv_column_sepa-db' => 'SEPA Direct Debet', - 'csv_column_tags-comma' => 'Tags (comma separated)', - 'csv_column_tags-space' => 'Tags (space separated)', - 'csv_specifix_RabobankDescription' => 'Select this when you\'re importing Rabobank CSV export files.', - 'csv_specifix_Dummy' => 'Checking this has no effect whatsoever.', - 'csv_import_account_help' => 'If your CSV file does NOT contain information about your asset account(s), use this dropdown to select to which account the transactions in the CSV belong to.', - 'csv_date_parse_error' => 'Could not parse a valid date from ":value", using the format ":format". Are you sure your CSV is correct?', + // csv import: + 'csv_import' => 'Import CSV file', + 'csv' => 'CSV', + 'csv_index_title' => 'Upload and import a CSV file', + 'csv_define_column_roles' => 'Define column roles', + 'csv_map_values' => 'Map found values to existing values', + 'csv_download_config' => 'Download CSV configuration file.', + 'csv_index_text' => 'This form allows you to import a CSV file with transactions into Firefly. It is based on the excellent CSV importer made by the folks at Atlassian. Simply upload your CSV file and follow the instructions. If you would like to learn more, please click on the button at the top of this page.', + 'csv_index_beta_warning' => 'This tool is very much in beta. Please proceed with caution', + 'csv_header_help' => 'Check this box when your CSV file\'s first row consists of column names, not actual data', + 'csv_date_help' => 'Date time format in your CSV. Follow the format like this page indicates. The default value will parse dates that look like this: :dateExample.', + 'csv_csv_file_help' => 'Select the CSV file here. You can only upload one file at a time', + 'csv_csv_config_file_help' => 'Select your CSV import configuration here. If you do not know what this is, ignore it. It will be explained later.', + 'csv_upload_button' => 'Start importing CSV', + 'csv_column_roles_title' => 'Define column roles', + 'csv_column_roles_text' => 'Firefly does not know what each column means. You need to indicate what every column is. Please check out the example data if you\'re not sure yourself. Click on the question mark (top right of the page) to learn what each column means. If you want to map imported data onto existing data in Firefly, use the checkbox. The next step will show you what this button does.', + 'csv_column_roles_table' => 'Column roles', + 'csv_column' => 'CSV column', + 'csv_column_name' => 'CSV column name', + 'csv_column_example' => 'Column example data', + 'csv_column_role' => 'Column contains?', + 'csv_do_map_value' => 'Map value?', + 'csv_continue' => 'Continue to the next step', + 'csv_go_back' => 'Go back to the previous step', + 'csv_map_title' => 'Map found values to existing values', + 'csv_map_text' => 'This page allows you to map the values from the CSV file to existing entries in your database. This ensures that accounts and other things won\'t be created twice.', + 'csv_field_value' => 'Field value from CSV', + 'csv_field_mapped_to' => 'Must be mapped to...', + 'csv_do_not_map' => 'Do not map this value', + 'csv_download_config_title' => 'Download CSV configuration', + 'csv_download_config_text' => 'Everything you\'ve just set up can be downloaded as a configuration file. Click the button to do so.', + 'csv_more_information_text' => 'If the import fails, you can use this configuration file so you don\'t have to start all over again. But, if the import succeeds, it will be easier to upload similar CSV files.', + 'csv_do_download_config' => 'Download configuration file.', + 'csv_empty_description' => '(empty description)', + 'csv_upload_form' => 'CSV upload form', + 'csv_index_unsupported_warning' => 'The CSV importer is yet incapable of doing the following:', + 'csv_unsupported_map' => 'The importer cannot map the column ":columnRole" to existing values in the database.', + 'csv_unsupported_value' => 'The importer does not know how to handle values in columns marked as ":columnRole".', + 'csv_cannot_store_value' => 'The importer has not reserved space for columns marked ":columnRole" and will be incapable of processing them.', + 'csv_process_title' => 'CSV import finished!', + 'csv_process_text' => 'The CSV importer has finished and has processed :rows rows', + 'csv_row' => 'Row', + 'csv_import_with_errors' => 'There was one error.|There were :errors errors.', + 'csv_error_see_logs' => 'Check the log files to see details.', + 'csv_process_new_entries' => 'Firefly has created :imported new transaction(s).', + 'csv_start_over' => 'Import again', + 'csv_to_index' => 'Back home', + 'csv_upload_not_writeable' => 'Cannot write to the path mentioned here. Cannot upload', + 'csv_column__ignore' => '(ignore this column)', + 'csv_column_account-iban' => 'Asset account (IBAN)', + 'csv_column_account-id' => 'Asset account ID (matching Firefly)', + 'csv_column_account-name' => 'Asset account (name)', + 'csv_column_amount' => 'Amount', + 'csv_column_amount-comma-separated' => 'Amount (comma as decimal separator)', + 'csv_column_bill-id' => 'Bill ID (matching Firefly)', + 'csv_column_bill-name' => 'Bill name', + 'csv_column_budget-id' => 'Budget ID (matching Firefly)', + 'csv_column_budget-name' => 'Budget name', + 'csv_column_category-id' => 'Category ID (matching Firefly)', + 'csv_column_category-name' => 'Category name', + 'csv_column_currency-code' => 'Currency code (ISO 4217)', + 'csv_column_currency-id' => 'Currency ID (matching Firefly)', + 'csv_column_currency-name' => 'Currency name (matching Firefly)', + 'csv_column_currency-symbol' => 'Currency symbol (matching Firefly)', + 'csv_column_date-rent' => 'Rent calculation date', + 'csv_column_date-transaction' => 'Date', + 'csv_column_description' => 'Description', + 'csv_column_opposing-iban' => 'Opposing account (IBAN)', + 'csv_column_opposing-id' => 'Opposing account ID (matching Firefly)', + 'csv_column_opposing-name' => 'Opposing account (name)', + 'csv_column_rabo-debet-credit' => 'Rabobank specific debet/credit indicator', + 'csv_column_sepa-ct-id' => 'SEPA Credit Transfer end-to-end ID', + 'csv_column_sepa-ct-op' => 'SEPA Credit Transfer opposing account', + 'csv_column_sepa-db' => 'SEPA Direct Debet', + 'csv_column_tags-comma' => 'Tags (comma separated)', + 'csv_column_tags-space' => 'Tags (space separated)', + 'csv_specifix_RabobankDescription' => 'Select this when you\'re importing Rabobank CSV export files.', + 'csv_specifix_AbnAmroDescription' => 'Select this when you\'re importing ABN AMRO CSV export files.', + 'csv_specifix_Dummy' => 'Checking this has no effect whatsoever.', + 'csv_import_account_help' => 'If your CSV file does NOT contain information about your asset account(s), use this dropdown to select to which account the transactions in the CSV belong to.', + 'csv_delimiter_help' => 'Choose the field delimiter that is used in your input file. If not sure, comma is the safest option.', + 'csv_date_parse_error' => 'Could not parse a valid date from ":value", using the format ":format". Are you sure your CSV is correct?', + // create new stuff: + 'create_new_withdrawal' => 'Creer un nouveau retrait', + 'create_new_deposit' => 'Create new deposit', + 'create_new_transfer' => 'Creer un nouveau transfert', + 'create_new_asset' => 'Create new asset account', + 'create_new_expense' => 'Create new expense account', + 'create_new_revenue' => 'Create new revenue account', + 'create_new_piggy_bank' => 'Create new piggy bank', + 'create_new_bill' => 'Create new bill', - // create new stuff - 'create_new_withdrawal' => 'Creer un nouveau retrait', - 'create_new_deposit' => 'Create new deposit', - 'create_new_transfer' => 'Creer un nouveau transfert', - 'create_new_asset' => 'Create new asset account', - 'create_new_expense' => 'Create new expense account', - 'create_new_revenue' => 'Create new revenue account', - 'create_new_piggy_bank' => 'Create new piggy bank', - 'create_new_bill' => 'Create new bill', + // currencies: + 'create_currency' => 'Create a new currency', + 'edit_currency' => 'Edit currency ":name"', + 'store_currency' => 'Store new currency', + 'update_currency' => 'Update currency', + 'new_default_currency' => ':name is now the default currency.', + 'cannot_delete_currency' => 'Cannot delete :name because there are still transactions attached to it!', + 'deleted_currency' => 'Currency :name deleted', + 'created_currency' => 'Currency :name created', + 'updated_currency' => 'Currency :name updated', + 'ask_site_owner' => 'Please ask :owner to add, remove or edit currencies.', + 'currencies_intro' => 'Firefly III supports various currencies which you can set and enable here.', + 'make_default_currency' => 'make default', + 'default_currency' => 'default', + // new user: + 'submit' => 'Submit', + 'getting_started' => 'Getting started', + 'to_get_started' => 'To get started with Firefly, please enter your current bank\'s name, and the balance of your checking account:', + 'savings_balance_text' => 'If you have a savings account, please enter the current balance of your savings account:', + 'cc_balance_text' => 'If you have a credit card, please enter your credit card\'s limit.', - // currencies - 'create_currency' => 'Create a new currency', - 'edit_currency' => 'Edit currency ":name"', - 'store_currency' => 'Store new currency', - 'update_currency' => 'Update currency', + // forms: + 'mandatoryFields' => 'Mandatory fields', + 'optionalFields' => 'Optional fields', + 'options' => 'Options', + 'something' => 'Something!', - // new user - 'submit' => 'Submit', - 'getting_started' => 'Getting started', - 'to_get_started' => 'To get started with Firefly, please enter your current bank\'s name, and the balance of your checking account:', - 'savings_balance_text' => 'If you have a savings account, please enter the current balance of your savings account:', - 'cc_balance_text' => 'If you have a credit card, please enter your credit card\'s limit.', + // budgets: + 'create_new_budget' => 'Create a new budget', + 'store_new_budget' => ' Store new budget', + 'availableIn' => 'Available in :date', + 'transactionsWithoutBudget' => 'Expenses without budget', + 'transactionsWithoutBudgetDate' => 'Expenses without budget in :date', + 'createBudget' => 'New budget', + 'inactiveBudgets' => 'Inactive budgets', + 'without_budget_between' => 'Transactions without a budget between :start and :end', + 'budget_in_month' => ':name in :month', + 'delete_budget' => 'Delete budget ":name"', + 'edit_budget' => 'Edit budget ":name"', + 'update_amount' => 'Update amount', + 'update_budget' => 'Update budget', - // forms - 'mandatoryFields' => 'Mandatory fields', - 'optionalFields' => 'Optional fields', - 'options' => 'Options', - 'something' => 'Something!', + // bills: + 'delete_bill' => 'Delete bill ":name"', + 'edit_bill' => 'Edit bill ":name"', + 'update_bill' => 'Update bill', + 'store_new_bill' => 'Store new bill', - // budgets - 'create_new_budget' => 'Create a new budget', - 'store_new_budget' => ' Store new budget', - 'availableIn' => 'Available in :date', - 'transactionsWithoutBudget' => 'Expenses without budget', - 'transactionsWithoutBudgetDate' => 'Expenses without budget in :date', - 'createBudget' => 'New budget', - 'inactiveBudgets' => 'Inactive budgets', - 'without_budget_between' => 'Transactions without a budget between :start and :end', - 'budget_in_month' => ':name in :month', - 'delete_budget' => 'Delete budget ":name"', - 'edit_budget' => 'Edit budget ":name"', - 'update_amount' => 'Update amount', - 'update_budget' => 'Update budget', + // accounts: + 'details_for_asset' => 'Details for asset account ":name"', + 'details_for_expense' => 'Details for expense account ":name"', + 'details_for_revenue' => 'Details for revenue account ":name"', + 'details_for_cash' => 'Details for cash account ":name"', + 'store_new_asset_account' => 'Store new asset account', + 'store_new_expense_account' => 'Store new expense account', + 'store_new_revenue_account' => 'Store new revenue account', + 'edit_asset_account' => 'Edit asset account ":name"', + 'edit_expense_account' => 'Edit expense account ":name"', + 'edit_revenue_account' => 'Edit revenue account ":name"', + 'delete_asset_account' => 'Delete asset account ":name"', + 'delete_expense_account' => 'Delete expense account ":name"', + 'delete_revenue_account' => 'Delete revenue account ":name"', + 'asset_deleted' => 'Successfully deleted asset account ":name"', + 'expense_deleted' => 'Successfully deleted expense account ":name"', + 'revenue_deleted' => 'Successfully deleted revenue account ":name"', + 'update_asset_account' => 'Update asset account', + 'update_expense_account' => 'Update expense account', + 'update_revenue_account' => 'Update revenue account', + 'make_new_asset_account' => 'Create a new asset account', + 'make_new_expense_account' => 'Create a new expense account', + 'make_new_revenue_account' => 'Create a new revenue account', + 'asset_accounts' => 'Asset accounts', + 'expense_accounts' => 'Expense accounts', + 'revenue_accounts' => 'Revenue accounts', + 'accountExtraHelp_asset' => '', + 'accountExtraHelp_expense' => '', + 'accountExtraHelp_revenue' => '', + 'account_type' => 'Account type', + 'save_transactions_by_moving' => 'Save these transaction(s) by moving them to another account:', - // bills - 'delete_bill' => 'Delete bill ":name"', - 'edit_bill' => 'Edit bill ":name"', - 'update_bill' => 'Update bill', - 'store_new_bill' => 'Store new bill', + // categories: + 'new_category' => 'New category', + 'create_new_category' => 'Create a new category', + 'without_category' => 'Without a category', + 'update_category' => 'Wijzig categorie', + 'categories' => 'Categories', + 'edit_category' => 'Edit category ":name"', + 'no_category' => '(no category)', + 'category' => 'Category', + 'delete_category' => 'Delete category ":name"', + 'store_category' => 'Store new category', + 'without_category_between' => 'Without category between :start and :end', - // accounts - 'details_for_asset' => 'Details for asset account ":name"', - 'details_for_expense' => 'Details for expense account ":name"', - 'details_for_revenue' => 'Details for revenue account ":name"', - 'details_for_cash' => 'Details for cash account ":name"', + // transactions: + 'update_withdrawal' => 'Update withdrawal', + 'update_deposit' => 'Update deposit', + 'update_transfer' => 'Update transfer', + 'delete_withdrawal' => 'Delete withdrawal ":description"', + 'delete_deposit' => 'Delete deposit ":description"', + 'delete_transfer' => 'Delete transfer ":description"', - 'store_new_asset_account' => 'Store new asset account', - 'store_new_expense_account' => 'Store new expense account', - 'store_new_revenue_account' => 'Store new revenue account', + // new user: + 'welcome' => 'Welcome to Firefly!', + 'createNewAsset' => 'Create a new asset account to get started. ' . + 'This will allow you to create transactions and start your financial management', + 'createNewAssetButton' => 'Create new asset account', - 'edit_asset_account' => 'Edit asset account ":name"', - 'edit_expense_account' => 'Edit expense account ":name"', - 'edit_revenue_account' => 'Edit revenue account ":name"', + // home page: + 'yourAccounts' => 'Your accounts', + 'budgetsAndSpending' => 'Budgets and spending', + 'savings' => 'Savings', + 'markAsSavingsToContinue' => 'Mark your asset accounts as "Savings account" to fill this panel', + 'createPiggyToContinue' => 'Create piggy banks to fill this panel.', + 'newWithdrawal' => 'New expense', + 'newDeposit' => 'New deposit', + 'newTransfer' => 'New transfer', + 'moneyIn' => 'Money in', + 'moneyOut' => 'Money out', + 'billsToPay' => 'Bills to pay', + 'billsPaid' => 'Bills paid', + 'viewDetails' => 'View details', + 'divided' => 'divided', + 'toDivide' => 'left to divide', - 'delete_asset_account' => 'Delete asset account ":name"', - 'delete_expense_account' => 'Delete expense account ":name"', - 'delete_revenue_account' => 'Delete revenue account ":name"', + // menu and titles, should be recycled as often as possible: + 'toggleNavigation' => 'Toggle navigation', + 'currency' => 'Currency', + 'preferences' => 'Preferences', + 'logout' => 'Logout', + 'searchPlaceholder' => 'Search...', + 'dashboard' => 'Dashboard', + 'currencies' => 'Currencies', + 'accounts' => 'Accounts', + 'Asset account' => 'Asset account', + 'Default account' => 'Asset account', + 'Expense account' => 'Expense account', + 'Revenue account' => 'Revenue account', + 'Initial balance account' => 'Initial balance account', + 'budgets' => 'Budgets', + 'tags' => 'Tags', + 'reports' => 'Reports', + 'transactions' => 'Transactions', + 'expenses' => 'Expenses', + 'income' => 'Revenue / income', + 'transfers' => 'Transferts', + 'moneyManagement' => 'Money management', + 'piggyBanks' => 'Piggy banks', + 'bills' => 'Bills', + 'createNew' => 'Create new', + 'withdrawal' => 'Withdrawal', + 'deposit' => 'Deposit', + 'account' => 'Account', + 'transfer' => 'Transfer', + 'Withdrawal' => 'Withdrawal', + 'Deposit' => 'Deposit', + 'Transfer' => 'Transfer', + 'bill' => 'Bill', + 'yes' => 'Yes', + 'no' => 'No', + 'amount' => 'Amount', + 'newBalance' => 'New balance', + 'overview' => 'Overview', + 'saveOnAccount' => 'Save on account', + 'unknown' => 'Unknown', + 'daily' => 'Daily', + 'weekly' => 'Weekly', + 'monthly' => 'Monthly', + 'quarterly' => 'Quarterly', + 'half-year' => 'Every six months', + 'yearly' => 'Yearly', + 'profile' => 'Profile', - 'asset_deleted' => 'Successfully deleted asset account ":name"', - 'expense_deleted' => 'Successfully deleted expense account ":name"', - 'revenue_deleted' => 'Successfully deleted revenue account ":name"', + // reports: + 'report_default' => 'Default financial report for :start until :end', + 'quick_link_reports' => 'Quick links', + 'quick_link_default_report' => 'Default financial report', + 'report_this_month_quick' => 'Current month, all accounts', + 'report_this_year_quick' => 'Current year, all accounts', + 'report_all_time_quick' => 'All-time, all accounts', + 'reports_can_bookmark' => 'Remember that reports can be bookmarked.', + 'incomeVsExpenses' => 'Income vs. expenses', + 'accountBalances' => 'Account balances', + 'balanceStartOfYear' => 'Balance at start of year', + 'balanceEndOfYear' => 'Balance at end of year', + 'balanceStartOfMonth' => 'Balance at start of month', + 'balanceEndOfMonth' => 'Balance at end of month', + 'balanceStart' => 'Balance at start of period', + 'balanceEnd' => 'Balance at end of period', + 'reportsOwnAccounts' => 'Reports for your own accounts', + 'reportsOwnAccountsAndShared' => 'Reports for your own accounts and shared accounts', + 'splitByAccount' => 'Split by account', + 'balancedByTransfersAndTags' => 'Balanced by transfers and tags', + 'coveredWithTags' => 'Covered with tags', + 'leftUnbalanced' => 'Left unbalanced', + 'expectedBalance' => 'Expected balance', + 'outsideOfBudgets' => 'Outside of budgets', + 'leftInBudget' => 'Left in budget', + 'sumOfSums' => 'Sum of sums', + 'noCategory' => '(no category)', + 'notCharged' => 'Not charged (yet)', + 'inactive' => 'Inactive', + 'difference' => 'Difference', + 'in' => 'In', + 'out' => 'Out', + 'topX' => 'top :number', + 'showTheRest' => 'Show everything', + 'hideTheRest' => 'Show only the top :number', + 'sum_of_year' => 'Sum of year', + 'sum_of_years' => 'Sum of years', + 'average_of_year' => 'Average of year', + 'average_of_years' => 'Average of years', + 'categories_earned_in_year' => 'Categories (by earnings)', + 'categories_spent_in_year' => 'Categories (by spendings)', + 'report_type' => 'Report type', + 'report_type_default' => 'Default financial report', + 'report_included_accounts' => 'Included accounts', + 'report_date_range' => 'Date range', + 'report_include_help' => 'In all cases, transfers to shared accounts count as expenses, and transfers from shared accounts count as income.', + 'report_preset_ranges' => 'Pre-set ranges', + 'shared' => 'Shared', - 'update_asset_account' => 'Update asset account', - 'update_expense_account' => 'Update expense account', - 'update_revenue_account' => 'Update revenue account', + // charts: + 'dayOfMonth' => 'Day of the month', + 'month' => 'Month', + 'budget' => 'Budget', + 'spent' => 'Spent', + 'earned' => 'Earned', + 'overspent' => 'Overspent', + 'left' => 'Left', + 'noBudget' => '(no budget)', + 'maxAmount' => 'Maximum amount', + 'minAmount' => 'Minumum amount', + 'billEntry' => 'Current bill entry', + 'name' => 'Name', + 'date' => 'Date', + 'paid' => 'Paid', + 'unpaid' => 'Unpaid', + 'day' => 'Day', + 'budgeted' => 'Budgeted', + 'period' => 'Period', + 'balance' => 'Balance', + 'summary' => 'Summary', + 'sum' => 'Sum', + 'average' => 'Average', + 'balanceFor' => 'Balance for :name', - 'make_new_asset_account' => 'Create a new asset account', - 'make_new_expense_account' => 'Create a new expense account', - 'make_new_revenue_account' => 'Create a new revenue account', - - 'asset_accounts' => 'Asset accounts', - 'expense_accounts' => 'Expense accounts', - 'revenue_accounts' => 'Revenue accounts', - - 'accountExtraHelp_asset' => '', - 'accountExtraHelp_expense' => '', - 'accountExtraHelp_revenue' => '', - 'account_type' => 'Account type', - 'save_transactions_by_moving' => 'Save these transaction(s) by moving them to another account:', - - // categories - 'new_category' => 'New category', - 'create_new_category' => 'Create a new category', - 'without_category' => 'Without a category', - 'update_category' => 'Wijzig categorie', - 'categories' => 'Categories', - 'edit_category' => 'Edit category ":name"', - 'no_category' => '(no category)', - 'category' => 'Category', - 'delete_category' => 'Delete category ":name"', - 'store_category' => 'Store new category', - - // transactions - 'update_withdrawal' => 'Update withdrawal', - 'update_deposit' => 'Update deposit', - 'update_transfer' => 'Update transfer', - 'delete_withdrawal' => 'Delete withdrawal ":description"', - 'delete_deposit' => 'Delete deposit ":description"', - 'delete_transfer' => 'Delete transfer ":description"', - - // new user - 'welcome' => 'Welcome to Firefly!', - 'createNewAsset' => 'Create a new asset account to get started. This will allow you to create transactions and start your financial management', - 'createNewAssetButton' => 'Create new asset account', - - // home page - 'yourAccounts' => 'Your accounts', - 'budgetsAndSpending' => 'Budgets and spending', - 'savings' => 'Savings', - 'markAsSavingsToContinue' => 'Mark your asset accounts as "Savings account" to fill this panel', - 'createPiggyToContinue' => 'Create piggy banks to fill this panel.', - 'newWithdrawal' => 'New expense', - 'newDeposit' => 'New deposit', - 'newTransfer' => 'New transfer', - 'moneyIn' => 'Money in', - 'moneyOut' => 'Money out', - 'billsToPay' => 'Bills to pay', - 'billsPaid' => 'Bills paid', - 'viewDetails' => 'View details', - 'divided' => 'divided', - 'toDivide' => 'left to divide', - - // menu and titles, should be recycled as often as possible - 'toggleNavigation' => 'Toggle navigation', - 'currency' => 'Currency', - 'preferences' => 'Preferences', - 'logout' => 'Logout', - 'searchPlaceholder' => 'Search...', - 'dashboard' => 'Dashboard', - 'currencies' => 'Currencies', - 'accounts' => 'Accounts', - 'Asset account' => 'Asset account', - 'Default account' => 'Asset account', - 'Expense account' => 'Expense account', - 'Revenue account' => 'Revenue account', - 'Initial balance account' => 'Initial balance account', - 'budgets' => 'Budgets', - 'tags' => 'Tags', - 'reports' => 'Reports', - 'transactions' => 'Transactions', - 'expenses' => 'Expenses', - 'income' => 'Revenue / income', - 'transfers' => 'Transferts', - 'moneyManagement' => 'Money management', - 'piggyBanks' => 'Piggy banks', - 'bills' => 'Bills', - 'createNew' => 'Create new', - 'withdrawal' => 'Withdrawal', - 'deposit' => 'Deposit', - 'account' => 'Account', - 'transfer' => 'Transfer', - 'Withdrawal' => 'Withdrawal', - 'Deposit' => 'Deposit', - 'Transfer' => 'Transfer', - 'bill' => 'Bill', - 'yes' => 'Yes', - 'no' => 'No', - 'amount' => 'Amount', - 'newBalance' => 'New balance', - 'overview' => 'Overview', - 'saveOnAccount' => 'Save on account', - 'unknown' => 'Unknown', - 'daily' => 'Daily', - 'weekly' => 'Weekly', - 'monthly' => 'Monthly', - 'quarterly' => 'Quarterly', - 'half-year' => 'Every six months', - 'yearly' => 'Yearly', - 'profile' => 'Profile', - - // reports - 'report_default' => 'Default financial report for :start until :end', - 'quick_link_reports' => 'Quick links', - 'quick_link_default_report' => 'Default financial report', - 'report_this_month_quick' => 'Current month, all accounts', - 'report_this_year_quick' => 'Current year, all accounts', - 'report_all_time_quick' => 'All-time, all accounts', - 'reports_can_bookmark' => 'Remember that reports can be bookmarked.', - 'incomeVsExpenses' => 'Income vs. expenses', - 'accountBalances' => 'Account balances', - 'balanceStartOfYear' => 'Balance at start of year', - 'balanceEndOfYear' => 'Balance at end of year', - 'balanceStartOfMonth' => 'Balance at start of month', - 'balanceEndOfMonth' => 'Balance at end of month', - 'balanceStart' => 'Balance at start of period', - 'balanceEnd' => 'Balance at end of period', - 'reportsOwnAccounts' => 'Reports for your own accounts', - 'reportsOwnAccountsAndShared' => 'Reports for your own accounts and shared accounts', - 'splitByAccount' => 'Split by account', - 'balancedByTransfersAndTags' => 'Balanced by transfers and tags', - 'coveredWithTags' => 'Covered with tags', - 'leftUnbalanced' => 'Left unbalanced', - 'expectedBalance' => 'Expected balance', - 'outsideOfBudgets' => 'Outside of budgets', - 'leftInBudget' => 'Left in budget', - 'sumOfSums' => 'Sum of sums', - 'noCategory' => '(no category)', - 'notCharged' => 'Not charged (yet)', - 'inactive' => 'Inactive', - 'difference' => 'Difference', - 'in' => 'In', - 'out' => 'Out', - 'topX' => 'top :number', - 'showTheRest' => 'Show everything', - 'hideTheRest' => 'Show only the top :number', - 'sum_of_year' => 'Sum of year', - 'sum_of_years' => 'Sum of years', - 'average_of_year' => 'Average of year', - 'average_of_years' => 'Average of years', - 'categories_earned_in_year' => 'Categories (by earnings)', - 'categories_spent_in_year' => 'Categories (by spendings)', - 'report_type' => 'Report type', - 'report_type_default' => 'Default financial report', - 'report_included_accounts' => 'Included accounts', - 'report_date_range' => 'Date range', - 'report_include_help' => 'In all cases, transfers to shared accounts count as expenses, and transfers from shared accounts count as income.', - 'report_preset_ranges' => 'Pre-set ranges', - 'shared' => 'Shared', - - // charts - 'dayOfMonth' => 'Day of the month', - 'month' => 'Month', - 'budget' => 'Budget', - 'spent' => 'Spent', - 'earned' => 'Earned', - 'overspent' => 'Overspent', - 'left' => 'Left', - 'noBudget' => '(no budget)', - 'maxAmount' => 'Maximum amount', - 'minAmount' => 'Minumum amount', - 'billEntry' => 'Current bill entry', - 'name' => 'Name', - 'date' => 'Date', - 'paid' => 'Paid', - 'unpaid' => 'Unpaid', - 'day' => 'Day', - 'budgeted' => 'Budgeted', - 'period' => 'Period', - 'balance' => 'Balance', - 'summary' => 'Summary', - 'sum' => 'Sum', - 'average' => 'Average', - 'balanceFor' => 'Balance for :name', - - // piggy banks - 'piggy_bank' => 'Piggy bank', - 'new_piggy_bank' => 'Create new piggy bank', - 'store_piggy_bank' => 'Store new piggy bank', - 'account_status' => 'Account status', - 'left_for_piggy_banks' => 'Left for piggy banks', - 'sum_of_piggy_banks' => 'Sum of piggy banks', - 'saved_so_far' => 'Saved so far', - 'left_to_save' => 'Left to save', - 'add_money_to_piggy_title' => 'Add money to piggy bank ":name"', - 'remove_money_from_piggy_title' => 'Remove money from piggy bank ":name"', - 'add' => 'Add', - 'remove' => 'Remove', - 'max_amount_add' => 'The maximum amount you can add is', - 'max_amount_remove' => 'The maximum amount you can remove is', - 'update_piggy_button' => 'Update piggy bank', - 'update_piggy_title' => 'Update piggy bank ":name"', - 'details' => 'Details', - 'events' => 'Events', - 'target_amount' => 'Target amount', - 'start_date' => 'Start date', - 'target_date' => 'Target date', - 'no_target_date' => 'No target date', - 'todo' => 'to do', - 'table' => 'Table', - 'piggy_bank_not_exists' => 'Piggy bank no longer exists.', - 'add_any_amount_to_piggy' => 'Add money to this piggy bank to reach your target of :amount.', - 'add_set_amount_to_piggy' => 'Add :amount to fill this piggy bank on :date', - 'delete_piggy_bank' => 'Delete piggy bank ":name"', + // piggy banks: + 'piggy_bank' => 'Piggy bank', + 'new_piggy_bank' => 'Create new piggy bank', + 'store_piggy_bank' => 'Store new piggy bank', + 'account_status' => 'Account status', + 'left_for_piggy_banks' => 'Left for piggy banks', + 'sum_of_piggy_banks' => 'Sum of piggy banks', + 'saved_so_far' => 'Saved so far', + 'left_to_save' => 'Left to save', + 'add_money_to_piggy_title' => 'Add money to piggy bank ":name"', + 'remove_money_from_piggy_title' => 'Remove money from piggy bank ":name"', + 'add' => 'Add', + 'remove' => 'Remove', + 'max_amount_add' => 'The maximum amount you can add is', + 'max_amount_remove' => 'The maximum amount you can remove is', + 'update_piggy_button' => 'Update piggy bank', + 'update_piggy_title' => 'Update piggy bank ":name"', + 'details' => 'Details', + 'events' => 'Events', + 'target_amount' => 'Target amount', + 'start_date' => 'Start date', + 'target_date' => 'Target date', + 'no_target_date' => 'No target date', + 'todo' => 'to do', + 'table' => 'Table', + 'piggy_bank_not_exists' => 'Piggy bank no longer exists.', + 'add_any_amount_to_piggy' => 'Add money to this piggy bank to reach your target of :amount.', + 'add_set_amount_to_piggy' => 'Add :amount to fill this piggy bank on :date', + 'delete_piggy_bank' => 'Delete piggy bank ":name"', // tags - 'regular_tag' => 'Just a regular tag.', - 'balancing_act' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.', - 'advance_payment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.', - - 'delete_tag' => 'Supprimer le tag ":tag"', - 'new_tag' => 'Make new tag', - 'edit_tag' => 'Editer le tag ":tag"', - 'no_year' => 'No year set', - 'no_month' => 'No month set', - 'tag_title_nothing' => 'Default tags', - 'tag_title_balancingAct' => 'Balancing act tags', - 'tag_title_advancePayment' => 'Advance payment tags', - 'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like expensive, bill or for-party. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called Christmas dinner with friends and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.', - 'tags_group' => 'Tags group transactions together, which makes it possible to store reimbursements (in case you front money for others) and other "balancing acts" where expenses are summed up (the payments on your new TV) or where expenses and deposits are cancelling each other out (buying something with saved money). It\'s all up to you. Using tags the old-fashioned way is of course always possible. ', - 'tags_start' => 'Create a tag to get started or enter tags when creating new transactions.', + 'regular_tag' => 'Just a regular tag.', + 'balancing_act' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.', + 'advance_payment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.', + 'delete_tag' => 'Supprimer le tag ":tag"', + 'new_tag' => 'Make new tag', + 'edit_tag' => 'Editer le tag ":tag"', + 'no_year' => 'No year set', + 'no_month' => 'No month set', + 'tag_title_nothing' => 'Default tags', + 'tag_title_balancingAct' => 'Balancing act tags', + 'tag_title_advancePayment' => 'Advance payment tags', + 'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like expensive, bill or for-party. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called Christmas dinner with friends and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.', + 'tags_group' => 'Tags group transactions together, which makes it possible to store reimbursements (in case you front money for others) and other "balancing acts" where expenses are summed up (the payments on your new TV) or where expenses and deposits are cancelling each other out (buying something with saved money). It\'s all up to you. Using tags the old-fashioned way is of course always possible.', + 'tags_start' => 'Create a tag to get started or enter tags when creating new transactions.', ]; diff --git a/resources/lang/fr_FR/form.php b/resources/lang/fr_FR/form.php old mode 100644 new mode 100755 index 19b1512659..a572419aec --- a/resources/lang/fr_FR/form.php +++ b/resources/lang/fr_FR/form.php @@ -2,33 +2,33 @@ return [ // new user: - 'bank_name' => 'Bank name', - 'bank_balance' => 'Balance', - 'savings_balance' => 'Savings balance', - 'credit_card_limit' => 'Credit card limit', + 'bank_name' => 'Nom de la banque', + 'bank_balance' => 'Solde', + 'savings_balance' => 'Solde de l\'épargne', + 'credit_card_limit' => 'Limite de carte de crédit', 'automatch' => 'Match automatically', 'skip' => 'Skip', - 'name' => 'Name', - 'active' => 'Active', - 'amount_min' => 'Minimum amount', - 'amount_max' => 'Maximum amount', + 'name' => 'Nom', + 'active' => 'Actif', + 'amount_min' => 'Montant minimum', + 'amount_max' => 'Montant maximum', 'match' => 'Matches on', 'repeat_freq' => 'Repeats', - 'account_from_id' => 'From account', - 'account_to_id' => 'To account', + 'account_from_id' => 'Compte d\'origine', + 'account_to_id' => 'Compte de destination', 'account_id' => 'Asset account', 'budget_id' => 'Budget', - 'openingBalance' => 'Opening balance', + 'openingBalance' => 'Solde initial', 'tagMode' => 'Tag mode', 'tagPosition' => 'Tag location', - 'virtualBalance' => 'Virtual balance', + 'virtualBalance' => 'Solde virtuel', 'longitude_latitude' => 'Location', 'targetamount' => 'Target amount', 'accountRole' => 'Account role', 'openingBalanceDate' => 'Opening balance date', 'ccType' => 'Credit card payment plan', 'ccMonthlyPaymentDate' => 'Credit card monthly payment date', - 'piggy_bank_id' => 'Piggy bank', + 'piggy_bank_id' => 'Tirelire', 'returnHere' => 'Return here', 'returnHereExplanation' => 'After storing, return here to create another one.', 'returnHereUpdateExplanation' => 'After updating, return here.', @@ -53,6 +53,7 @@ return [ 'csv_config' => 'CSV import configuration', 'specifix' => 'Bank- or file specific fixes', 'csv_import_account' => 'Default import account', + 'csv_delimiter' => 'CSV field delimiter', 'attachments[]' => 'Attachments', 'store_new_withdrawal' => 'Store new withdrawal', 'store_new_deposit' => 'Store new deposit', @@ -67,6 +68,13 @@ return [ 'filename' => 'File name', 'mime' => 'Mime type', 'size' => 'Size', + 'trigger' => 'Trigger', + 'stop_processing' => 'Stop processing', + + 'csv_comma' => 'A comma (,)', + 'csv_semicolon' => 'A semicolon (;)', + 'csv_tab' => 'A tab (invisible)', + 'delete_account' => 'Delete account ":name"', 'delete_bill' => 'Supprimer la facture ":name"', @@ -75,10 +83,14 @@ return [ 'delete_currency' => 'Delete currency ":name"', 'delete_journal' => 'Delete transaction with description ":description"', 'delete_attachment' => 'Delete attachment ":name"', + 'delete_rule' => 'Delete rule ":title"', + 'delete_rule_group' => 'Delete rule group ":title"', 'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?', 'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?', 'bill_areYouSure' => 'Are you sure you want to delete the bill named ":name"?', + 'rule_areYouSure' => 'Are you sure you want to delete the rule titled ":title"?', + 'ruleGroup_areYouSure' => 'Are you sure you want to delete the rule group titled ":title"?', 'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?', 'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?', 'currency_areYouSure' => 'Are you sure you want to delete the currency named ":name"?', @@ -88,6 +100,7 @@ return [ 'permDeleteWarning' => 'Deleting stuff from Firely is permanent and cannot be undone.', 'also_delete_transactions' => 'The only transaction connected to this account will be deleted as well.|All :count transactions connected to this account will be deleted as well.', + 'also_delete_rules' => 'The only rule connected to this rule group will be deleted as well.|All :count rules connected to this rule group will be deleted as well.', 'also_delete_piggyBanks' => 'The only piggy bank connected to this account will be deleted as well.|All :count piggy bank connected to this account will be deleted as well.', 'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.|All :count transactions connected to this bill will spared deletion.', 'budget_keep_transactions' => 'The only transaction connected to this budget will not be deleted.|All :count transactions connected to this budget will spared deletion.', diff --git a/resources/lang/fr_FR/help.php b/resources/lang/fr_FR/help.php old mode 100644 new mode 100755 index 75acf0fbdd..71f96fa6f2 --- a/resources/lang/fr_FR/help.php +++ b/resources/lang/fr_FR/help.php @@ -2,7 +2,7 @@ return [ // tour! - 'main-content-title' => 'Welcome to Firefly III', + 'main-content-title' => 'Bienvenue sur Firefly III', 'main-content-text' => 'Do yourself a favor and follow this short guide to make sure you know your way around.', 'sidebar-toggle-title' => 'Sidebar to create stuff', 'sidebar-toggle-text' => 'Hidden under the plus icon are all the buttons to create new stuff. Accounts, transactions, everything!', @@ -13,81 +13,72 @@ return [ 'report-menu-title' => 'Rapport', 'report-menu-text' => 'Check this out when you want a solid overview of your fiances.', 'transaction-menu-title' => 'Transactions', - 'transaction-menu-text' => 'All transactions you\'ve created can be found here.', + 'transaction-menu-text' => 'Toutes les transactions que vous avez créé peuvent être trouvées ici.', 'option-menu-title' => 'Options', - 'option-menu-text' => 'This is pretty self-explanatory.', - 'main-content-end-title' => 'The end!', - 'main-content-end-text' => 'Remember that every page has a small question mark at the right top. Click it to get help about the page you\'re on.', + 'option-menu-text' => 'C\'est assez explicite.', + 'main-content-end-title' => 'Fin !', + 'main-content-end-text' => 'N\'oubliez pas que chaque page a un petit point d\'interrogation en haut à droite. Cliquez dessus pour obtenir de l\'aide concernant la page actuelle.', - 'register' => 'register', - 'index' => 'The main index', - 'home' => 'home', - 'flush' => 'flush', - 'accounts-index' => 'accounts.index', - 'accounts-create' => 'accounts.create', - 'accounts-edit' => 'accounts.edit', - 'accounts-delete' => 'accounts.delete', - 'accounts-show' => 'accounts.show', - 'bills-index' => 'bills.index', - 'bills-rescan' => 'bills.rescan', - 'bills-create' => 'bills.create', - 'bills-edit' => 'bills.edit', - 'bills-delete' => 'bills.delete', - 'bills-show' => 'bills.show', - 'budgets-index' => 'budgets.index', - 'budgets-income' => 'budgets.income', - 'budgets-create' => 'budgets.create', - 'budgets-edit' => 'budgets.edit', - 'budgets-delete' => 'budgets.delete', - 'budgets-show' => 'budgets.show', - 'budgets-noBudget' => 'budgets.noBudget', - 'categories-index' => 'categories.index', - 'categories-create' => 'categories.create', - 'categories-edit' => 'categories.edit', - 'categories-delete' => 'categories.delete', - 'categories-show' => 'categories.show', - 'categories-noCategory' => 'categories.noCategory', - 'csv-index' => 'Upload and import a CSV file', - 'currency-index' => 'currency.index', - 'currency-create' => 'currency.create', - 'currency-edit' => 'currency.edit', - 'currency-delete' => 'currency.delete', - 'currency-default' => 'currency.default', - 'help-show' => 'help.show', - 'json-expense-accounts' => 'json.expense-accounts', - 'json-revenue-accounts' => 'json.revenue-accounts', - 'json-categories' => 'json.categories', - 'json-tags' => 'json.tags', - 'json-box-in' => 'json.box.in', - 'json-box-out' => 'json.box.out', - 'json-box-paid' => 'json.box.paid', - 'json-box-unpaid' => 'json.box.unpaid', - 'new-user-index' => 'new-user.index', - 'piggy-banks-index' => 'piggy-banks.index', - 'piggy-banks-addMoney' => 'piggy-banks.addMoney', - 'piggy-banks-removeMoney' => 'piggy-banks.removeMoney', - 'piggy-banks-create' => 'piggy-banks.create', - 'piggy-banks-edit' => 'piggy-banks.edit', - 'piggy-banks-delete' => 'piggy-banks.delete', - 'piggy-banks-show' => 'piggy-banks.show', - 'preferences' => 'preferences', - 'profile' => 'profile', - 'profile-change-password' => 'profile.change-password', - 'profile-delete-account' => 'profile.delete-account', - 'reports-index' => 'reports.index', - 'reports-year' => 'reports.year', - 'reports-month' => 'reports.month', - 'search' => 'search', - 'tags-index' => 'tags.index', - 'tags-create' => 'tags.create', - 'tags-show' => 'tags.show', - 'tags-edit' => 'tags.edit', - 'tags-delete' => 'tags.delete', - 'transactions-index' => 'transactions.index', - 'transactions-create' => 'transactions.create', - 'transactions-edit' => 'transactions.edit', - 'transactions-delete' => 'transactions.delete', - 'transactions-show' => 'transactions.show', - 'logout' => 'logout', + 'index' => 'index', + 'home' => 'home', + 'accounts-index' => 'accounts.index', + 'accounts-create' => 'accounts.create', + 'accounts-edit' => 'accounts.edit', + 'accounts-delete' => 'accounts.delete', + 'accounts-show' => 'accounts.show', + 'attachments-edit' => 'attachments.edit', + 'attachments-delete' => 'attachments.delete', + 'attachments-show' => 'attachments.show', + 'attachments-preview' => 'attachments.preview', + 'bills-index' => 'bills.index', + 'bills-create' => 'bills.create', + 'bills-edit' => 'bills.edit', + 'bills-delete' => 'bills.delete', + 'bills-show' => 'bills.show', + 'budgets-index' => 'budgets.index', + 'budgets-create' => 'budgets.create', + 'budgets-edit' => 'budgets.edit', + 'budgets-delete' => 'budgets.delete', + 'budgets-show' => 'budgets.show', + 'budgets-noBudget' => 'budgets.noBudget', + 'categories-index' => 'categories.index', + 'categories-create' => 'categories.create', + 'categories-edit' => 'categories.edit', + 'categories-delete' => 'categories.delete', + 'categories-show' => 'categories.show', + 'categories-show-date' => 'categories.show.date', + 'categories-noCategory' => 'categories.noCategory', + 'csv-index' => 'csv.index', + 'csv-column-roles' => 'csv.column-roles', + 'csv-map' => 'csv.map', + 'csv-download-config-page' => 'csv.download-config-page', + 'csv-process' => 'csv.process', + 'currency-index' => 'currency.index', + 'currency-create' => 'currency.create', + 'currency-edit' => 'currency.edit', + 'currency-delete' => 'currency.delete', + 'new-user-index' => 'new-user.index', + 'piggy-banks-index' => 'piggy-banks.index', + 'piggy-banks-create' => 'piggy-banks.create', + 'piggy-banks-edit' => 'piggy-banks.edit', + 'piggy-banks-delete' => 'piggy-banks.delete', + 'piggy-banks-show' => 'piggy-banks.show', + 'preferences' => 'preferences', + 'profile' => 'profile', + 'profile-change-password' => 'profile.change-password', + 'profile-delete-account' => 'profile.delete-account', + 'reports-index' => 'reports.index', + 'reports-report' => 'reports.report', + 'search' => 'search', + 'tags-index' => 'tags.index', + 'tags-create' => 'tags.create', + 'tags-show' => 'tags.show', + 'tags-edit' => 'tags.edit', + 'tags-delete' => 'tags.delete', + 'transactions-index' => 'transactions.index', + 'transactions-create' => 'transactions.create', + 'transactions-edit' => 'transactions.edit', + 'transactions-delete' => 'transactions.delete', + 'transactions-show' => 'transactions.show', ]; diff --git a/resources/lang/fr_FR/list.php b/resources/lang/fr_FR/list.php old mode 100644 new mode 100755 index 4bc0b61bc9..9d7fa6e86a --- a/resources/lang/fr_FR/list.php +++ b/resources/lang/fr_FR/list.php @@ -3,15 +3,15 @@ // all table headers. return [ - 'name' => 'Name', - 'role' => 'Role', - 'currentBalance' => 'Current balance', - 'active' => 'Is active?', - 'lastActivity' => 'Last activity', - 'balanceDiff' => 'Balance difference between :start and :end', + 'name' => 'Nom', + 'role' => 'Rôle', + 'currentBalance' => 'Solde courant', + 'active' => 'Actif ?', + 'lastActivity' => 'Activité récente', + 'balanceDiff' => 'Difference solde entre :start et :end', 'matchedOn' => 'Matched on', 'matchesOn' => 'Matched on', - 'matchingAmount' => 'Amount', + 'matchingAmount' => 'Montant', 'lastMatch' => 'Last match', 'expectedMatch' => 'Expected match', 'automatch' => 'Auto match?', diff --git a/resources/lang/fr_FR/pagination.php b/resources/lang/fr_FR/pagination.php old mode 100644 new mode 100755 index fcab34b253..e16f862ea6 --- a/resources/lang/fr_FR/pagination.php +++ b/resources/lang/fr_FR/pagination.php @@ -13,7 +13,7 @@ return [ | */ - 'previous' => '« Previous', - 'next' => 'Next »', + 'previous' => '« Precedent', + 'next' => 'Suivant »', ]; diff --git a/resources/lang/fr_FR/passwords.php b/resources/lang/fr_FR/passwords.php old mode 100644 new mode 100755 index 926c2b197d..49f2dfe6b1 --- a/resources/lang/fr_FR/passwords.php +++ b/resources/lang/fr_FR/passwords.php @@ -1,4 +1,11 @@ "Passwords must be at least six characters and match the confirmation.", - "user" => "We can't find a user with that e-mail address.", - "token" => "This password reset token is invalid.", - "sent" => "We have e-mailed your password reset link!", - "reset" => "Your password has been reset!", - 'blocked' => 'Nice try though.' + "password" => "Le mot de passe doit contenir au moins 6 caractères et correspondre à la confirmation.", + "user" => "Aucun utilisateur avec cette addresse email.", + "token" => "Le jeton de réinitialisation de mot de passe est invalide.", + "sent" => "Nous avons envoyé votre lien de réinitialisation de mot de passe!", + "reset" => "Le mot de passe a été réinitialisé!", + 'blocked' => 'Nice try though.', + ]; diff --git a/resources/lang/fr_FR/validation.php b/resources/lang/fr_FR/validation.php old mode 100644 new mode 100755 index fb45bf34d8..53c07b4811 --- a/resources/lang/fr_FR/validation.php +++ b/resources/lang/fr_FR/validation.php @@ -1,78 +1,69 @@ 'This value is invalid for the selected trigger.', + 'rule_action_value' => 'This value is invalid for the selected action.', 'invalid_domain' => 'Due to security constraints, you cannot register from this domain.', 'file_already_attached' => 'Uploaded file ":name" is already attached to this object.', 'file_attached' => 'Succesfully uploaded file ":name".', 'file_invalid_mime' => 'File ":name" is of type ":mime" which is not accepted as a new upload.', 'file_too_large' => 'File ":name" is too large.', - 'accepted' => 'Le champ :attribute doit être accepté.', + "accepted" => "Le champ :attribute doit être accepté.", + "active_url" => "Le champ :attribute n'est pas une URL valide.", + "after" => "Le champ :attribute doit être une date postérieure au :date.", + "alpha" => "Le champ :attribute doit seulement contenir des lettres.", + "alpha_dash" => "Le champ :attribute doit seulement contenir des lettres, des chiffres et des tirets.", + "alpha_num" => "Le champ :attribute doit seulement contenir des chiffres et des lettres.", + "array" => "Le champ :attribute doit être un tableau.", "unique_for_user" => "There already is an entry with this :attribute.", + "before" => "Le champ :attribute doit être une date antérieure au :date.", 'unique_object_for_user' => 'This name is already in use', 'unique_account_for_user' => 'This account name is already in use', - 'active_url' => "Le champ :attribute n'est pas une URL valide.", - 'after' => 'Le champ :attribute doit être une date postérieure au :date.', - 'alpha' => 'Le champ :attribute doit seulement contenir des lettres.', - 'alpha_dash' => 'Le champ :attribute doit seulement contenir des lettres, des chiffres et des tirets.', - 'alpha_num' => 'Le champ :attribute doit seulement contenir des chiffres et des lettres.', - 'array' => 'Le champ :attribute doit être un tableau.', - 'before' => 'Le champ :attribute doit être une date antérieure au :date.', - 'between.numeric' => 'La valeur de :attribute doit être comprise entre :min et :max.', - 'between.file' => 'Le fichier :attribute doit avoir une taille entre :min et :max kilo-octets.', - 'between.string' => 'Le texte :attribute doit avoir entre :min et :max caractères.', - 'between.array' => 'Le tableau :attribute doit avoir entre :min et :max éléments.', - 'boolean' => 'Le champ :attribute doit être vrai ou faux.', - 'confirmed' => 'Le champ de confirmation :attribute ne correspond pas.', - 'date' => "Le champ :attribute n'est pas une date valide.", - 'date_format' => 'Le champ :attribute ne correspond pas au format :format.', - 'different' => 'Les champs :attribute et :other doivent être différents.', - 'digits' => 'Le champ :attribute doit avoir :digits chiffres.', - 'digits_between' => 'Le champ :attribute doit avoir entre :min et :max chiffres.', - 'email' => 'Le champ :attribute doit être une adresse email valide.', - 'exists' => 'Le champ :attribute sélectionné est invalide.', - 'filled' => 'Le champ :attribute est obligatoire.', - 'image' => 'Le champ :attribute doit être une image.', - 'in' => 'Le champ :attribute est invalide.', - 'integer' => 'Le champ :attribute doit être un entier.', - 'ip' => 'Le champ :attribute doit être une adresse IP valide.', + "between.numeric" => "La valeur de :attribute doit être comprise entre :min et :max.", + "between.file" => "Le fichier :attribute doit avoir une taille entre :min et :max kilo-octets.", + "between.string" => "Le texte :attribute doit avoir entre :min et :max caractères.", + "between.array" => "Le tableau :attribute doit avoir entre :min et :max éléments.", + "boolean" => "Le champ :attribute doit être vrai ou faux.", + "confirmed" => "Le champ de confirmation :attribute ne correspond pas.", + "date" => "Le champ :attribute n'est pas une date valide.", + "date_format" => "Le champ :attribute ne correspond pas au format :format.", + "different" => "Les champs :attribute et :other doivent être différents.", + "digits" => "Le champ :attribute doit avoir :digits chiffres.", + "digits_between" => "Le champ :attribute doit avoir entre :min et :max chiffres.", + "email" => "Le champ :attribute doit être une adresse email valide.", + "filled" => "Le champ :attribute est obligatoire.", + "exists" => "Le champ :attribute sélectionné est invalide.", + "image" => "Le champ :attribute doit être une image.", + "in" => "Le champ :attribute est invalide.", + "integer" => "Le champ :attribute doit être un entier.", + "ip" => "Le champ :attribute doit être une adresse IP valide.", 'json' => 'Le champ :attribute doit être un document JSON valide.', - 'max.numeric' => 'La valeur de :attribute ne peut être supérieure à :max.', - 'max.file' => 'Le fichier :attribute ne peut être plus gros que :max kilo-octets.', - 'max.string' => 'Le texte de :attribute ne peut contenir plus de :max caractères.', - 'max.array' => 'Le tableau :attribute ne peut avoir plus de :max éléments.', - 'mimes' => 'Le champ :attribute doit être un fichier de type : :values.', - 'min.numeric' => 'La valeur de :attribute doit être supérieure à :min.', - 'min.file' => 'Le fichier :attribute doit être plus gros que :min kilo-octets.', - 'min.string' => 'Le texte :attribute doit contenir au moins :min caractères.', - 'min.array' => 'Le tableau :attribute doit avoir au moins :min éléments.', - 'not_in' => "Le champ :attribute sélectionné n'est pas valide.", - 'numeric' => 'Le champ :attribute doit contenir un nombre.', - 'regex' => 'Le format du champ :attribute est invalide.', - 'required' => 'Le champ :attribute est obligatoire.', - 'required_if' => 'Le champ :attribute est obligatoire quand la valeur de :other est :value.', + "max.numeric" => "La valeur de :attribute ne peut être supérieure à :max.", + "max.file" => "Le fichier :attribute ne peut être plus gros que :max kilo-octets.", + "max.string" => "Le texte de :attribute ne peut contenir plus de :max caractères.", + "max.array" => "Le tableau :attribute ne peut avoir plus de :max éléments.", + "mimes" => "Le champ :attribute doit être un fichier de type : :values.", + "min.numeric" => "La valeur de :attribute doit être supérieure à :min.", + "min.file" => "Le fichier :attribute doit être plus gros que :min kilo-octets.", + "min.string" => "Le texte :attribute doit contenir au moins :min caractères.", + "min.array" => "Le tableau :attribute doit avoir au moins :min éléments.", + "not_in" => "Le champ :attribute sélectionné n'est pas valide.", + "numeric" => "Le champ :attribute doit contenir un nombre.", + "regex" => "Le format du champ :attribute est invalide.", + "required" => "Le champ :attribute est obligatoire.", + "required_if" => "Le champ :attribute est obligatoire quand la valeur de :other est :value.", 'required_unless' => 'Le champ :attribute est obligatoire sauf si :other est :values.', - 'required_with' => 'Le champ :attribute est obligatoire quand :values est présent.', - 'required_with_all' => 'Le champ :attribute est obligatoire quand :values est présent.', - 'required_without' => "Le champ :attribute est obligatoire quand :values n'est pas présent.", - 'required_without_all' => "Le champ :attribute est requis quand aucun de :values n'est présent.", - 'same' => 'Les champs :attribute et :other doivent être identiques.', - 'size.numeric' => 'La valeur de :attribute doit être :size.', - 'size.file' => 'La taille du fichier de :attribute doit être de :size kilo-octets.', - 'size.string' => 'Le texte de :attribute doit contenir :size caractères.', - 'size.array' => 'Le tableau :attribute doit contenir :size éléments.', + "required_with" => "Le champ :attribute est obligatoire quand :values est présent.", + "required_with_all" => "Le champ :attribute est obligatoire quand :values est présent.", + "required_without" => "Le champ :attribute est obligatoire quand :values n'est pas présent.", + "required_without_all" => "Le champ :attribute est requis quand aucun de :values n'est présent.", + "same" => "Les champs :attribute et :other doivent être identiques.", + "size.numeric" => "La valeur de :attribute doit être :size.", + "size.file" => "La taille du fichier de :attribute doit être de :size kilo-octets.", + "size.string" => "Le texte de :attribute doit contenir :size caractères.", + "size.array" => "Le tableau :attribute doit contenir :size éléments.", + "unique" => "La valeur du champ :attribute est déjà utilisée.", 'string' => 'Le champ :attribute doit être une chaîne de caractères.', - 'timezone' => 'Le champ :attribute doit être un fuseau horaire valide.', - 'unique' => 'La valeur du champ :attribute est déjà utilisée.', - 'url' => "Le format de l'URL de :attribute n'est pas valide.", + "url" => "Le format de l'URL de :attribute n'est pas valide.", + "timezone" => "Le champ :attribute doit être un fuseau horaire valide.", ]; diff --git a/resources/lang/nl_NL/breadcrumbs.php b/resources/lang/nl_NL/breadcrumbs.php old mode 100644 new mode 100755 diff --git a/resources/lang/nl_NL/config.php b/resources/lang/nl_NL/config.php old mode 100644 new mode 100755 diff --git a/resources/lang/nl_NL/firefly.php b/resources/lang/nl_NL/firefly.php old mode 100644 new mode 100755 index 9d731d940b..093624be21 --- a/resources/lang/nl_NL/firefly.php +++ b/resources/lang/nl_NL/firefly.php @@ -2,476 +2,592 @@ return [ // general stuff: - 'test' => 'Nederlands geselecteerd!', - 'close' => 'Sluiten', - 'pleaseHold' => 'Momentje...', - 'actions' => 'Acties', - 'edit' => 'Wijzig', - 'delete' => 'Verwijder', - 'welcomeBack' => 'Hoe staat het er voor?', - 'everything' => 'Alles', - 'customRange' => 'Zelf bereik kiezen', - 'apply' => 'Go', - 'cancel' => 'Annuleren', - 'from' => 'Van', - 'to' => 'Tot', - 'total_sum' => 'Totale som', - 'period_sum' => 'Som van periode', - 'showEverything' => 'Laat alles zien', - 'never' => 'Nooit', - 'search_results_for' => 'Zoekresultaten voor ":query"', - 'bounced_error' => 'Het emailtje naar :email kwam nooit aan.', - 'deleted_error' => 'Deze gegevens zijn niet correct.', - 'general_blocked_error' => 'Je account is uitgeschakeld, je kan helaas niet inloggen.', - 'removed_amount' => ':amount weggehaald', - 'added_amount' => ':amount toegevoegd', - 'asset_account_role_help' => 'Voorkeuren die voortkomen uit je keuze hier kan je later aangeven.', - 'Opening balance' => 'Startsaldo', - 'create_new_stuff' => 'Nieuw', - 'new_withdrawal' => 'Nieuwe uitgave', - 'new_deposit' => 'Nieuwe inkomsten', - 'new_transfer' => 'Nieuwe overschrijving', - 'new_asset_account' => 'Nieuwe betaalrekening', - 'new_expense_account' => 'Nieuwe crediteur', - 'new_revenue_account' => 'Nieuwe debiteur', - 'new_budget' => 'Nieuw budget', - 'new_bill' => 'Nieuw contract', + 'language_incomplete' => 'Deze taal is nog niet helemaal af', + 'test' => 'Nederlands geselecteerd!', + 'close' => 'Sluiten', + 'pleaseHold' => 'Momentje...', + 'actions' => 'Acties', + 'edit' => 'Wijzig', + 'delete' => 'Verwijder', + 'welcomeBack' => 'Hoe staat het er voor?', + 'everything' => 'Alles', + 'customRange' => 'Zelf bereik kiezen', + 'apply' => 'Go', + 'cancel' => 'Annuleren', + 'from' => 'Van', + 'to' => 'Tot', + 'total_sum' => 'Totale som', + 'period_sum' => 'Som van periode', + 'showEverything' => 'Laat alles zien', + 'never' => 'Nooit', + 'search_results_for' => 'Zoekresultaten voor ":query"', + 'bounced_error' => 'Het emailtje naar :email kwam nooit aan.', + 'deleted_error' => 'Deze gegevens zijn niet correct.', + 'general_blocked_error' => 'Je account is uitgeschakeld, je kan helaas niet inloggen.', + 'removed_amount' => ':amount weggehaald', + 'added_amount' => ':amount toegevoegd', + 'asset_account_role_help' => 'Voorkeuren die voortkomen uit je keuze hier kan je later aangeven.', + 'Opening balance' => 'Startsaldo', + 'create_new_stuff' => 'Nieuw', + 'new_withdrawal' => 'Nieuwe uitgave', + 'new_deposit' => 'Nieuwe inkomsten', + 'new_transfer' => 'Nieuwe overschrijving', + 'new_asset_account' => 'Nieuwe betaalrekening', + 'new_expense_account' => 'Nieuwe crediteur', + 'new_revenue_account' => 'Nieuwe debiteur', + 'new_budget' => 'Nieuw budget', + 'new_bill' => 'Nieuw contract', + + // rules + 'rules' => 'Regels', + 'rules_explanation' => 'Hier kan je regels instellen. Regels worden in werking gesteld als je een bij-, afschrijving of overboeking maakt (of verandert). Als die transactie bepaalde eigenschappen heeft (zogenaamde "triggers") zal Firefly de bijbehorende "acties" uitvoeren. Gecombineerd kan je Firefly op een bepaalde manier laten reageren op nieuwe transacties.', + 'rule_name' => 'Regelnaam', + 'rule_triggers' => 'Regel reageert op', + 'rule_actions' => 'Regel zal dan', + 'new_rule' => 'Nieuwe regel', + 'new_rule_group' => 'Nieuwe regelgroep', + 'rule_priority_up' => 'Geef regel meer prioriteit', + 'rule_priority_down' => 'Geef regel minder prioriteit', + 'make_new_rule_group' => 'Maak nieuwe regelgroep', + 'store_new_rule_group' => 'Sla nieuwe regelgroep op', + 'created_new_rule_group' => 'Nieuwe regelgroep ":title" opgeslagen!', + 'updated_rule_group' => 'Regelgroep ":title" geüpdatet.', + 'edit_rule_group' => 'Wijzig regelgroep ":title"', + 'delete_rule_group' => 'Verwijder regelgroep ":title"', + 'deleted_rule_group' => 'Regelgroep ":title" verwijderd', + 'update_rule_group' => 'Wijzig regelgroep', + 'no_rules_in_group' => 'Er zijn geen regels in deze groep', + 'move_rule_group_up' => 'Verplaats regelgroep omhoog', + 'move_rule_group_down' => 'Verplaats regelgroep omlaag', + 'save_rules_by_moving' => 'Red deze regel(s) van de ondergang door ze te verplaatsen naar een andere regelgroep:', + 'make_new_rule' => 'Maak een nieuwe regel in regelgroep ":title"', + 'rule_help_stop_processing' => 'Zet hier een vinkje om latere regels in deze groep te negeren.', + 'rule_help_active' => 'Niet actieve regels zullen nooit worden gecontroleerd.', + 'stored_new_rule' => 'Nieuwe regel ":title" opgeslagen', + 'deleted_rule' => 'Regel ":title" verwijderd', + 'store_new_rule' => 'Sla nieuwe regel op', + 'updated_rule' => 'Regel ":title" geüpdatet', + + 'trigger' => 'Trigger', + 'trigger_value' => 'Trigger bij waarde', + 'stop_processing_other_triggers' => 'Reageer niet meer op andere triggers', + 'add_rule_trigger' => 'Nieuwe trigger toevoegen', + 'action' => 'Actie', + 'action_value' => 'Actie-waarde', + 'stop_executing_other_actions' => 'Voer verdere acties niet uit', + 'add_rule_action' => 'Nieuwe actie toevoegen', + 'edit_rule' => 'Wijzig regel ":title"', + 'update_rule' => 'Werk regel bij', + + // actions and triggers + 'rule_trigger_user_action' => 'Gebruikersactie is ":trigger_value"', + 'rule_trigger_from_account_starts' => 'Bronrekeningnaam begint met ":trigger_value"', + 'rule_trigger_from_account_ends' => 'Bronrekeningnaam eindigt op ":trigger_value"', + 'rule_trigger_from_account_is' => 'Bronrekeningnaam is ":trigger_value"', + 'rule_trigger_from_account_contains' => 'Bronrekeningnaam bevat ":trigger_value"', + 'rule_trigger_to_account_starts' => 'Doelrekeningnaam begint met ":trigger_value"', + 'rule_trigger_to_account_ends' => 'Doelrekeningnaam eindigt op ":trigger_value"', + 'rule_trigger_to_account_is' => 'Doelrekeningnaam is ":trigger_value"', + 'rule_trigger_to_account_contains' => 'Doelrekeningnaam bevat ":trigger_value"', + 'rule_trigger_transaction_type' => 'Transactiesoort is ":trigger_value" (Engels)', + 'rule_trigger_amount_less' => 'Bedrag is minder dan :trigger_value', + 'rule_trigger_amount_exactly' => 'Bedrag is :trigger_value', + 'rule_trigger_amount_more' => 'Bedrag is meer dan :trigger_value', + 'rule_trigger_description_starts' => 'Omschrijving begint met ":trigger_value"', + 'rule_trigger_description_ends' => 'Omschrijving eindigt op ":trigger_value"', + 'rule_trigger_description_contains' => 'Omschrijving bevat ":trigger_value"', + 'rule_trigger_description_is' => 'Omschrijving is ":trigger_value"', + + 'rule_trigger_from_account_starts_choice' => 'Bronrekening naam begint met..', + 'rule_trigger_from_account_ends_choice' => 'Bronrekening eindigt op..', + 'rule_trigger_from_account_is_choice' => 'Bronrekening is..', + 'rule_trigger_from_account_contains_choice' => 'Bronrekening bevat..', + 'rule_trigger_to_account_starts_choice' => 'Doelrekeningnaam begint met..', + 'rule_trigger_to_account_ends_choice' => 'Doelrekeningnaam eindigt op..', + 'rule_trigger_to_account_is_choice' => 'Doelrekeningnaam is..', + 'rule_trigger_to_account_contains_choice' => 'Doelrekeningnaam bevat..', + 'rule_trigger_transaction_type_choice' => 'Transactietype is..', + 'rule_trigger_amount_less_choice' => 'Bedrag is minder dan..', + 'rule_trigger_amount_exactly_choice' => 'Bedrag is..', + 'rule_trigger_amount_more_choice' => 'Bedrag is meer dan..', + 'rule_trigger_description_starts_choice' => 'Omschrijving begint met..', + 'rule_trigger_description_ends_choice' => 'Omschrijving eindigt op..', + 'rule_trigger_description_contains_choice' => 'Omschrijving bevat..', + 'rule_trigger_description_is_choice' => 'Omschrijving is..', + + 'rule_trigger_store_journal' => 'Als een transactie wordt gemaakt', + 'rule_trigger_update_journal' => 'Als een transactie wordt bewerkt', + + 'rule_action_set_category' => 'Verander categorie naar ":action_value"', + 'rule_action_clear_category' => 'Maak categorie-veld leeg', + 'rule_action_set_budget' => 'Sla op onder budget ":action_value"', + 'rule_action_clear_budget' => 'Sla op zonder budget', + 'rule_action_add_tag' => 'Voeg tag ":action_value" toe', + 'rule_action_remove_tag' => 'Haal tag ":action_value" weg', + 'rule_action_remove_all_tags' => 'Haal alle tags weg', + 'rule_action_set_description' => 'Geef omschrijving ":action_value"', + 'rule_action_append_description' => 'Zet ":action_value" voor de omschrijving', + 'rule_action_prepend_description' => 'Zet ":action_value" voor de omschrijving', + + 'rule_action_set_category_choice' => 'Geef categorie..', + 'rule_action_clear_category_choice' => 'Geef geen categorie', + 'rule_action_set_budget_choice' => 'Sla op onder budget..', + 'rule_action_clear_budget_choice' => 'Maak budget-veld leeg', + 'rule_action_add_tag_choice' => 'Voeg tag toe..', + 'rule_action_remove_tag_choice' => 'Haal tag weg..', + 'rule_action_remove_all_tags_choice' => 'Haal alle tags weg', + 'rule_action_set_description_choice' => 'Geef omschrijving..', + 'rule_action_append_description_choice' => 'Zet .. achter de omschrijving', + 'rule_action_prepend_description_choice' => 'Zet .. voor de omschrijving', // tags - 'store_new_tag' => 'Sla tag op', - 'update_tag' => 'Sla wijzigingen op', - 'no_location_set' => 'Zonder plaats', - 'meta_data' => 'Metagegevens', - 'location' => 'Plaats', + 'store_new_tag' => 'Sla tag op', + 'update_tag' => 'Sla wijzigingen op', + 'no_location_set' => 'Zonder plaats', + 'meta_data' => 'Metagegevens', + 'location' => 'Plaats', // preferences - 'pref_home_screen_accounts' => 'Voorpaginarekeningen', - 'pref_home_screen_accounts_help' => 'Welke betaalrekeningen wil je op de voorpagina zien?', - 'pref_budget_settings' => 'Budgetinstellingen', - 'pref_budget_settings_help' => 'Wat is het maximale bedrag dat je voor een budget kan instellen?', - 'pref_view_range' => 'Bereik', - 'pref_view_range_help' => 'Sommige pagina\'s springen naar een standaard bereik. Welk bereik heeft jouw voorkeur?', - 'pref_1D' => 'Eén dag', - 'pref_1W' => 'Eén week', - 'pref_1M' => 'Eén maand', - 'pref_3M' => 'Drie maanden (kwartaal)', - 'pref_6M' => 'Zes maanden', - 'pref_languages' => 'Talen', - 'pref_languages_help' => 'Firefly III ondersteunt meerdere talen. Welke heeft jouw voorkeur?', - 'pref_save_settings' => 'Instellingen opslaan', + 'pref_home_screen_accounts' => 'Voorpaginarekeningen', + 'pref_home_screen_accounts_help' => 'Welke betaalrekeningen wil je op de voorpagina zien?', + 'pref_budget_settings' => 'Budgetinstellingen', + 'pref_budget_settings_help' => 'Wat is het maximale bedrag dat je voor een budget kan instellen?', + 'pref_view_range' => 'Bereik', + 'pref_view_range_help' => 'Sommige pagina\'s springen naar een standaard bereik. Welk bereik heeft jouw voorkeur?', + 'pref_1D' => 'Eén dag', + 'pref_1W' => 'Eén week', + 'pref_1M' => 'Eén maand', + 'pref_3M' => 'Drie maanden (kwartaal)', + 'pref_6M' => 'Zes maanden', + 'pref_languages' => 'Talen', + 'pref_languages_help' => 'Firefly III ondersteunt meerdere talen. Welke heeft jouw voorkeur?', + 'pref_save_settings' => 'Instellingen opslaan', // profile: - 'change_your_password' => 'Verander je wachtwoord', - 'delete_account' => 'Verwijder je account', - 'current_password' => 'Huidige wachtwoord', - 'new_password' => 'Nieuw wachtwoord', - 'new_password_again' => 'Nieuw wachtwoord (bevestiging)', - 'delete_your_account' => 'Verwijder je account', - 'delete_your_account_help' => 'Als je je account verwijdert worden ook al je rekeningen, transacties en alle andere zaken verwijderd. Alles is dan WEG.', - 'delete_your_account_password' => 'Voer je wachtwoord in om door te gaan.', - 'password' => 'Wachtwoord', - 'are_you_sure' => 'Zeker weten? Je kan niet meer terug!', - 'delete_account_button' => 'VERWIJDER je account', - 'invalid_current_password' => 'Huidige wachtwoord is niet geldig!', - 'password_changed' => 'Je wachtwoord is veranderd!', - 'should_change' => 'Vul ook echt een ander wachtwoord in.', - 'invalid_password' => 'Ongeldig wachtwoord!', + 'change_your_password' => 'Verander je wachtwoord', + 'delete_account' => 'Verwijder je account', + 'current_password' => 'Huidige wachtwoord', + 'new_password' => 'Nieuw wachtwoord', + 'new_password_again' => 'Nieuw wachtwoord (bevestiging)', + 'delete_your_account' => 'Verwijder je account', + 'delete_your_account_help' => 'Als je je account verwijdert worden ook al je rekeningen, transacties en alle andere zaken verwijderd. Alles is dan WEG.', + 'delete_your_account_password' => 'Voer je wachtwoord in om door te gaan.', + 'password' => 'Wachtwoord', + 'are_you_sure' => 'Zeker weten? Je kan niet meer terug!', + 'delete_account_button' => 'VERWIJDER je account', + 'invalid_current_password' => 'Huidige wachtwoord is niet geldig!', + 'password_changed' => 'Je wachtwoord is veranderd!', + 'should_change' => 'Vul ook echt een ander wachtwoord in.', + 'invalid_password' => 'Ongeldig wachtwoord!', // attachments - 'nr_of_attachments' => 'Eén bijlage|:count bijlagen', - 'attachments' => 'Bijlagen', - 'edit_attachment' => 'Wijzig bijlage ":name"', - 'update_attachment' => 'Update bijlage', - 'delete_attachment' => 'Verwijder bijlage ":name"', - 'attachment_deleted' => 'Bijlage ":name" verwijderd', - 'upload_max_file_size' => 'Maximale grootte: :size', + 'nr_of_attachments' => 'Eén bijlage|:count bijlagen', + 'attachments' => 'Bijlagen', + 'edit_attachment' => 'Wijzig bijlage ":name"', + 'update_attachment' => 'Update bijlage', + 'delete_attachment' => 'Verwijder bijlage ":name"', + 'attachment_deleted' => 'Bijlage ":name" verwijderd', + 'upload_max_file_size' => 'Maximale grootte: :size', // tour: - 'prev' => 'Vorige', - 'next' => 'Volgende', - 'end-tour' => 'Einde', - 'pause' => 'Pauze', + 'prev' => 'Vorige', + 'next' => 'Volgende', + 'end-tour' => 'Einde', + 'pause' => 'Pauze', // transaction index - 'title_expenses' => 'Uitgaven', - 'title_withdrawal' => 'Uitgaven', - 'title_revenue' => 'Inkomsten', - 'title_deposit' => 'Inkomsten', - 'title_transfer' => 'Overboekingen', - 'title_transfers' => 'Overboekingen', + 'title_expenses' => 'Uitgaven', + 'title_withdrawal' => 'Uitgaven', + 'title_revenue' => 'Inkomsten', + 'title_deposit' => 'Inkomsten', + 'title_transfer' => 'Overboekingen', + 'title_transfers' => 'Overboekingen', // csv import: - 'csv_import' => 'Importeer CSV-bestand', - 'csv' => 'CSV', - 'csv_index_title' => 'Upload en importeer een kommagescheiden tekstbestand', - 'csv_define_column_roles' => 'Bepaal kolominhoud', - 'csv_map_values' => 'Leg relaties met kolomwaardes', - 'csv_download_config' => 'Download CSV configuratiebestand.', - 'csv_index_text' => 'Met deze (en de komende) pagina\'s kan je kommagescheiden tekstbestanden importeren. Deze tool is gebaseerd op de prachtige tool van Atlassian. Om te beginnen selecteer je jouw tekstbestand bij "CSV-bestand". Als je hulp nodig hebt, klik dan op het -icoontje rechtsboven.', - 'csv_index_beta_warning' => 'Deze tool is nog erg experimenteel. Wees dus voorzichtig.', - 'csv_header_help' => 'Zet hier een vinkje als de eerste rij van het CSV-bestand de namen van de kolommen bevat', - 'csv_date_help' => 'Het gebruikte datumformaat in jouw bestand. Gebruik het formaat zoals deze pagina het uitlegt (Engels). Het standaardformaat kan omgaan met data zoals deze: :dateExample.', - 'csv_csv_file_help' => 'Voer hier je kommagescheiden tekstbestand in. Je kan er maar één tegelijkertijd invoeren.', - 'csv_csv_config_file_help' => 'Voer hier je configuratiebestand in. Als je deze niet hebt, geen zorgen. Latere stappen leggen dit uit.', - 'csv_upload_button' => 'Begin de import', - 'csv_column_roles_title' => 'Bepaal de inhoud van elke kolom', - 'csv_column_roles_text' => 'Firefly kan niet automatisch ontdekken wat elke kolom betekent. Je moet het zelf aangeven. Gebruik de voorbeeldgegevens als je het ook niet zeker weet. Klik op het vraagteken-icoontje (rechtsboven) om te ontdekken wat elke kolomsoort precies is. Als de kolominhoud een directe relatie heeft met gegevens die al in Firefly staan, gebruik dan het vinkje. Tijdens de volgende stap komt Firefly hier dan op terug.', - 'csv_column_roles_table' => 'Kolominhoud', - 'csv_column' => 'CSV-kolom', - 'csv_column_name' => 'CSV-kolomnaam', - 'csv_column_example' => 'Voorbeeldgegevens', - 'csv_column_role' => 'Kolom bevat?', - 'csv_do_map_value' => 'Directe relatie?', - 'csv_continue' => 'Naar de volgende stap', - 'csv_go_back' => 'Terug naar de vorige stap', - 'csv_map_title' => 'Leg relaties met kolomwaardes', - 'csv_map_text' => 'Sommige kolommen bevatten waardes die misschien al in Firefly bestaan. Selecteer hier de juiste combinaties zodat het importeren netjes aansluit bij je huidige gegevens.', - 'csv_field_value' => 'Veldwaarde', - 'csv_field_mapped_to' => 'Is gelijk aan', - 'csv_do_not_map' => 'Geen relatie', - 'csv_download_config_title' => 'Download importconfiguratie', - 'csv_download_config_text' => 'Alles wat je nu hebt zitten instellen kan je downloaden als configuratiebestand voor de volgende keer. Klik op de knop om dit te doen.', - 'csv_more_information_text' => 'Ook als het importeren fout gaat is dit bestand handig. Na het importeren krijg je nogmaals de gelegenheid dit bestand te downloaden.', - 'csv_do_download_config' => 'Download het configuratiebestand', - 'csv_empty_description' => '(geen beschrijving)', - 'csv_upload_form' => 'CSV upload formulier', - 'csv_index_unsupported_warning' => 'Het volgende wordt nog niet ondersteund:', - 'csv_unsupported_map' => 'De tool kan de kolom ":columnRole" niet koppelen aan bestaande gegevens in de database.', - 'csv_unsupported_value' => 'Firefly kan niet omgaan met kolommen gemarkeerd als ":columnRole".', - 'csv_cannot_store_value' => 'Firefly heeft geen ruimte gereserveerd voor kolommen gemarkeert als ":columnRole" en kan ze helaas niet verwerken.', - 'csv_process_title' => 'Het importeren is klaar', - 'csv_process_text' => ':rows rijen zijn verwerkt.', - 'csv_row' => 'Rij', - 'csv_import_with_errors' => 'Er ging één ding fout.|Er gingen :errors dingen fout.', - 'csv_error_see_logs' => 'De logboeken bevatten mogelijk meer details.', - 'csv_process_new_entries' => 'Firefly heeft :imported nieuwe transactie(s) gemaakt.', - 'csv_start_over' => 'Begin opnieuw', - 'csv_to_index' => 'Naar de index', - 'csv_upload_not_writeable' => 'Kan niet naar onderstaand pad schrijven. Kan dus niet uploaden.', - 'csv_column__ignore' => '(negeer deze kolom)', - 'csv_column_account-iban' => 'Betaalrekening (IBAN)', - 'csv_column_account-id' => 'Betaalrekening (ID gelijk aan Firefly)', - 'csv_column_account-name' => 'Betaalrekeningnaam', - 'csv_column_amount' => 'Bedrag', - 'csv_column_bill-id' => 'Contract (ID gelijk aan Firefly)', - 'csv_column_bill-name' => 'Contractnaam', - 'csv_column_budget-id' => 'Budget (ID gelijk aan Firefly)', - 'csv_column_budget-name' => 'Budgetnaam', - 'csv_column_category-id' => 'Categorie (ID gelijk aan Firefly)', - 'csv_column_category-name' => 'Categorienaam', - 'csv_column_currency-code' => 'Valutacode (ISO 4217)', - 'csv_column_currency-id' => 'Valuta (ID gelijk aan Firefly)', - 'csv_column_currency-name' => 'Valutanaam', - 'csv_column_currency-symbol' => 'Valuta', - 'csv_column_date-rent' => 'Datum (renteberekening)', - 'csv_column_date-transaction' => 'Datum (transactie)', - 'csv_column_description' => 'Beschrijving', - 'csv_column_opposing-iban' => 'Tegenrekening (IBAN)', - 'csv_column_opposing-id' => 'Tegenrekening (ID gelijk aan Firefly)', - 'csv_column_opposing-name' => 'Tegenrekeningnaam', - 'csv_column_rabo-debet-credit' => 'Rabobankspecifiek bij/af indicator', - 'csv_column_sepa-ct-id' => 'SEPA transactienummer', - 'csv_column_sepa-ct-op' => 'SEPA tegenrekeningnummer', - 'csv_column_sepa-db' => 'SEPA "direct debet"-nummer', - 'csv_column_tags-comma' => 'Tags (kommagescheiden)', - 'csv_column_tags-space' => 'Tags (spatiegescheiden)', - 'csv_specifix_RabobankDescription' => 'Vink dit aan als je Rabobank bestanden importeert.', - 'csv_specifix_Dummy' => 'Dit vinkje doet niks (dummy).', - 'csv_import_account_help' => 'Als jouw CSV bestand geen referenties bevat naar jouw rekening(en), geef dan hier aan om welke rekening het gaat.', - 'csv_date_parse_error' => 'Firefly kan van ":value" geen datum maken, gegeven het formaat ":format". Weet je zeker dat je CSV goed is?', + 'csv_import' => 'Importeer CSV-bestand', + 'csv' => 'CSV', + 'csv_index_title' => 'Upload en importeer een kommagescheiden tekstbestand', + 'csv_define_column_roles' => 'Bepaal kolominhoud', + 'csv_map_values' => 'Leg relaties met kolomwaardes', + 'csv_download_config' => 'Download CSV configuratiebestand.', + 'csv_index_text' => 'Met deze (en de komende) pagina\'s kan je kommagescheiden tekstbestanden importeren. Deze tool is gebaseerd op de prachtige tool van Atlassian. Om te beginnen selecteer je jouw tekstbestand bij "CSV-bestand". Als je hulp nodig hebt, klik dan op het -icoontje rechtsboven.', + 'csv_index_beta_warning' => 'Deze tool is nog erg experimenteel. Wees dus voorzichtig.', + 'csv_header_help' => 'Zet hier een vinkje als de eerste rij van het CSV-bestand de namen van de kolommen bevat', + 'csv_date_help' => 'Het gebruikte datumformaat in jouw bestand. Gebruik het formaat zoals deze pagina het uitlegt (Engels). Het standaardformaat kan omgaan met data zoals deze: :dateExample.', + 'csv_csv_file_help' => 'Voer hier je kommagescheiden tekstbestand in. Je kan er maar één tegelijkertijd invoeren.', + 'csv_csv_config_file_help' => 'Voer hier je configuratiebestand in. Als je deze niet hebt, geen zorgen. Latere stappen leggen dit uit.', + 'csv_upload_button' => 'Begin de import', + 'csv_column_roles_title' => 'Bepaal de inhoud van elke kolom', + 'csv_column_roles_text' => 'Firefly kan niet automatisch ontdekken wat elke kolom betekent. Je moet het zelf aangeven. Gebruik de voorbeeldgegevens als je het ook niet zeker weet. Klik op het vraagteken-icoontje (rechtsboven) om te ontdekken wat elke kolomsoort precies is. Als de kolominhoud een directe relatie heeft met gegevens die al in Firefly staan, gebruik dan het vinkje. Tijdens de volgende stap komt Firefly hier dan op terug.', + 'csv_column_roles_table' => 'Kolominhoud', + 'csv_column' => 'CSV-kolom', + 'csv_column_name' => 'CSV-kolomnaam', + 'csv_column_example' => 'Voorbeeldgegevens', + 'csv_column_role' => 'Kolom bevat?', + 'csv_do_map_value' => 'Directe relatie?', + 'csv_continue' => 'Naar de volgende stap', + 'csv_go_back' => 'Terug naar de vorige stap', + 'csv_map_title' => 'Leg relaties met kolomwaardes', + 'csv_map_text' => 'Sommige kolommen bevatten waardes die misschien al in Firefly bestaan. Selecteer hier de juiste combinaties zodat het importeren netjes aansluit bij je huidige gegevens.', + 'csv_field_value' => 'Veldwaarde', + 'csv_field_mapped_to' => 'Is gelijk aan', + 'csv_do_not_map' => 'Geen relatie', + 'csv_download_config_title' => 'Download importconfiguratie', + 'csv_download_config_text' => 'Alles wat je nu hebt zitten instellen kan je downloaden als configuratiebestand voor de volgende keer. Klik op de knop om dit te doen.', + 'csv_more_information_text' => 'Ook als het importeren fout gaat is dit bestand handig. Na het importeren krijg je nogmaals de gelegenheid dit bestand te downloaden.', + 'csv_do_download_config' => 'Download het configuratiebestand', + 'csv_empty_description' => '(geen omschrijving)', + 'csv_upload_form' => 'CSV upload formulier', + 'csv_index_unsupported_warning' => 'Het volgende wordt nog niet ondersteund:', + 'csv_unsupported_map' => 'De tool kan de kolom ":columnRole" niet koppelen aan bestaande gegevens in de database.', + 'csv_unsupported_value' => 'Firefly kan niet omgaan met kolommen gemarkeerd als ":columnRole".', + 'csv_cannot_store_value' => 'Firefly heeft geen ruimte gereserveerd voor kolommen gemarkeert als ":columnRole" en kan ze helaas niet verwerken.', + 'csv_process_title' => 'Het importeren is klaar', + 'csv_process_text' => ':rows rijen zijn verwerkt.', + 'csv_row' => 'Rij', + 'csv_import_with_errors' => 'Er ging één ding fout.|Er gingen :errors dingen fout.', + 'csv_error_see_logs' => 'De logboeken bevatten mogelijk meer details.', + 'csv_process_new_entries' => 'Firefly heeft :imported nieuwe transactie(s) gemaakt.', + 'csv_start_over' => 'Begin opnieuw', + 'csv_to_index' => 'Naar de index', + 'csv_upload_not_writeable' => 'Kan niet naar onderstaand pad schrijven. Kan dus niet uploaden.', + 'csv_column__ignore' => '(negeer deze kolom)', + 'csv_column_account-iban' => 'Betaalrekening (IBAN)', + 'csv_column_account-id' => 'Betaalrekening (ID gelijk aan Firefly)', + 'csv_column_account-name' => 'Betaalrekeningnaam', + 'csv_column_amount' => 'Bedrag', + 'csv_column_amount-comma-separated' => 'Bedrag (komma as decimaalscheidingsteken)', + 'csv_column_bill-id' => 'Contract (ID gelijk aan Firefly)', + 'csv_column_bill-name' => 'Contractnaam', + 'csv_column_budget-id' => 'Budget (ID gelijk aan Firefly)', + 'csv_column_budget-name' => 'Budgetnaam', + 'csv_column_category-id' => 'Categorie (ID gelijk aan Firefly)', + 'csv_column_category-name' => 'Categorienaam', + 'csv_column_currency-code' => 'Valutacode (ISO 4217)', + 'csv_column_currency-id' => 'Valuta (ID gelijk aan Firefly)', + 'csv_column_currency-name' => 'Valutanaam', + 'csv_column_currency-symbol' => 'Valuta', + 'csv_column_date-rent' => 'Datum (renteberekening)', + 'csv_column_date-transaction' => 'Datum (transactie)', + 'csv_column_description' => 'Omschrijving', + 'csv_column_opposing-iban' => 'Tegenrekening (IBAN)', + 'csv_column_opposing-id' => 'Tegenrekening (ID gelijk aan Firefly)', + 'csv_column_opposing-name' => 'Tegenrekeningnaam', + 'csv_column_rabo-debet-credit' => 'Rabobankspecifiek bij/af indicator', + 'csv_column_sepa-ct-id' => 'SEPA transactienummer', + 'csv_column_sepa-ct-op' => 'SEPA tegenrekeningnummer', + 'csv_column_sepa-db' => 'SEPA "direct debet"-nummer', + 'csv_column_tags-comma' => 'Tags (kommagescheiden)', + 'csv_column_tags-space' => 'Tags (spatiegescheiden)', + 'csv_specifix_RabobankDescription' => 'Vink dit aan als je Rabobank CSV-bestanden importeert.', + 'csv_specifix_AbnAmroDescription' => 'Vink dit aan als je ABN AMRO CSV-bestanden importeert.', + 'csv_specifix_Dummy' => 'Dit vinkje doet niks (dummy).', + 'csv_import_account_help' => 'Als jouw CSV bestand geen referenties bevat naar jouw rekening(en), geef dan hier aan om welke rekening het gaat.', + 'csv_delimiter_help' => 'Kies het veldscheidingsteken dat in het invoerbestand is gebruikt. Bij twijfel is de komma de veiligste optie.', + 'csv_date_parse_error' => 'Firefly kan van ":value" geen datum maken, gegeven het formaat ":format". Weet je zeker dat je CSV goed is?', // create new stuff: - 'create_new_withdrawal' => 'Nieuwe uitgave', - 'create_new_deposit' => 'Nieuwe inkomsten', - 'create_new_transfer' => 'Nieuwe overschrijving', - 'create_new_asset' => 'Nieuwe betaalrekening', - 'create_new_expense' => 'Nieuwe crediteur', - 'create_new_revenue' => 'Nieuwe debiteur', - 'create_new_piggy_bank' => 'Nieuw spaarpotje', - 'create_new_bill' => 'Nieuw contract', + 'create_new_withdrawal' => 'Nieuwe uitgave', + 'create_new_deposit' => 'Nieuwe inkomsten', + 'create_new_transfer' => 'Nieuwe overschrijving', + 'create_new_asset' => 'Nieuwe betaalrekening', + 'create_new_expense' => 'Nieuwe crediteur', + 'create_new_revenue' => 'Nieuwe debiteur', + 'create_new_piggy_bank' => 'Nieuw spaarpotje', + 'create_new_bill' => 'Nieuw contract', // currencies: - 'create_currency' => 'Voeg nieuwe valuta toe', - 'edit_currency' => 'Wijzig valuta ":name"', - 'store_currency' => 'Sla nieuwe valuta op', - 'update_currency' => 'Wijzig valuta', + 'create_currency' => 'Voeg nieuwe valuta toe', + 'edit_currency' => 'Wijzig valuta ":name"', + 'store_currency' => 'Sla nieuwe valuta op', + 'update_currency' => 'Wijzig valuta', + 'new_default_currency' => ':name is nu de standaard valuta.', + 'cannot_delete_currency' => 'Kan :name niet verwijderen omdat er nog transacties van zijn!', + 'deleted_currency' => 'Valuta :name verwijderd', + 'created_currency' => 'Nieuwe valuta :name opgeslagen', + 'updated_currency' => 'Valuta :name bijgewerkt', + 'ask_site_owner' => 'Vraag :owner of deze valuta wilt toevoegen, verwijderen of wijzigen.', + 'currencies_intro' => 'Firefly III ondersteunt diverse valuta die je hier kan instellen en bewerken.', + 'make_default_currency' => 'maak standaard', + 'default_currency' => 'standaard', // new user: - 'submit' => 'Invoeren', - 'getting_started' => 'Aan de start!', - 'to_get_started' => 'Begin met de naam van de bank waar je je betaalrekening hebt, en het saldo van die rekening.', - 'savings_balance_text' => 'Voer ook het saldo van je spaarrekening in, als je die hebt.', - 'cc_balance_text' => 'Als je een credit card hebt, vul dan hier je credit cardlimiet in.', + 'submit' => 'Invoeren', + 'getting_started' => 'Aan de start!', + 'to_get_started' => 'Begin met de naam van de bank waar je je betaalrekening hebt, en het saldo van die rekening.', + 'savings_balance_text' => 'Voer ook het saldo van je spaarrekening in, als je die hebt.', + 'cc_balance_text' => 'Als je een credit card hebt, vul dan hier je credit cardlimiet in.', // forms: - 'mandatoryFields' => 'Verplichte velden', - 'optionalFields' => 'Optionele velden', - 'options' => 'Opties', - 'something' => 'Iets!', + 'mandatoryFields' => 'Verplichte velden', + 'optionalFields' => 'Optionele velden', + 'options' => 'Opties', + 'something' => 'Iets!', // budgets: - 'create_new_budget' => 'Maak een nieuw budget', - 'store_new_budget' => 'Sla nieuw budget op', - 'availableIn' => 'Beschikbaar in :date', - 'transactionsWithoutBudget' => 'Uitgaven zonder budget', - 'transactionsWithoutBudgetDate' => 'Uitgaven zonder budget in :date', - 'createBudget' => 'Maak nieuw budget', - 'inactiveBudgets' => 'Inactieve budgetten', - 'without_budget_between' => 'Transacties zonder budget tussen :start en :end', - 'budget_in_month' => ':naam in :maand', - 'delete_budget' => 'Verwijder budget ":name"', - 'edit_budget' => 'Wijzig budget ":name"', - 'update_amount' => 'Bedrag bijwerken', - 'update_budget' => 'Budget bijwerken', + 'create_new_budget' => 'Maak een nieuw budget', + 'store_new_budget' => 'Sla nieuw budget op', + 'availableIn' => 'Beschikbaar in :date', + 'transactionsWithoutBudget' => 'Uitgaven zonder budget', + 'transactionsWithoutBudgetDate' => 'Uitgaven zonder budget in :date', + 'createBudget' => 'Maak nieuw budget', + 'inactiveBudgets' => 'Inactieve budgetten', + 'without_budget_between' => 'Transacties zonder budget tussen :start en :end', + 'budget_in_month' => ':name in :month', + 'delete_budget' => 'Verwijder budget ":name"', + 'edit_budget' => 'Wijzig budget ":name"', + 'update_amount' => 'Bedrag bijwerken', + 'update_budget' => 'Budget bijwerken', // bills: - 'delete_bill' => 'Verwijder contract ":name"', - 'edit_bill' => 'Wijzig contract ":name"', - 'update_bill' => 'Wijzig contract', - 'store_new_bill' => 'Sla nieuw contract op', + 'delete_bill' => 'Verwijder contract ":name"', + 'edit_bill' => 'Wijzig contract ":name"', + 'update_bill' => 'Wijzig contract', + 'store_new_bill' => 'Sla nieuw contract op', // accounts: - 'details_for_asset' => 'Overzicht voor betaalrekening ":name"', - 'details_for_expense' => 'Overzicht voor crediteur ":name"', - 'details_for_revenue' => 'Overzicht voor debiteur ":name"', - 'details_for_cash' => 'Overzicht voor contant geldrekening ":name"', - 'store_new_asset_account' => 'Sla nieuwe betaalrekening op', - 'store_new_expense_account' => 'Sla nieuwe crediteur op', - 'store_new_revenue_account' => 'Sla nieuwe debiteur op', - 'edit_asset_account' => 'Wijzig betaalrekening ":name"', - 'edit_expense_account' => 'Wijzig crediteur ":name"', - 'edit_revenue_account' => 'Wijzig debiteur ":name"', - 'delete_asset_account' => 'Verwijder betaalrekening ":name"', - 'delete_expense_account' => 'Verwijder crediteur ":name"', - 'delete_revenue_account' => 'Verwijder debiteur ":name"', - 'asset_deleted' => 'Betaalrekening ":name" is verwijderd.', - 'expense_deleted' => 'Crediteur ":name" is verwijderd.', - 'revenue_deleted' => 'Debiteur ":name" is verwijderd.', - 'update_asset_account' => 'Wijzig betaalrekening', - 'update_expense_account' => 'Wijzig crediteur', - 'update_revenue_account' => 'Wijzig debiteur', - 'make_new_asset_account' => 'Nieuwe betaalrekening', - 'make_new_expense_account' => 'Nieuwe crediteur', - 'make_new_revenue_account' => 'Nieuwe debiteur', - 'asset_accounts' => 'Betaalrekeningen', - 'expense_accounts' => 'Crediteuren', - 'revenue_accounts' => 'Debiteuren', - 'accountExtraHelp_asset' => '', - 'accountExtraHelp_expense' => '', - 'accountExtraHelp_revenue' => '', - 'account_type' => 'Rekeningtype', - 'save_transactions_by_moving' => 'Bewaar deze transacties door ze aan een andere rekening te koppelen:', + 'details_for_asset' => 'Overzicht voor betaalrekening ":name"', + 'details_for_expense' => 'Overzicht voor crediteur ":name"', + 'details_for_revenue' => 'Overzicht voor debiteur ":name"', + 'details_for_cash' => 'Overzicht voor contant geldrekening ":name"', + 'store_new_asset_account' => 'Sla nieuwe betaalrekening op', + 'store_new_expense_account' => 'Sla nieuwe crediteur op', + 'store_new_revenue_account' => 'Sla nieuwe debiteur op', + 'edit_asset_account' => 'Wijzig betaalrekening ":name"', + 'edit_expense_account' => 'Wijzig crediteur ":name"', + 'edit_revenue_account' => 'Wijzig debiteur ":name"', + 'delete_asset_account' => 'Verwijder betaalrekening ":name"', + 'delete_expense_account' => 'Verwijder crediteur ":name"', + 'delete_revenue_account' => 'Verwijder debiteur ":name"', + 'asset_deleted' => 'Betaalrekening ":name" is verwijderd.', + 'expense_deleted' => 'Crediteur ":name" is verwijderd.', + 'revenue_deleted' => 'Debiteur ":name" is verwijderd.', + 'update_asset_account' => 'Wijzig betaalrekening', + 'update_expense_account' => 'Wijzig crediteur', + 'update_revenue_account' => 'Wijzig debiteur', + 'make_new_asset_account' => 'Nieuwe betaalrekening', + 'make_new_expense_account' => 'Nieuwe crediteur', + 'make_new_revenue_account' => 'Nieuwe debiteur', + 'asset_accounts' => 'Betaalrekeningen', + 'expense_accounts' => 'Crediteuren', + 'revenue_accounts' => 'Debiteuren', + 'accountExtraHelp_asset' => '', + 'accountExtraHelp_expense' => '', + 'accountExtraHelp_revenue' => '', + 'account_type' => 'Rekeningtype', + 'save_transactions_by_moving' => 'Bewaar deze transacties door ze aan een andere rekening te koppelen:', // categories: - 'new_category' => 'Nieuwe categorie', - 'create_new_category' => 'Nieuwe categorie', - 'without_category' => 'Zonder categorie', - 'update_category' => 'Wijzig categorie', - 'categories' => 'Categorieën', - 'edit_category' => 'Wijzig categorie ":name"', - 'no_category' => '(geen categorie)', - 'category' => 'Categorie', - 'delete_category' => 'Verwijder categorie ":name"', - 'store_category' => 'Sla nieuwe categorie op', + 'new_category' => 'Nieuwe categorie', + 'create_new_category' => 'Nieuwe categorie', + 'without_category' => 'Zonder categorie', + 'update_category' => 'Wijzig categorie', + 'categories' => 'Categorieën', + 'edit_category' => 'Wijzig categorie ":name"', + 'no_category' => '(geen categorie)', + 'category' => 'Categorie', + 'delete_category' => 'Verwijder categorie ":name"', + 'store_category' => 'Sla nieuwe categorie op', + 'without_category_between' => 'Zonder categorie tussen :start en :end', // transactions: - 'update_withdrawal' => 'Wijzig uitgave', - 'update_deposit' => 'Wijzig inkomsten', - 'update_transfer' => 'Wijzig overschrijving', - 'delete_withdrawal' => 'Verwijder uitgave ":description"', - 'delete_deposit' => 'Verwijder inkomsten ":description"', - 'delete_transfer' => 'Verwijder overschrijving ":description"', + 'update_withdrawal' => 'Wijzig uitgave', + 'update_deposit' => 'Wijzig inkomsten', + 'update_transfer' => 'Wijzig overschrijving', + 'delete_withdrawal' => 'Verwijder uitgave ":description"', + 'delete_deposit' => 'Verwijder inkomsten ":description"', + 'delete_transfer' => 'Verwijder overschrijving ":description"', // new user: - 'welcome' => 'Welkom bij Firefly!', - 'createNewAsset' => 'Maak om te beginnen een nieuwe betaalrekening .' . - 'Hiermee kan je nieuwe transacties opslaan en beginnen met het beheren van je geld', - 'createNewAssetButton' => 'Maak een nieuwe betaalrekening', + 'welcome' => 'Welkom bij Firefly!', + 'createNewAsset' => 'Maak om te beginnen een nieuwe betaalrekening .' . + 'Hiermee kan je nieuwe transacties opslaan en beginnen met het beheren van je geld', + 'createNewAssetButton' => 'Maak een nieuwe betaalrekening', // home page: - 'yourAccounts' => 'Je betaalrekeningen', - 'budgetsAndSpending' => 'Budgetten en uitgaven', - 'savings' => 'Sparen', - 'markAsSavingsToContinue' => 'Om hier wat te zien stel je je betaalrekeningen in als "spaarrekening".', - 'createPiggyToContinue' => 'Maak spaarpotjes om hier iets te zien.', - 'newWithdrawal' => 'Nieuwe uitgave', - 'newDeposit' => 'Nieuwe inkomsten', - 'newTransfer' => 'Nieuwe overschrijving', - 'moneyIn' => 'Inkomsten', - 'moneyOut' => 'Uitgaven', - 'billsToPay' => 'Openstaande contracten', - 'billsPaid' => 'Betaalde contracten', - 'viewDetails' => 'Meer info', - 'divided' => 'verdeeld', - 'toDivide' => 'te verdelen', + 'yourAccounts' => 'Je betaalrekeningen', + 'budgetsAndSpending' => 'Budgetten en uitgaven', + 'savings' => 'Sparen', + 'markAsSavingsToContinue' => 'Om hier wat te zien stel je je betaalrekeningen in als "spaarrekening".', + 'createPiggyToContinue' => 'Maak spaarpotjes om hier iets te zien.', + 'newWithdrawal' => 'Nieuwe uitgave', + 'newDeposit' => 'Nieuwe inkomsten', + 'newTransfer' => 'Nieuwe overschrijving', + 'moneyIn' => 'Inkomsten', + 'moneyOut' => 'Uitgaven', + 'billsToPay' => 'Openstaande contracten', + 'billsPaid' => 'Betaalde contracten', + 'viewDetails' => 'Meer info', + 'divided' => 'verdeeld', + 'toDivide' => 'te verdelen', // menu and titles, should be recycled as often as possible: - 'toggleNavigation' => 'Navigatie aan of uit', - 'currency' => 'Valuta', - 'preferences' => 'Voorkeuren', - 'logout' => 'Uitloggen', - 'searchPlaceholder' => 'Zoeken...', - 'dashboard' => 'Dashboard', - 'currencies' => 'Valuta', - 'accounts' => 'Rekeningen', - 'Asset account' => 'Betaalrekening', - 'Default account' => 'Betaalrekening', - 'Expense account' => 'Crediteur', - 'Revenue account' => 'Debiteur', - 'Initial balance account' => 'Startbalansrekening', - 'budgets' => 'Budgetten', - 'tags' => 'Tags', - 'reports' => 'Overzichten', - 'transactions' => 'Transacties', - 'expenses' => 'Uitgaven', - 'income' => 'Inkomsten', - 'transfers' => 'Overschrijvingen', - 'moneyManagement' => 'Geldbeheer', - 'piggyBanks' => 'Spaarpotjes', - 'bills' => 'Contracten', - 'createNew' => 'Nieuw', - 'withdrawal' => 'Uitgave', - 'deposit' => 'Inkomsten', - 'account' => 'Rekening', - 'transfer' => 'Overschrijving', - 'Withdrawal' => 'Uitgave', - 'Deposit' => 'Inkomsten', - 'Transfer' => 'Overschrijving', - 'bill' => 'Contract', - 'yes' => 'Ja', - 'no' => 'Nee', - 'amount' => 'Bedrag', - 'newBalance' => 'Nieuw saldo', - 'overview' => 'Overzicht', - 'saveOnAccount' => 'Sparen op rekening', - 'unknown' => 'Onbekend', - 'daily' => 'Dagelijks', - 'weekly' => 'Wekelijks', - 'monthly' => 'Maandelijks', - 'quarterly' => 'Elk kwartaal', - 'half-year' => 'Elk half jaar', - 'yearly' => 'Jaarlijks', - 'profile' => 'Profiel', + 'toggleNavigation' => 'Navigatie aan of uit', + 'currency' => 'Valuta', + 'preferences' => 'Voorkeuren', + 'logout' => 'Uitloggen', + 'searchPlaceholder' => 'Zoeken...', + 'dashboard' => 'Dashboard', + 'currencies' => 'Valuta', + 'accounts' => 'Rekeningen', + 'Asset account' => 'Betaalrekening', + 'Default account' => 'Betaalrekening', + 'Expense account' => 'Crediteur', + 'Revenue account' => 'Debiteur', + 'Initial balance account' => 'Startbalansrekening', + 'budgets' => 'Budgetten', + 'tags' => 'Tags', + 'reports' => 'Overzichten', + 'transactions' => 'Transacties', + 'expenses' => 'Uitgaven', + 'income' => 'Inkomsten', + 'transfers' => 'Overschrijvingen', + 'moneyManagement' => 'Geldbeheer', + 'piggyBanks' => 'Spaarpotjes', + 'bills' => 'Contracten', + 'createNew' => 'Nieuw', + 'withdrawal' => 'Uitgave', + 'deposit' => 'Inkomsten', + 'account' => 'Rekening', + 'transfer' => 'Overschrijving', + 'Withdrawal' => 'Uitgave', + 'Deposit' => 'Inkomsten', + 'Transfer' => 'Overschrijving', + 'bill' => 'Contract', + 'yes' => 'Ja', + 'no' => 'Nee', + 'amount' => 'Bedrag', + 'newBalance' => 'Nieuw saldo', + 'overview' => 'Overzicht', + 'saveOnAccount' => 'Sparen op rekening', + 'unknown' => 'Onbekend', + 'daily' => 'Dagelijks', + 'weekly' => 'Wekelijks', + 'monthly' => 'Maandelijks', + 'quarterly' => 'Elk kwartaal', + 'half-year' => 'Elk half jaar', + 'yearly' => 'Jaarlijks', + 'profile' => 'Profiel', // reports: - 'report_default' => 'Standaard financieel rapport (:start tot :end)', - 'quick_link_reports' => 'Snelle links', - 'quick_link_default_report' => 'Standaard financieel rapport', - 'report_this_month_quick' => 'Deze maand, alle rekeningen', - 'report_this_year_quick' => 'Dit jaar, alle rekeningen', - 'report_all_time_quick' => 'Gehele periode, alle rekeningen', - 'reports_can_bookmark' => 'Je kan rapporten aan je favorieten toevoegen.', - 'incomeVsExpenses' => 'Inkomsten tegenover uitgaven', - 'accountBalances' => 'Rekeningsaldi', - 'balanceStartOfYear' => 'Saldo aan het begin van het jaar', - 'balanceEndOfYear' => 'Saldo aan het einde van het jaar', - 'balanceStartOfMonth' => 'Saldo aan het begin van de maand', - 'balanceEndOfMonth' => 'Saldo aan het einde van de maand', - 'balanceStart' => 'Saldo aan het begin van de periode', - 'balanceEnd' => 'Saldo aan het einde van de periode', - 'reportsOwnAccounts' => 'Overzichten voor je eigen betaalrekeningen', - 'reportsOwnAccountsAndShared' => 'Overzichten voor je eigen betaalrekeningen en gedeelde rekeningen', - 'splitByAccount' => 'Per betaalrekening', - 'balancedByTransfersAndTags' => 'Gecorrigeerd met overschrijvingen en tags', - 'coveredWithTags' => 'Gecorrigeerd met tags', - 'leftUnbalanced' => 'Ongecorrigeerd', - 'expectedBalance' => 'Verwacht saldo', - 'outsideOfBudgets' => 'Buiten budgetten', - 'leftInBudget' => 'Over van budget', - 'sumOfSums' => 'Alles bij elkaar', - 'noCategory' => '(zonder categorie)', - 'notCharged' => '(Nog) niet betaald', - 'inactive' => 'Niet actief', - 'difference' => 'Verschil', - 'in' => 'In', - 'out' => 'Uit', - 'topX' => 'top :number', - 'showTheRest' => 'Laat alles zien', - 'hideTheRest' => 'Laat alleen de top :number zien', - 'sum_of_year' => 'Som van jaar', - 'sum_of_years' => 'Som van jaren', - 'average_of_year' => 'Gemiddelde in jaar', - 'average_of_years' => 'Gemiddelde in jaren', - 'categories_earned_in_year' => 'Categorieën (inkomsten)', - 'categories_spent_in_year' => 'Categorieën (uitgaven)', - 'report_type' => 'Rapporttype', - 'report_type_default' => 'Standard financieel rapport', - 'report_included_accounts' => 'Accounts in rapport', - 'report_date_range' => 'Datumbereik', - 'report_include_help' => 'Overboekingen naar gedeelde rekeningen tellen als uitgave. Overboekingen van gedeelde rekeningen tellen als inkomsten.', - 'report_preset_ranges' => 'Standaardbereik', - 'shared' => 'Gedeeld', + 'report_default' => 'Standaard financieel rapport (:start tot :end)', + 'quick_link_reports' => 'Snelle links', + 'quick_link_default_report' => 'Standaard financieel rapport', + 'report_this_month_quick' => 'Deze maand, alle rekeningen', + 'report_this_year_quick' => 'Dit jaar, alle rekeningen', + 'report_all_time_quick' => 'Gehele periode, alle rekeningen', + 'reports_can_bookmark' => 'Je kan rapporten aan je favorieten toevoegen.', + 'incomeVsExpenses' => 'Inkomsten tegenover uitgaven', + 'accountBalances' => 'Rekeningsaldi', + 'balanceStartOfYear' => 'Saldo aan het begin van het jaar', + 'balanceEndOfYear' => 'Saldo aan het einde van het jaar', + 'balanceStartOfMonth' => 'Saldo aan het begin van de maand', + 'balanceEndOfMonth' => 'Saldo aan het einde van de maand', + 'balanceStart' => 'Saldo aan het begin van de periode', + 'balanceEnd' => 'Saldo aan het einde van de periode', + 'reportsOwnAccounts' => 'Overzichten voor je eigen betaalrekeningen', + 'reportsOwnAccountsAndShared' => 'Overzichten voor je eigen betaalrekeningen en gedeelde rekeningen', + 'splitByAccount' => 'Per betaalrekening', + 'balancedByTransfersAndTags' => 'Gecorrigeerd met overschrijvingen en tags', + 'coveredWithTags' => 'Gecorrigeerd met tags', + 'leftUnbalanced' => 'Ongecorrigeerd', + 'expectedBalance' => 'Verwacht saldo', + 'outsideOfBudgets' => 'Buiten budgetten', + 'leftInBudget' => 'Over van budget', + 'sumOfSums' => 'Alles bij elkaar', + 'noCategory' => '(zonder categorie)', + 'notCharged' => '(Nog) niet betaald', + 'inactive' => 'Niet actief', + 'difference' => 'Verschil', + 'in' => 'In', + 'out' => 'Uit', + 'topX' => 'top :number', + 'showTheRest' => 'Laat alles zien', + 'hideTheRest' => 'Laat alleen de top :number zien', + 'sum_of_year' => 'Som van jaar', + 'sum_of_years' => 'Som van jaren', + 'average_of_year' => 'Gemiddelde in jaar', + 'average_of_years' => 'Gemiddelde in jaren', + 'categories_earned_in_year' => 'Categorieën (inkomsten)', + 'categories_spent_in_year' => 'Categorieën (uitgaven)', + 'report_type' => 'Rapporttype', + 'report_type_default' => 'Standard financieel rapport', + 'report_included_accounts' => 'Accounts in rapport', + 'report_date_range' => 'Datumbereik', + 'report_include_help' => 'Overboekingen naar gedeelde rekeningen tellen als uitgave. Overboekingen van gedeelde rekeningen tellen als inkomsten.', + 'report_preset_ranges' => 'Standaardbereik', + 'shared' => 'Gedeeld', // charts: - 'dayOfMonth' => 'Dag vd maand', - 'month' => 'Maand', - 'budget' => 'Budget', - 'spent' => 'Uitgegeven', - 'earned' => 'Verdiend', - 'overspent' => 'Teveel uitgegeven', - 'left' => 'Over', - 'noBudget' => '(geen budget)', - 'maxAmount' => 'Maximaal bedrag', - 'minAmount' => 'Minimaal bedrag', - 'billEntry' => 'Bedrag voor dit contract', - 'name' => 'Naam', - 'date' => 'Datum', - 'paid' => 'Betaald', - 'unpaid' => 'Niet betaald', - 'day' => 'Dag', - 'budgeted' => 'Gebudgetteerd', - 'period' => 'Periode', - 'balance' => 'Saldo', - 'summary' => 'Samenvatting', - 'sum' => 'Som', - 'average' => 'Gemiddeld', - 'balanceFor' => 'Saldo op :name', + 'dayOfMonth' => 'Dag vd maand', + 'month' => 'Maand', + 'budget' => 'Budget', + 'spent' => 'Uitgegeven', + 'earned' => 'Verdiend', + 'overspent' => 'Teveel uitgegeven', + 'left' => 'Over', + 'noBudget' => '(geen budget)', + 'maxAmount' => 'Maximaal bedrag', + 'minAmount' => 'Minimaal bedrag', + 'billEntry' => 'Bedrag voor dit contract', + 'name' => 'Naam', + 'date' => 'Datum', + 'paid' => 'Betaald', + 'unpaid' => 'Niet betaald', + 'day' => 'Dag', + 'budgeted' => 'Gebudgetteerd', + 'period' => 'Periode', + 'balance' => 'Saldo', + 'summary' => 'Samenvatting', + 'sum' => 'Som', + 'average' => 'Gemiddeld', + 'balanceFor' => 'Saldo op :name', // piggy banks: - 'piggy_bank' => 'Spaarpotje', - 'new_piggy_bank' => 'Nieuw spaarpotje', - 'store_piggy_bank' => 'Sla spaarpotje op', - 'account_status' => 'Rekeningoverzicht', - 'left_for_piggy_banks' => 'Over voor spaarpotjes', - 'sum_of_piggy_banks' => 'Som van spaarpotjes', - 'saved_so_far' => 'Gespaard', - 'left_to_save' => 'Te sparen', - 'add_money_to_piggy_title' => 'Stop geld in spaarpotje ":name"', - 'remove_money_from_piggy_title' => 'Haal geld uit spaarpotje ":name"', - 'add' => 'Toevoegen', - 'remove' => 'Verwijderen', - 'max_amount_add' => 'Hooguit toe te voegen', - 'max_amount_remove' => 'Hooguit te verwijderen', - 'update_piggy_button' => 'Wijzig spaarpotje', - 'update_piggy_title' => 'Wijzig spaarpotje ":name"', - 'details' => 'Details', - 'events' => 'Gebeurtenissen', - 'target_amount' => 'Doelbedrag', - 'start_date' => 'Startdatum', - 'target_date' => 'Doeldatum', - 'no_target_date' => 'Geen doeldatum', - 'todo' => 'te doen', - 'table' => 'Tabel', - 'piggy_bank_not_exists' => 'Dit spaarpotje bestaat niet meer.', - 'add_any_amount_to_piggy' => 'Stop geld in dit spaarpotje om het doel van :amount te halen.', - 'add_set_amount_to_piggy' => 'Stop voor :date :amount in dit spaarpotje om hem op tijd te vullen.', - 'delete_piggy_bank' => 'Verwijder spaarpotje ":name"', + 'piggy_bank' => 'Spaarpotje', + 'new_piggy_bank' => 'Nieuw spaarpotje', + 'store_piggy_bank' => 'Sla spaarpotje op', + 'account_status' => 'Rekeningoverzicht', + 'left_for_piggy_banks' => 'Over voor spaarpotjes', + 'sum_of_piggy_banks' => 'Som van spaarpotjes', + 'saved_so_far' => 'Gespaard', + 'left_to_save' => 'Te sparen', + 'add_money_to_piggy_title' => 'Stop geld in spaarpotje ":name"', + 'remove_money_from_piggy_title' => 'Haal geld uit spaarpotje ":name"', + 'add' => 'Toevoegen', + 'remove' => 'Verwijderen', + 'max_amount_add' => 'Hooguit toe te voegen', + 'max_amount_remove' => 'Hooguit te verwijderen', + 'update_piggy_button' => 'Wijzig spaarpotje', + 'update_piggy_title' => 'Wijzig spaarpotje ":name"', + 'details' => 'Details', + 'events' => 'Gebeurtenissen', + 'target_amount' => 'Doelbedrag', + 'start_date' => 'Startdatum', + 'target_date' => 'Doeldatum', + 'no_target_date' => 'Geen doeldatum', + 'todo' => 'te doen', + 'table' => 'Tabel', + 'piggy_bank_not_exists' => 'Dit spaarpotje bestaat niet meer.', + 'add_any_amount_to_piggy' => 'Stop geld in dit spaarpotje om het doel van :amount te halen.', + 'add_set_amount_to_piggy' => 'Stop voor :date :amount in dit spaarpotje om hem op tijd te vullen.', + 'delete_piggy_bank' => 'Verwijder spaarpotje ":name"', // tags - 'regular_tag' => 'Een gewone tag.', - 'balancing_act' => 'Er kunnen maar twee transacties worden getagged; een uitgaven en inkomsten. Ze balanceren elkaar.', - 'advance_payment' => 'Je kan een uitgave taggen en zoveel inkomsten om de uitgave (helemaal) te compenseren.', - 'delete_tag' => 'Verwijder tag ":tag"', - 'new_tag' => 'Maak nieuwe tag', - 'edit_tag' => 'Wijzig tag ":tag"', - 'no_year' => 'Zonder jaar', - 'no_month' => 'Zonder maand', - 'tag_title_nothing' => 'Standaard tags', - 'tag_title_balancingAct' => 'Balancerende tags', - 'tag_title_advancePayment' => 'Vooruitbetaalde tags', - 'tags_introduction' => 'Normaal gesproken zijn tags enkele woorden, gebruikt om gerelateerde zaken snel aan elkaar te plakken. dure-aanschaf, rekening, feestje. In Firefly III hebben tags meer betekenis en kan je er een datum, beschrijving en locatie aan geven. Daarmee kan je je transacties op een wat zinvollere manier aan elkaar koppelen. Je kan bijvoorbeeld een tag Kerstdiner maken en informatie over het restaurant meenemen. Zulke tags zijn enkelvoudig; je gebruikt ze maar bij één gelegenheid.', - 'tags_group' => 'Omdat tags transacties groeperen kan je er teruggaves, vergoedingen en andere geldzaken mee aanduiden, zolang de transacties elkaar "opheffen". Hoe je dit aanpakt is aan jou. De gewone manier kan natuurlijk ook.', - 'tags_start' => 'Maak hieronder een tag, of voer nieuwe tags in als je nieuwe transacties maakt.', + 'regular_tag' => 'Een gewone tag.', + 'balancing_act' => 'Er kunnen maar twee transacties worden getagged; een uitgaven en inkomsten. Ze balanceren elkaar.', + 'advance_payment' => 'Je kan een uitgave taggen en zoveel inkomsten om de uitgave (helemaal) te compenseren.', + 'delete_tag' => 'Verwijder tag ":tag"', + 'new_tag' => 'Maak nieuwe tag', + 'edit_tag' => 'Wijzig tag ":tag"', + 'no_year' => 'Zonder jaar', + 'no_month' => 'Zonder maand', + 'tag_title_nothing' => 'Standaard tags', + 'tag_title_balancingAct' => 'Balancerende tags', + 'tag_title_advancePayment' => 'Vooruitbetaalde tags', + 'tags_introduction' => 'Normaal gesproken zijn tags enkele woorden, gebruikt om gerelateerde zaken snel aan elkaar te plakken. dure-aanschaf, rekening, feestje. In Firefly III hebben tags meer betekenis en kan je er een datum, omschrijving en locatie aan geven. Daarmee kan je je transacties op een wat zinvollere manier aan elkaar koppelen. Je kan bijvoorbeeld een tag Kerstdiner maken en informatie over het restaurant meenemen. Zulke tags zijn enkelvoudig; je gebruikt ze maar bij één gelegenheid.', + 'tags_group' => 'Omdat tags transacties groeperen kan je er teruggaves, vergoedingen en andere geldzaken mee aanduiden, zolang de transacties elkaar "opheffen". Hoe je dit aanpakt is aan jou. De gewone manier kan natuurlijk ook.', + 'tags_start' => 'Maak hieronder een tag, of voer nieuwe tags in als je nieuwe transacties maakt.', ]; diff --git a/resources/lang/nl_NL/form.php b/resources/lang/nl_NL/form.php old mode 100644 new mode 100755 index 5bfb9a1a11..cce6489790 --- a/resources/lang/nl_NL/form.php +++ b/resources/lang/nl_NL/form.php @@ -53,6 +53,7 @@ return [ 'csv_config' => 'Configuratiebestand', 'specifix' => 'Bank- or of bestandsspecifieke opties', 'csv_import_account' => 'Standaard rekening voor importeren', + 'csv_delimiter' => 'CSV scheidingsteken', 'attachments[]' => 'Bijlagen', 'store_new_withdrawal' => 'Nieuwe uitgave opslaan', 'store_new_deposit' => 'Nieuwe inkomsten opslaan', @@ -67,6 +68,12 @@ return [ 'filename' => 'Bestandsnaam', 'mime' => 'Bestandstype', 'size' => 'Grootte', + 'trigger' => 'Trigger', + 'stop_processing' => 'Stop met verwerken', + + 'csv_comma' => 'Een komma (,)', + 'csv_semicolon' => 'Een puntkomma (;)', + 'csv_tab' => 'Een tab (onzichtbaar)', 'delete_account' => 'Verwijder rekening ":name"', @@ -76,10 +83,14 @@ return [ 'delete_currency' => 'Verwijder valuta ":name"', 'delete_journal' => 'Verwijder transactie met omschrijving ":description"', 'delete_attachment' => 'Verwijder bijlage ":name"', + 'delete_rule' => 'Verwijder regel ":title"', + 'delete_rule_group' => 'Verwijder regelgroep ":title"', 'attachment_areYouSure' => 'Weet je zeker dat je de bijlage met naam ":name" wilt verwijderen?', 'account_areYouSure' => 'Weet je zeker dat je de rekening met naam ":name" wilt verwijderen?', 'bill_areYouSure' => 'Weet je zeker dat je het contract met naam ":name" wilt verwijderen?', + 'rule_areYouSure' => 'Weet je zeker dat je regel ":title" wilt verwijderen?', + 'ruleGroup_areYouSure' => 'Weet je zeker dat je regelgroep ":title" wilt verwijderen?', 'budget_areYouSure' => 'Weet je zeker dat je het budget met naam ":name" wilt verwijderen?', 'category_areYouSure' => 'Weet je zeker dat je het category met naam ":name" wilt verwijderen?', 'currency_areYouSure' => 'Weet je zeker dat je de valuta met naam ":name" wilt verwijderen?', @@ -89,6 +100,7 @@ return [ 'permDeleteWarning' => 'Dingen verwijderen uit Firefly is permanent en kan niet ongedaan gemaakt worden.', 'also_delete_transactions' => 'Ook de enige transactie verbonden aan deze rekening wordt verwijderd.|Ook alle :count transacties verbonden aan deze rekening worden verwijderd.', + 'also_delete_rules' => 'De enige regel in deze regelgroep wordt ook verwijderd.|Alle :count regels in deze regelgroep worden ook verwijderd.', 'also_delete_piggyBanks' => 'Ook het spaarpotje verbonden aan deze rekening wordt verwijderd.|Ook alle :count spaarpotjes verbonden aan deze rekening worden verwijderd.', 'bill_keep_transactions' => 'De transactie verbonden aan dit contract blijft bewaard.|De :count transacties verbonden aan dit contract blijven bewaard.', 'budget_keep_transactions' => 'De transactie verbonden aan dit budget blijft bewaard.|De :count transacties verbonden aan dit budget blijven bewaard.', diff --git a/resources/lang/nl_NL/help.php b/resources/lang/nl_NL/help.php old mode 100644 new mode 100755 index 7282a1259f..815b05bfc9 --- a/resources/lang/nl_NL/help.php +++ b/resources/lang/nl_NL/help.php @@ -20,74 +20,65 @@ return [ 'main-content-end-text' => 'Elke pagina heeft een vraagtekentje rechtsboven. Gebruik deze voor meer hulp. Veel plezier!', - 'register' => 'register', - 'index' => 'index', - 'home' => 'home', - 'flush' => 'flush', - 'accounts-index' => 'accounts.index', - 'accounts-create' => 'accounts.create', - 'accounts-edit' => 'accounts.edit', - 'accounts-delete' => 'accounts.delete', - 'accounts-show' => 'accounts.show', - 'bills-index' => 'bills.index', - 'bills-rescan' => 'bills.rescan', - 'bills-create' => 'bills.create', - 'bills-edit' => 'bills.edit', - 'bills-delete' => 'bills.delete', - 'bills-show' => 'bills.show', - 'budgets-index' => 'budgets.index', - 'budgets-income' => 'budgets.income', - 'budgets-create' => 'budgets.create', - 'budgets-edit' => 'budgets.edit', - 'budgets-delete' => 'budgets.delete', - 'budgets-show' => 'budgets.show', - 'budgets-noBudget' => 'budgets.noBudget', - 'categories-index' => 'categories.index', - 'categories-create' => 'categories.create', - 'categories-edit' => 'categories.edit', - 'categories-delete' => 'categories.delete', - 'categories-show' => 'categories.show', - 'categories-noCategory' => 'categories.noCategory', - 'csv-index' => 'csv-index', - 'currency-index' => 'currency.index', - 'currency-create' => 'currency.create', - 'currency-edit' => 'currency.edit', - 'currency-delete' => 'currency.delete', - 'currency-default' => 'currency.default', - 'help-show' => 'help.show', - 'json-expense-accounts' => 'json.expense-accounts', - 'json-revenue-accounts' => 'json.revenue-accounts', - 'json-categories' => 'json.categories', - 'json-tags' => 'json.tags', - 'json-box-in' => 'json.box.in', - 'json-box-out' => 'json.box.out', - 'json-box-paid' => 'json.box.paid', - 'json-box-unpaid' => 'json.box.unpaid', - 'new-user-index' => 'new-user.index', - 'piggy-banks-index' => 'piggy-banks.index', - 'piggy-banks-addMoney' => 'piggy-banks.addMoney', - 'piggy-banks-removeMoney' => 'piggy-banks.removeMoney', - 'piggy-banks-create' => 'piggy-banks.create', - 'piggy-banks-edit' => 'piggy-banks.edit', - 'piggy-banks-delete' => 'piggy-banks.delete', - 'piggy-banks-show' => 'piggy-banks.show', - 'preferences' => 'preferences', - 'profile' => 'profile', - 'profile-change-password' => 'profile.change-password', - 'profile-delete-account' => 'profile.delete-account', - 'reports-index' => 'reports.index', - 'reports-year' => 'reports.year', - 'reports-month' => 'reports.month', - 'search' => 'search', - 'tags-index' => 'tags.index', - 'tags-create' => 'tags.create', - 'tags-show' => 'tags.show', - 'tags-edit' => 'tags.edit', - 'tags-delete' => 'tags.delete', - 'transactions-index' => 'transactions.index', - 'transactions-create' => 'transactions.create', - 'transactions-edit' => 'transactions.edit', - 'transactions-delete' => 'transactions.delete', - 'transactions-show' => 'transactions.show', - 'logout' => 'logout', + 'index' => 'index', + 'home' => 'home', + 'accounts-index' => 'rekeningen', + 'accounts-create' => 'maak nieuwe rekening', + 'accounts-edit' => 'rekening wijzigen', + 'accounts-delete' => 'rekening verwijderen', + 'accounts-show' => 'rekening bekijken', + 'attachments-edit' => 'wijzig bijlage', + 'attachments-delete' => 'verwijder bijlage', + 'attachments-show' => 'bekijk bijlage', + 'attachments-preview' => 'bekijik bijlage', + 'bills-index' => 'contracten', + 'bills-create' => 'maak contract', + 'bills-edit' => 'wijzig contract', + 'bills-delete' => 'verwijder contract', + 'bills-show' => 'bekijk contract', + 'budgets-index' => 'budgetten', + 'budgets-create' => 'maak een nieuw budget', + 'budgets-edit' => 'wijzig een budget', + 'budgets-delete' => 'verwijder een budget', + 'budgets-show' => 'bekijk een budget', + 'budgets-noBudget' => 'transacties zonder budget', + 'categories-index' => 'categorieën', + 'categories-create' => 'maak nieuwe categorie', + 'categories-edit' => 'wijzig een categorie', + 'categories-delete' => 'verwijder een categorie', + 'categories-show' => 'bekijk een categorie', + 'categories-show-date' => 'bekijk categorie', + 'categories-noCategory' => 'transacties zonder categorie', + 'csv-index' => 'csv-index', + 'csv-column-roles' => 'kolommen en rollen', + 'csv-map' => 'kolommen en data', + 'csv-download-config-page' => 'download configuratie', + 'csv-process' => 'CSV verwerken', + 'currency-index' => 'valuta\'s', + 'currency-create' => 'maak een nieuwe munteenheid', + 'currency-edit' => 'wijzig een munteenheid', + 'currency-delete' => 'verwijder een munteenheid', + 'new-user-index' => 'nieuwe gebruiker', + 'piggy-banks-index' => 'spaarpotjes', + 'piggy-banks-create' => 'maak nieuw spaarpotje', + 'piggy-banks-edit' => 'wijzig spaarpotje', + 'piggy-banks-delete' => 'verwijder spaarpotje', + 'piggy-banks-show' => 'bekijk spaarportje', + 'preferences' => 'voorkeuren', + 'profile' => 'profiel', + 'profile-change-password' => 'verander je wachtwoord', + 'profile-delete-account' => 'verwijder je account', + 'reports-index' => 'rapporten', + 'reports-report' => 'rapport', + 'search' => 'zoeken', + 'tags-index' => 'tags', + 'tags-create' => 'maak nieuwe tag', + 'tags-show' => 'bekijk tag', + 'tags-edit' => 'wijzig tag', + 'tags-delete' => 'verwijder tag', + 'transactions-index' => 'transacties', + 'transactions-create' => 'maak nieuwe transactie', + 'transactions-edit' => 'wijzig transactie', + 'transactions-delete' => 'verwijder transactie', + 'transactions-show' => 'bekijk transactie', ]; diff --git a/resources/lang/nl_NL/list.php b/resources/lang/nl_NL/list.php old mode 100644 new mode 100755 diff --git a/resources/lang/nl_NL/pagination.php b/resources/lang/nl_NL/pagination.php old mode 100644 new mode 100755 diff --git a/resources/lang/nl_NL/passwords.php b/resources/lang/nl_NL/passwords.php old mode 100644 new mode 100755 index 6b189b754b..c8451e8ac0 --- a/resources/lang/nl_NL/passwords.php +++ b/resources/lang/nl_NL/passwords.php @@ -1,4 +1,11 @@ "Ongeldig token! Sorry", "sent" => "Je krijgt een mailtje met een linkje om je wachtwoord te herstellen!", "reset" => "Je wachtwoord is hersteld!", - 'blocked' => 'Leuk geprobeerd wel.' + 'blocked' => 'Leuk geprobeerd wel.', ]; diff --git a/resources/lang/nl_NL/validation.php b/resources/lang/nl_NL/validation.php old mode 100644 new mode 100755 index bfd6f6004f..b3da11cde3 --- a/resources/lang/nl_NL/validation.php +++ b/resources/lang/nl_NL/validation.php @@ -1,6 +1,8 @@ 'Deze waarde is niet geldig voor de geselecteerde trigger.', + 'rule_action_value' => 'Deze waarde is niet geldig voor de geselecteerde actie.', 'invalid_domain' => 'Kan niet registereren vanaf dit domein.', 'file_already_attached' => 'Het geuploade bestand ":name" is al gelinkt aan deze transactie.', 'file_attached' => 'Bestand met naam ":name" is met succes geuploaded.', diff --git a/resources/lang/pt_BR/breadcrumbs.php b/resources/lang/pt_BR/breadcrumbs.php old mode 100644 new mode 100755 diff --git a/resources/lang/pt_BR/config.php b/resources/lang/pt_BR/config.php old mode 100644 new mode 100755 diff --git a/resources/lang/pt_BR/firefly.php b/resources/lang/pt_BR/firefly.php old mode 100644 new mode 100755 index 23584f877e..71e6922ae9 --- a/resources/lang/pt_BR/firefly.php +++ b/resources/lang/pt_BR/firefly.php @@ -2,476 +2,592 @@ return [ // general stuff: - 'test' => 'Você selecionou Inglês', - 'close' => 'Fechar', - 'pleaseHold' => 'Por favor espere...', - 'actions' => 'Ações', - 'edit' => 'Editar', - 'delete' => 'Apagar', - 'welcomeBack' => 'What\'s playing?', - 'everything' => 'Tudo', - 'customRange' => 'Intervalo Personalizado', - 'apply' => 'Aplicar', - 'cancel' => 'Cancelar', - 'from' => 'De', - 'to' => 'Até', - 'total_sum' => 'Soma Total', - 'period_sum' => 'Soma por período', - 'showEverything' => 'Mostrar tudo', - 'never' => 'Never', - 'search_results_for' => 'Pesquisar resultados por ":query"', - 'bounced_error' => 'A mensagem enviado para :email ressaltado, não tem acesso para você.', - 'deleted_error' => 'Estas credenciais não correspondem aos nossos registros.', - 'general_blocked_error' => 'Sua conta foi desativada, você não pode entrar.', - 'removed_amount' => ':amount removido', - 'added_amount' => ':amount adicionada', - 'asset_account_role_help' => 'Quaisquer opções extras resultantes da sua escolha pode ser definido mais tarde.', - 'Opening balance' => 'Saldo inicial', - 'create_new_stuff' => 'Criar novas coisas', - 'new_withdrawal' => 'Nova retirada', - 'new_deposit' => 'Novo depósito', - 'new_transfer' => 'Nova transferência', - 'new_asset_account' => 'Nova conta de ativo', - 'new_expense_account' => 'Nova conta de despesa', - 'new_revenue_account' => 'Nova conta de receita', - 'new_budget' => 'Novo orçamento', - 'new_bill' => 'Nova fatura', + 'language_incomplete' => 'This language is not yet fully translated', + 'test' => 'Você selecionou Inglês', + 'close' => 'Fechar', + 'pleaseHold' => 'Por favor espere...', + 'actions' => 'Ações', + 'edit' => 'Editar', + 'delete' => 'Apagar', + 'welcomeBack' => 'What\'s playing?', + 'everything' => 'Tudo', + 'customRange' => 'Intervalo Personalizado', + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'from' => 'De', + 'to' => 'Até', + 'total_sum' => 'Soma Total', + 'period_sum' => 'Soma por período', + 'showEverything' => 'Mostrar tudo', + 'never' => 'Never', + 'search_results_for' => 'Pesquisar resultados por ":query"', + 'bounced_error' => 'A mensagem enviado para :email ressaltado, não tem acesso para você.', + 'deleted_error' => 'Estas credenciais não correspondem aos nossos registros.', + 'general_blocked_error' => 'Sua conta foi desativada, você não pode entrar.', + 'removed_amount' => ':amount removido', + 'added_amount' => ':amount adicionada', + 'asset_account_role_help' => 'Quaisquer opções extras resultantes da sua escolha pode ser definido mais tarde.', + 'Opening balance' => 'Saldo inicial', + 'create_new_stuff' => 'Criar novas coisas', + 'new_withdrawal' => 'Nova retirada', + 'new_deposit' => 'Novo depósito', + 'new_transfer' => 'Nova transferência', + 'new_asset_account' => 'Nova conta de ativo', + 'new_expense_account' => 'Nova conta de despesa', + 'new_revenue_account' => 'Nova conta de receita', + 'new_budget' => 'Novo orçamento', + 'new_bill' => 'Nova fatura', + + // rules + 'rules' => 'Rules', + 'rules_explanation' => 'Here you can manage rules. Rules are triggered when a transaction is created or updated. Then, if the transaction has certain properties (called "triggers") Firefly will execute the "actions". Combined, you can make Firefly respond in a certain way to new transactions.', + 'rule_name' => 'Name of rule', + 'rule_triggers' => 'Rule triggers when', + 'rule_actions' => 'Rule will', + 'new_rule' => 'New rule', + 'new_rule_group' => 'New rule group', + 'rule_priority_up' => 'Give rule more priority', + 'rule_priority_down' => 'Give rule less priority', + 'make_new_rule_group' => 'Make new rule group', + 'store_new_rule_group' => 'Store new rule group', + 'created_new_rule_group' => 'New rule group ":title" stored!', + 'updated_rule_group' => 'Successfully updated rule group ":title".', + 'edit_rule_group' => 'Edit rule group ":title"', + 'delete_rule_group' => 'Delete rule group ":title"', + 'deleted_rule_group' => 'Deleted rule group ":title"', + 'update_rule_group' => 'Update rule group', + 'no_rules_in_group' => 'There are no rules in this group', + 'move_rule_group_up' => 'Move rule group up', + 'move_rule_group_down' => 'Move rule group down', + 'save_rules_by_moving' => 'Save these rule(s) by moving them to another rule group:', + 'make_new_rule' => 'Make new rule in rule group ":title"', + 'rule_help_stop_processing' => 'When you check this box, later rules in this group will not be executed.', + 'rule_help_active' => 'Inactive rules will never fire.', + 'stored_new_rule' => 'Stored new rule with title ":title"', + 'deleted_rule' => 'Deleted rule with title ":title"', + 'store_new_rule' => 'Store new rule', + 'updated_rule' => 'Updated rule with title ":title"', + + 'trigger' => 'Trigger', + 'trigger_value' => 'Trigger on value', + 'stop_processing_other_triggers' => 'Stop processing other triggers', + 'add_rule_trigger' => 'Add new trigger', + 'action' => 'Action', + 'action_value' => 'Action value', + 'stop_executing_other_actions' => 'Stop executing other actions', + 'add_rule_action' => 'Add new action', + 'edit_rule' => 'Edit rule ":title"', + 'update_rule' => 'Update rule', + + // actions and triggers + 'rule_trigger_user_action' => 'User action is ":trigger_value"', + 'rule_trigger_from_account_starts' => 'Source account starts with ":trigger_value"', + 'rule_trigger_from_account_ends' => 'Source account ends with ":trigger_value"', + 'rule_trigger_from_account_is' => 'Source account is ":trigger_value"', + 'rule_trigger_from_account_contains' => 'Source account contains ":trigger_value"', + 'rule_trigger_to_account_starts' => 'Destination account starts with ":trigger_value"', + 'rule_trigger_to_account_ends' => 'Destination account ends with ":trigger_value"', + 'rule_trigger_to_account_is' => 'Destination account is ":trigger_value"', + 'rule_trigger_to_account_contains' => 'Destination account contains ":trigger_value"', + 'rule_trigger_transaction_type' => 'Transaction is of type ":trigger_value"', + 'rule_trigger_amount_less' => 'Amount is less than :trigger_value', + 'rule_trigger_amount_exactly' => 'Amount is :trigger_value', + 'rule_trigger_amount_more' => 'Amount is more than :trigger_value', + 'rule_trigger_description_starts' => 'Description starts with ":trigger_value"', + 'rule_trigger_description_ends' => 'Description ends with ":trigger_value"', + 'rule_trigger_description_contains' => 'Description contains ":trigger_value"', + 'rule_trigger_description_is' => 'Description is ":trigger_value"', + + 'rule_trigger_from_account_starts_choice' => 'Source account starts with..', + 'rule_trigger_from_account_ends_choice' => 'Source account ends with..', + 'rule_trigger_from_account_is_choice' => 'Source account is..', + 'rule_trigger_from_account_contains_choice' => 'Source account contains..', + 'rule_trigger_to_account_starts_choice' => 'Destination account starts with..', + 'rule_trigger_to_account_ends_choice' => 'Destination account ends with..', + 'rule_trigger_to_account_is_choice' => 'Destination account is..', + 'rule_trigger_to_account_contains_choice' => 'Destination account contains..', + 'rule_trigger_transaction_type_choice' => 'Transaction is of type..', + 'rule_trigger_amount_less_choice' => 'Amount is less than..', + 'rule_trigger_amount_exactly_choice' => 'Amount is..', + 'rule_trigger_amount_more_choice' => 'Amount is more than..', + 'rule_trigger_description_starts_choice' => 'Description starts with..', + 'rule_trigger_description_ends_choice' => 'Description ends with..', + 'rule_trigger_description_contains_choice' => 'Description contains..', + 'rule_trigger_description_is_choice' => 'Description is..', + + 'rule_trigger_store_journal' => 'When a journal is created', + 'rule_trigger_update_journal' => 'When a journal is updated', + + 'rule_action_set_category' => 'Set category to ":action_value"', + 'rule_action_clear_category' => 'Clear category', + 'rule_action_set_budget' => 'Set budget to ":action_value"', + 'rule_action_clear_budget' => 'Clear budget', + 'rule_action_add_tag' => 'Add tag ":action_value"', + 'rule_action_remove_tag' => 'Remove tag ":action_value"', + 'rule_action_remove_all_tags' => 'Remove all tags', + 'rule_action_set_description' => 'Set description to ":action_value"', + 'rule_action_append_description' => 'Append description with ":action_value"', + 'rule_action_prepend_description' => 'Prepend description with ":action_value"', + + 'rule_action_set_category_choice' => 'Set category to..', + 'rule_action_clear_category_choice' => 'Clear any category', + 'rule_action_set_budget_choice' => 'Set budget to..', + 'rule_action_clear_budget_choice' => 'Clear any budget', + 'rule_action_add_tag_choice' => 'Add tag..', + 'rule_action_remove_tag_choice' => 'Remove tag..', + 'rule_action_remove_all_tags_choice' => 'Remove all tags', + 'rule_action_set_description_choice' => 'Set description to..', + 'rule_action_append_description_choice' => 'Append description with..', + 'rule_action_prepend_description_choice' => 'Prepend description with..', // tags - 'store_new_tag' => 'Armazenar nova tag', - 'update_tag' => 'Atualizar tag', - 'no_location_set' => 'Nenhuma localização.', - 'meta_data' => 'Meta dados', - 'location' => 'Localização', + 'store_new_tag' => 'Armazenar nova tag', + 'update_tag' => 'Atualizar tag', + 'no_location_set' => 'Nenhuma localização.', + 'meta_data' => 'Meta dados', + 'location' => 'Localização', // preferences - 'pref_home_screen_accounts' => 'Conta da tela inicial', - 'pref_home_screen_accounts_help' => 'Que conta deve ser exibida na tela inicial?', - 'pref_budget_settings' => 'Definições de Orçamento', - 'pref_budget_settings_help' => 'Qual a quantidade máxima de dinheiro um envelope orçamental pode conter?', - 'pref_view_range' => 'Ver intervalo', - 'pref_view_range_help' => 'Alguns gráficos são agrupados automaticamente em períodos. Qual período você prefere?', - 'pref_1D' => 'Um dia', - 'pref_1W' => 'Uma semana', - 'pref_1M' => 'Um mês', - 'pref_3M' => 'Trimestral', - 'pref_6M' => 'Semestral', - 'pref_languages' => 'Idiomas', - 'pref_languages_help' => 'Firefly III suporta muitos idiomas. Qual você prefere?', - 'pref_save_settings' => 'Salvar definições', + 'pref_home_screen_accounts' => 'Conta da tela inicial', + 'pref_home_screen_accounts_help' => 'Que conta deve ser exibida na tela inicial?', + 'pref_budget_settings' => 'Definições de Orçamento', + 'pref_budget_settings_help' => 'Qual a quantidade máxima de dinheiro um envelope orçamental pode conter?', + 'pref_view_range' => 'Ver intervalo', + 'pref_view_range_help' => 'Alguns gráficos são agrupados automaticamente em períodos. Qual período você prefere?', + 'pref_1D' => 'Um dia', + 'pref_1W' => 'Uma semana', + 'pref_1M' => 'Um mês', + 'pref_3M' => 'Trimestral', + 'pref_6M' => 'Semestral', + 'pref_languages' => 'Idiomas', + 'pref_languages_help' => 'Firefly III suporta muitos idiomas. Qual você prefere?', + 'pref_save_settings' => 'Salvar definições', // profile: - 'change_your_password' => 'Alterar sua senha', - 'delete_account' => 'Apagar conta', - 'current_password' => 'Senha atual', - 'new_password' => 'Nova senha', - 'new_password_again' => 'Nova senha (novamente)', - 'delete_your_account' => 'Apagar sua conta', - 'delete_your_account_help' => 'Deleting your account will also delete any accounts, transactions, anything you might have saved into Firefly III. It\'ll be GONE.', - 'delete_your_account_password' => 'Coloque sua senha para continuar.', - 'password' => 'Senha', - 'are_you_sure' => 'Você tem certeza? Você não poderá desfazer isso.', - 'delete_account_button' => 'Apagar sua conta', - 'invalid_current_password' => 'Senha atual inválida!', - 'password_changed' => 'Senha alterada!', - 'should_change' => 'A idéia é alterar sua senha.', - 'invalid_password' => 'Senha inválida!', + 'change_your_password' => 'Alterar sua senha', + 'delete_account' => 'Apagar conta', + 'current_password' => 'Senha atual', + 'new_password' => 'Nova senha', + 'new_password_again' => 'Nova senha (novamente)', + 'delete_your_account' => 'Apagar sua conta', + 'delete_your_account_help' => 'Deleting your account will also delete any accounts, transactions, anything you might have saved into Firefly III. It\'ll be GONE.', + 'delete_your_account_password' => 'Coloque sua senha para continuar.', + 'password' => 'Senha', + 'are_you_sure' => 'Você tem certeza? Você não poderá desfazer isso.', + 'delete_account_button' => 'Apagar sua conta', + 'invalid_current_password' => 'Senha atual inválida!', + 'password_changed' => 'Senha alterada!', + 'should_change' => 'A idéia é alterar sua senha.', + 'invalid_password' => 'Senha inválida!', // attachments - 'nr_of_attachments' => 'Um anexo|:count anexos', - 'attachments' => 'Anexos', - 'edit_attachment' => 'Editar anexo ":name"', - 'update_attachment' => 'Atualizar anexo', - 'delete_attachment' => 'Apagar anexo ":name"', - 'attachment_deleted' => 'Anexo apagado ":name"', - 'upload_max_file_size' => 'Tamanho máximo do arquivo: :size', + 'nr_of_attachments' => 'Um anexo|:count anexos', + 'attachments' => 'Anexos', + 'edit_attachment' => 'Editar anexo ":name"', + 'update_attachment' => 'Atualizar anexo', + 'delete_attachment' => 'Apagar anexo ":name"', + 'attachment_deleted' => 'Anexo apagado ":name"', + 'upload_max_file_size' => 'Tamanho máximo do arquivo: :size', // tour: - 'prev' => 'Anterior', - 'next' => 'Próximo', - 'end-tour' => 'Fim do Tour', - 'pause' => 'Parar', + 'prev' => 'Anterior', + 'next' => 'Próximo', + 'end-tour' => 'Fim do Tour', + 'pause' => 'Parar', // transaction index - 'title_expenses' => 'Despesas', - 'title_withdrawal' => 'Despesas', - 'title_revenue' => 'Receitas / Renda', - 'title_deposit' => 'Receita / Renda', - 'title_transfer' => 'Transferências', - 'title_transfers' => 'Transferências', + 'title_expenses' => 'Despesas', + 'title_withdrawal' => 'Despesas', + 'title_revenue' => 'Receitas / Renda', + 'title_deposit' => 'Receita / Renda', + 'title_transfer' => 'Transferências', + 'title_transfers' => 'Transferências', // csv import: - 'csv_import' => 'Importar arquivo CSV', - 'csv' => 'CSV', - 'csv_index_title' => 'Carregar e importar um arquivo CSV', - 'csv_define_column_roles' => 'Definir papeis da coluna', - 'csv_map_values' => 'Valores mapeados encontrados para valores existentes', - 'csv_download_config' => 'Download do arquivo CSV de configuração.', - 'csv_index_text' => 'This form allows you to import a CSV file with transactions into Firefly. It is based on the excellent CSV importer made by the folks at Atlassian. Simply upload your CSV file and follow the instructions. If you would like to learn more, please click on the button at the top of this page.', - 'csv_index_beta_warning' => 'Esta ferramenta está em beta. Por favor proceder com cautela', - 'csv_header_help' => 'Check this box when your CSV file\'s first row consists of column names, not actual data', - 'csv_date_help' => 'Date time format in your CSV. Follow the format like this page indicates. The default value will parse dates that look like this: :dateExample.', - 'csv_csv_file_help' => 'Select the CSV file here. You can only upload one file at a time', - 'csv_csv_config_file_help' => 'Select your CSV import configuration here. If you do not know what this is, ignore it. It will be explained later.', - 'csv_upload_button' => 'Iniciando importação do CSV', - 'csv_column_roles_title' => 'Definir papeis da coluna', - 'csv_column_roles_text' => 'Firefly does not know what each column means. You need to indicate what every column is. Please check out the example data if you\'re not sure yourself. Click on the question mark (top right of the page) to learn what each column means. If you want to map imported data onto existing data in Firefly, use the checkbox. The next step will show you what this button does.', - 'csv_column_roles_table' => 'Papéis da Coluna', - 'csv_column' => 'Coluna CSV', - 'csv_column_name' => 'Nome da coluna do CSV', - 'csv_column_example' => 'Exemplo de dados da coluna', - 'csv_column_role' => 'Coluna contém?', - 'csv_do_map_value' => 'Valor mapeado?', - 'csv_continue' => 'Continuar para o próximo passo', - 'csv_go_back' => 'Voltar para o passo anterior', - 'csv_map_title' => 'Valores mapeados encontrados para valores existentes', - 'csv_map_text' => 'This page allows you to map the values from the CSV file to existing entries in your database. This ensures that accounts and other things won\'t be created twice.', - 'csv_field_value' => 'Valor do campo do CSV', - 'csv_field_mapped_to' => 'Deve ser mapeado para...', - 'csv_do_not_map' => 'Não mapear este valor', - 'csv_download_config_title' => 'Download do CSV de configuração ', - 'csv_download_config_text' => 'Everything you\'ve just set up can be downloaded as a configuration file. Click the button to do so.', - 'csv_more_information_text' => 'If the import fails, you can use this configuration file so you don\'t have to start all over again. But, if the import succeeds, it will be easier to upload similar CSV files.', - 'csv_do_download_config' => 'Download do arquivo de configuração.', - 'csv_empty_description' => '(descrição vazia)', - 'csv_upload_form' => 'Formulário de Upload do CSV', - 'csv_index_unsupported_warning' => 'O importador de CSV está incapaz de fazer o seguinte:', - 'csv_unsupported_map' => 'The importer cannot map the column ":columnRole" to existing values in the database.', - 'csv_unsupported_value' => 'The importer does not know how to handle values in columns marked as ":columnRole".', - 'csv_cannot_store_value' => 'The importer has not reserved space for columns marked ":columnRole" and will be incapable of processing them.', - 'csv_process_title' => 'Importação do CSV terminou!', - 'csv_process_text' => 'O importador do CSV terminou e processou :rows linhas', - 'csv_row' => 'Linha', - 'csv_import_with_errors' => 'Houve um erro.|Houve :errors erros.', - 'csv_error_see_logs' => 'Verifique o arquivo de log para ver detalhes.', - 'csv_process_new_entries' => 'Firefly criou :imported nova(s) transação(ões)', - 'csv_start_over' => 'Importar novamente', - 'csv_to_index' => 'Voltar para tela inicial', - 'csv_upload_not_writeable' => 'Cannot write to the path mentioned here. Cannot upload', - 'csv_column__ignore' => '(ignorar esta coluna)', - 'csv_column_account-iban' => 'Conta de Ativo (IBAN)', - 'csv_column_account-id' => 'ID da Conta de Ativo (correspondente Firefly)', - 'csv_column_account-name' => 'Conta de Ativo (nome)', - 'csv_column_amount' => 'Valor', - 'csv_column_bill-id' => 'ID Fatura (correspondente Firefly)', - 'csv_column_bill-name' => 'Nom da Fatura', - 'csv_column_budget-id' => 'ID do Orçamento (correspondente Firefly)', - 'csv_column_budget-name' => 'Nome do Orçamento', - 'csv_column_category-id' => 'ID da Categoria (correspondente Firefly)', - 'csv_column_category-name' => 'Nome da Categoria', - 'csv_column_currency-code' => 'Código da Moeda (ISO 4217)', - 'csv_column_currency-id' => 'ID da Moeda (correspondente Firefly)', - 'csv_column_currency-name' => 'Nome da Moeda (correspondente Firefly)', - 'csv_column_currency-symbol' => 'Símbolo da Moeda (correspondente Firefly)', - 'csv_column_date-rent' => 'Rent calculation date', - 'csv_column_date-transaction' => 'Data', - 'csv_column_description' => 'Descrição', - 'csv_column_opposing-iban' => 'Opposing account (IBAN)', - 'csv_column_opposing-id' => 'Opposing account ID (matching Firefly)', - 'csv_column_opposing-name' => 'Opposing account (name)', - 'csv_column_rabo-debet-credit' => 'Rabobank specific debet/credit indicator', - 'csv_column_sepa-ct-id' => 'SEPA Credit Transfer end-to-end ID', - 'csv_column_sepa-ct-op' => 'SEPA Credit Transfer opposing account', - 'csv_column_sepa-db' => 'SEPA Direct Debet', - 'csv_column_tags-comma' => 'Tags (separadas por vírgula)', - 'csv_column_tags-space' => 'Tags (separadas por espaço)', - 'csv_specifix_RabobankDescription' => 'Select this when you\'re importing Rabobank CSV export files.', - 'csv_specifix_Dummy' => 'Checking this has no effect whatsoever.', - 'csv_import_account_help' => 'If your CSV file does NOT contain information about your asset account(s), use this dropdown to select to which account the transactions in the CSV belong to.', - 'csv_date_parse_error' => 'Could not parse a valid date from ":value", using the format ":format". Are you sure your CSV is correct?', + 'csv_import' => 'Importar arquivo CSV', + 'csv' => 'CSV', + 'csv_index_title' => 'Carregar e importar um arquivo CSV', + 'csv_define_column_roles' => 'Definir papeis da coluna', + 'csv_map_values' => 'Valores mapeados encontrados para valores existentes', + 'csv_download_config' => 'Download do arquivo CSV de configuração.', + 'csv_index_text' => 'This form allows you to import a CSV file with transactions into Firefly. It is based on the excellent CSV importer made by the folks at Atlassian. Simply upload your CSV file and follow the instructions. If you would like to learn more, please click on the button at the top of this page.', + 'csv_index_beta_warning' => 'Esta ferramenta está em beta. Por favor proceder com cautela', + 'csv_header_help' => 'Check this box when your CSV file\'s first row consists of column names, not actual data', + 'csv_date_help' => 'Date time format in your CSV. Follow the format like this page indicates. The default value will parse dates that look like this: :dateExample.', + 'csv_csv_file_help' => 'Select the CSV file here. You can only upload one file at a time', + 'csv_csv_config_file_help' => 'Select your CSV import configuration here. If you do not know what this is, ignore it. It will be explained later.', + 'csv_upload_button' => 'Iniciando importação do CSV', + 'csv_column_roles_title' => 'Definir papeis da coluna', + 'csv_column_roles_text' => 'Firefly does not know what each column means. You need to indicate what every column is. Please check out the example data if you\'re not sure yourself. Click on the question mark (top right of the page) to learn what each column means. If you want to map imported data onto existing data in Firefly, use the checkbox. The next step will show you what this button does.', + 'csv_column_roles_table' => 'Papéis da Coluna', + 'csv_column' => 'Coluna CSV', + 'csv_column_name' => 'Nome da coluna do CSV', + 'csv_column_example' => 'Exemplo de dados da coluna', + 'csv_column_role' => 'Coluna contém?', + 'csv_do_map_value' => 'Valor mapeado?', + 'csv_continue' => 'Continuar para o próximo passo', + 'csv_go_back' => 'Voltar para o passo anterior', + 'csv_map_title' => 'Valores mapeados encontrados para valores existentes', + 'csv_map_text' => 'This page allows you to map the values from the CSV file to existing entries in your database. This ensures that accounts and other things won\'t be created twice.', + 'csv_field_value' => 'Valor do campo do CSV', + 'csv_field_mapped_to' => 'Deve ser mapeado para...', + 'csv_do_not_map' => 'Não mapear este valor', + 'csv_download_config_title' => 'Download do CSV de configuração ', + 'csv_download_config_text' => 'Everything you\'ve just set up can be downloaded as a configuration file. Click the button to do so.', + 'csv_more_information_text' => 'If the import fails, you can use this configuration file so you don\'t have to start all over again. But, if the import succeeds, it will be easier to upload similar CSV files.', + 'csv_do_download_config' => 'Download do arquivo de configuração.', + 'csv_empty_description' => '(descrição vazia)', + 'csv_upload_form' => 'Formulário de Upload do CSV', + 'csv_index_unsupported_warning' => 'O importador de CSV está incapaz de fazer o seguinte:', + 'csv_unsupported_map' => 'The importer cannot map the column ":columnRole" to existing values in the database.', + 'csv_unsupported_value' => 'The importer does not know how to handle values in columns marked as ":columnRole".', + 'csv_cannot_store_value' => 'The importer has not reserved space for columns marked ":columnRole" and will be incapable of processing them.', + 'csv_process_title' => 'Importação do CSV terminou!', + 'csv_process_text' => 'O importador do CSV terminou e processou :rows linhas', + 'csv_row' => 'Linha', + 'csv_import_with_errors' => 'Houve um erro.|Houve :errors erros.', + 'csv_error_see_logs' => 'Verifique o arquivo de log para ver detalhes.', + 'csv_process_new_entries' => 'Firefly criou :imported nova(s) transação(ões)', + 'csv_start_over' => 'Importar novamente', + 'csv_to_index' => 'Voltar para tela inicial', + 'csv_upload_not_writeable' => 'Cannot write to the path mentioned here. Cannot upload', + 'csv_column__ignore' => '(ignorar esta coluna)', + 'csv_column_account-iban' => 'Conta de Ativo (IBAN)', + 'csv_column_account-id' => 'ID da Conta de Ativo (correspondente Firefly)', + 'csv_column_account-name' => 'Conta de Ativo (nome)', + 'csv_column_amount' => 'Valor', + 'csv_column_amount-comma-separated' => 'Amount (comma as decimal separator)', + 'csv_column_bill-id' => 'ID Fatura (correspondente Firefly)', + 'csv_column_bill-name' => 'Nom da Fatura', + 'csv_column_budget-id' => 'ID do Orçamento (correspondente Firefly)', + 'csv_column_budget-name' => 'Nome do Orçamento', + 'csv_column_category-id' => 'ID da Categoria (correspondente Firefly)', + 'csv_column_category-name' => 'Nome da Categoria', + 'csv_column_currency-code' => 'Código da Moeda (ISO 4217)', + 'csv_column_currency-id' => 'ID da Moeda (correspondente Firefly)', + 'csv_column_currency-name' => 'Nome da Moeda (correspondente Firefly)', + 'csv_column_currency-symbol' => 'Símbolo da Moeda (correspondente Firefly)', + 'csv_column_date-rent' => 'Rent calculation date', + 'csv_column_date-transaction' => 'Data', + 'csv_column_description' => 'Descrição', + 'csv_column_opposing-iban' => 'Opposing account (IBAN)', + 'csv_column_opposing-id' => 'Opposing account ID (matching Firefly)', + 'csv_column_opposing-name' => 'Opposing account (name)', + 'csv_column_rabo-debet-credit' => 'Rabobank specific debet/credit indicator', + 'csv_column_sepa-ct-id' => 'SEPA Credit Transfer end-to-end ID', + 'csv_column_sepa-ct-op' => 'SEPA Credit Transfer opposing account', + 'csv_column_sepa-db' => 'SEPA Direct Debet', + 'csv_column_tags-comma' => 'Tags (separadas por vírgula)', + 'csv_column_tags-space' => 'Tags (separadas por espaço)', + 'csv_specifix_RabobankDescription' => 'Select this when you\'re importing Rabobank CSV export files.', + 'csv_specifix_AbnAmroDescription' => 'Select this when you\'re importing ABN AMRO CSV export files.', + 'csv_specifix_Dummy' => 'Checking this has no effect whatsoever.', + 'csv_import_account_help' => 'If your CSV file does NOT contain information about your asset account(s), use this dropdown to select to which account the transactions in the CSV belong to.', + 'csv_delimiter_help' => 'Choose the field delimiter that is used in your input file. If not sure, comma is the safest option.', + 'csv_date_parse_error' => 'Could not parse a valid date from ":value", using the format ":format". Are you sure your CSV is correct?', // create new stuff: - 'create_new_withdrawal' => 'Criar nova retirada', - 'create_new_deposit' => 'Criar um novo depósito', - 'create_new_transfer' => 'Criar nova transferência', - 'create_new_asset' => 'Criar nova conta de ativo', - 'create_new_expense' => 'Criar nova conta de despesa', - 'create_new_revenue' => 'Criar nova conta de receita', - 'create_new_piggy_bank' => 'Criar novo cofrinho', - 'create_new_bill' => 'Criar nova fatura', + 'create_new_withdrawal' => 'Criar nova retirada', + 'create_new_deposit' => 'Criar um novo depósito', + 'create_new_transfer' => 'Criar nova transferência', + 'create_new_asset' => 'Criar nova conta de ativo', + 'create_new_expense' => 'Criar nova conta de despesa', + 'create_new_revenue' => 'Criar nova conta de receita', + 'create_new_piggy_bank' => 'Criar novo cofrinho', + 'create_new_bill' => 'Criar nova fatura', // currencies: - 'create_currency' => 'Criar uma nova moeda', - 'edit_currency' => 'Editar moeda ":name"', - 'store_currency' => 'Armazenar nova moeda', - 'update_currency' => 'Atualizar moeda', + 'create_currency' => 'Criar uma nova moeda', + 'edit_currency' => 'Editar moeda ":name"', + 'store_currency' => 'Armazenar nova moeda', + 'update_currency' => 'Atualizar moeda', + 'new_default_currency' => ':name is now the default currency.', + 'cannot_delete_currency' => 'Cannot delete :name because there are still transactions attached to it!', + 'deleted_currency' => 'Currency :name deleted', + 'created_currency' => 'Currency :name created', + 'updated_currency' => 'Currency :name updated', + 'ask_site_owner' => 'Please ask :owner to add, remove or edit currencies.', + 'currencies_intro' => 'Firefly III supports various currencies which you can set and enable here.', + 'make_default_currency' => 'make default', + 'default_currency' => 'default', // new user: - 'submit' => 'Enviar', - 'getting_started' => 'Iniciar', - 'to_get_started' => 'To get started with Firefly, please enter your current bank\'s name, and the balance of your checking account:', - 'savings_balance_text' => 'If you have a savings account, please enter the current balance of your savings account:', - 'cc_balance_text' => 'If you have a credit card, please enter your credit card\'s limit.', + 'submit' => 'Enviar', + 'getting_started' => 'Iniciar', + 'to_get_started' => 'To get started with Firefly, please enter your current bank\'s name, and the balance of your checking account:', + 'savings_balance_text' => 'If you have a savings account, please enter the current balance of your savings account:', + 'cc_balance_text' => 'If you have a credit card, please enter your credit card\'s limit.', // forms: - 'mandatoryFields' => 'Campos obrigatórios', - 'optionalFields' => 'Campos opcionais', - 'options' => 'Opções', - 'something' => 'Qualquer coisa!', + 'mandatoryFields' => 'Campos obrigatórios', + 'optionalFields' => 'Campos opcionais', + 'options' => 'Opções', + 'something' => 'Qualquer coisa!', // budgets: - 'create_new_budget' => 'Criar um novo orçamento', - 'store_new_budget' => 'Armazenar novo orçamento', - 'availableIn' => 'Disponível em :date', - 'transactionsWithoutBudget' => 'Despesas sem orçamentos', - 'transactionsWithoutBudgetDate' => 'Despesas sem orçamentos em :date', - 'createBudget' => 'Novo orçamento', - 'inactiveBudgets' => 'Orçamentos inativos', - 'without_budget_between' => 'Transactions without a budget between :start and :end', - 'budget_in_month' => ':name no :month', - 'delete_budget' => 'Delete budget ":name"', - 'edit_budget' => 'Edit budget ":name"', - 'update_amount' => 'Update amount', - 'update_budget' => 'Update budget', + 'create_new_budget' => 'Criar um novo orçamento', + 'store_new_budget' => 'Armazenar novo orçamento', + 'availableIn' => 'Disponível em :date', + 'transactionsWithoutBudget' => 'Despesas sem orçamentos', + 'transactionsWithoutBudgetDate' => 'Despesas sem orçamentos em :date', + 'createBudget' => 'Novo orçamento', + 'inactiveBudgets' => 'Orçamentos inativos', + 'without_budget_between' => 'Transactions without a budget between :start and :end', + 'budget_in_month' => ':name no :month', + 'delete_budget' => 'Delete budget ":name"', + 'edit_budget' => 'Edit budget ":name"', + 'update_amount' => 'Update amount', + 'update_budget' => 'Update budget', // bills: - 'delete_bill' => 'Delete bill ":name"', - 'edit_bill' => 'Edit bill ":name"', - 'update_bill' => 'Update bill', - 'store_new_bill' => 'Store new bill', + 'delete_bill' => 'Delete bill ":name"', + 'edit_bill' => 'Edit bill ":name"', + 'update_bill' => 'Update bill', + 'store_new_bill' => 'Store new bill', // accounts: - 'details_for_asset' => 'Details for asset account ":name"', - 'details_for_expense' => 'Details for expense account ":name"', - 'details_for_revenue' => 'Details for revenue account ":name"', - 'details_for_cash' => 'Details for cash account ":name"', - 'store_new_asset_account' => 'Store new asset account', - 'store_new_expense_account' => 'Store new expense account', - 'store_new_revenue_account' => 'Store new revenue account', - 'edit_asset_account' => 'Edit asset account ":name"', - 'edit_expense_account' => 'Edit expense account ":name"', - 'edit_revenue_account' => 'Edit revenue account ":name"', - 'delete_asset_account' => 'Delete asset account ":name"', - 'delete_expense_account' => 'Delete expense account ":name"', - 'delete_revenue_account' => 'Delete revenue account ":name"', - 'asset_deleted' => 'Successfully deleted asset account ":name"', - 'expense_deleted' => 'Successfully deleted expense account ":name"', - 'revenue_deleted' => 'Successfully deleted revenue account ":name"', - 'update_asset_account' => 'Update asset account', - 'update_expense_account' => 'Update expense account', - 'update_revenue_account' => 'Update revenue account', - 'make_new_asset_account' => 'Create a new asset account', - 'make_new_expense_account' => 'Create a new expense account', - 'make_new_revenue_account' => 'Create a new revenue account', - 'asset_accounts' => 'Asset accounts', - 'expense_accounts' => 'Expense accounts', - 'revenue_accounts' => 'Revenue accounts', - 'accountExtraHelp_asset' => '', - 'accountExtraHelp_expense' => '', - 'accountExtraHelp_revenue' => '', - 'account_type' => 'Account type', - 'save_transactions_by_moving' => 'Save these transaction(s) by moving them to another account:', + 'details_for_asset' => 'Details for asset account ":name"', + 'details_for_expense' => 'Details for expense account ":name"', + 'details_for_revenue' => 'Details for revenue account ":name"', + 'details_for_cash' => 'Details for cash account ":name"', + 'store_new_asset_account' => 'Store new asset account', + 'store_new_expense_account' => 'Store new expense account', + 'store_new_revenue_account' => 'Store new revenue account', + 'edit_asset_account' => 'Edit asset account ":name"', + 'edit_expense_account' => 'Edit expense account ":name"', + 'edit_revenue_account' => 'Edit revenue account ":name"', + 'delete_asset_account' => 'Delete asset account ":name"', + 'delete_expense_account' => 'Delete expense account ":name"', + 'delete_revenue_account' => 'Delete revenue account ":name"', + 'asset_deleted' => 'Successfully deleted asset account ":name"', + 'expense_deleted' => 'Successfully deleted expense account ":name"', + 'revenue_deleted' => 'Successfully deleted revenue account ":name"', + 'update_asset_account' => 'Update asset account', + 'update_expense_account' => 'Update expense account', + 'update_revenue_account' => 'Update revenue account', + 'make_new_asset_account' => 'Create a new asset account', + 'make_new_expense_account' => 'Create a new expense account', + 'make_new_revenue_account' => 'Create a new revenue account', + 'asset_accounts' => 'Asset accounts', + 'expense_accounts' => 'Expense accounts', + 'revenue_accounts' => 'Revenue accounts', + 'accountExtraHelp_asset' => '', + 'accountExtraHelp_expense' => '', + 'accountExtraHelp_revenue' => '', + 'account_type' => 'Account type', + 'save_transactions_by_moving' => 'Save these transaction(s) by moving them to another account:', // categories: - 'new_category' => 'New category', - 'create_new_category' => 'Create a new category', - 'without_category' => 'Without a category', - 'update_category' => 'Wijzig categorie', - 'categories' => 'Categories', - 'edit_category' => 'Edit category ":name"', - 'no_category' => '(no category)', - 'category' => 'Category', - 'delete_category' => 'Delete category ":name"', - 'store_category' => 'Store new category', + 'new_category' => 'New category', + 'create_new_category' => 'Create a new category', + 'without_category' => 'Without a category', + 'update_category' => 'Wijzig categorie', + 'categories' => 'Categories', + 'edit_category' => 'Edit category ":name"', + 'no_category' => '(no category)', + 'category' => 'Category', + 'delete_category' => 'Delete category ":name"', + 'store_category' => 'Store new category', + 'without_category_between' => 'Without category between :start and :end', // transactions: - 'update_withdrawal' => 'Update withdrawal', - 'update_deposit' => 'Update deposit', - 'update_transfer' => 'Update transfer', - 'delete_withdrawal' => 'Delete withdrawal ":description"', - 'delete_deposit' => 'Delete deposit ":description"', - 'delete_transfer' => 'Delete transfer ":description"', + 'update_withdrawal' => 'Update withdrawal', + 'update_deposit' => 'Update deposit', + 'update_transfer' => 'Update transfer', + 'delete_withdrawal' => 'Delete withdrawal ":description"', + 'delete_deposit' => 'Delete deposit ":description"', + 'delete_transfer' => 'Delete transfer ":description"', // new user: - 'welcome' => 'Welcome to Firefly!', - 'createNewAsset' => 'Create a new asset account to get started. ' . - 'This will allow you to create transactions and start your financial management', - 'createNewAssetButton' => 'Criar nova conta de ativo', + 'welcome' => 'Welcome to Firefly!', + 'createNewAsset' => 'Create a new asset account to get started. ' . + 'This will allow you to create transactions and start your financial management', + 'createNewAssetButton' => 'Criar nova conta de ativo', // home page: - 'yourAccounts' => 'Your accounts', - 'budgetsAndSpending' => 'Budgets and spending', - 'savings' => 'Savings', - 'markAsSavingsToContinue' => 'Mark your asset accounts as "Savings account" to fill this panel', - 'createPiggyToContinue' => 'Create piggy banks to fill this panel.', - 'newWithdrawal' => 'New expense', - 'newDeposit' => 'Novo depósito', - 'newTransfer' => 'Nova transferência', - 'moneyIn' => 'Money in', - 'moneyOut' => 'Money out', - 'billsToPay' => 'Bills to pay', - 'billsPaid' => 'Bills paid', - 'viewDetails' => 'View details', - 'divided' => 'divided', - 'toDivide' => 'left to divide', + 'yourAccounts' => 'Your accounts', + 'budgetsAndSpending' => 'Budgets and spending', + 'savings' => 'Savings', + 'markAsSavingsToContinue' => 'Mark your asset accounts as "Savings account" to fill this panel', + 'createPiggyToContinue' => 'Create piggy banks to fill this panel.', + 'newWithdrawal' => 'New expense', + 'newDeposit' => 'Novo depósito', + 'newTransfer' => 'Nova transferência', + 'moneyIn' => 'Money in', + 'moneyOut' => 'Money out', + 'billsToPay' => 'Bills to pay', + 'billsPaid' => 'Bills paid', + 'viewDetails' => 'View details', + 'divided' => 'divided', + 'toDivide' => 'left to divide', // menu and titles, should be recycled as often as possible: - 'toggleNavigation' => 'Toggle navigation', - 'currency' => 'Currency', - 'preferences' => 'Preferences', - 'logout' => 'Logout', - 'searchPlaceholder' => 'Search...', - 'dashboard' => 'Dashboard', - 'currencies' => 'Currencies', - 'accounts' => 'Accounts', - 'Asset account' => 'Asset account', - 'Default account' => 'Asset account', - 'Expense account' => 'Conta de Despesa', - 'Revenue account' => 'Conta de Receita', - 'Initial balance account' => 'Initial balance account', - 'budgets' => 'Budgets', - 'tags' => 'Tags', - 'reports' => 'Relatórios', - 'transactions' => 'Transações', - 'expenses' => 'Despesas', - 'income' => 'Receita / Renda', - 'transfers' => 'Transferências', - 'moneyManagement' => 'Gerenciamento de Dinheiro', - 'piggyBanks' => 'Cofrinhos', - 'bills' => 'Faturas', - 'createNew' => 'Criar nova(o)', - 'withdrawal' => 'Retirada', - 'deposit' => 'Depósito', - 'account' => 'Conta', - 'transfer' => 'Transferência', - 'Withdrawal' => 'Retirada', - 'Deposit' => 'Depósito', - 'Transfer' => 'Transferência', - 'bill' => 'Fatura', - 'yes' => 'Sim', - 'no' => 'Não', - 'amount' => 'Valor', - 'newBalance' => 'Novo saldo', - 'overview' => 'Visão Geral', - 'saveOnAccount' => 'Salvar na conta', - 'unknown' => 'Desconhecido', - 'daily' => 'Diário', - 'weekly' => 'Semanal', - 'monthly' => 'Mensal', - 'quarterly' => 'Trimestral', - 'half-year' => 'Semestral', - 'yearly' => 'Anual', - 'profile' => 'Perfil', + 'toggleNavigation' => 'Toggle navigation', + 'currency' => 'Currency', + 'preferences' => 'Preferences', + 'logout' => 'Logout', + 'searchPlaceholder' => 'Search...', + 'dashboard' => 'Dashboard', + 'currencies' => 'Currencies', + 'accounts' => 'Accounts', + 'Asset account' => 'Asset account', + 'Default account' => 'Asset account', + 'Expense account' => 'Conta de Despesa', + 'Revenue account' => 'Conta de Receita', + 'Initial balance account' => 'Initial balance account', + 'budgets' => 'Budgets', + 'tags' => 'Tags', + 'reports' => 'Relatórios', + 'transactions' => 'Transações', + 'expenses' => 'Despesas', + 'income' => 'Receita / Renda', + 'transfers' => 'Transferências', + 'moneyManagement' => 'Gerenciamento de Dinheiro', + 'piggyBanks' => 'Cofrinhos', + 'bills' => 'Faturas', + 'createNew' => 'Criar nova(o)', + 'withdrawal' => 'Retirada', + 'deposit' => 'Depósito', + 'account' => 'Conta', + 'transfer' => 'Transferência', + 'Withdrawal' => 'Retirada', + 'Deposit' => 'Depósito', + 'Transfer' => 'Transferência', + 'bill' => 'Fatura', + 'yes' => 'Sim', + 'no' => 'Não', + 'amount' => 'Valor', + 'newBalance' => 'Novo saldo', + 'overview' => 'Visão Geral', + 'saveOnAccount' => 'Salvar na conta', + 'unknown' => 'Desconhecido', + 'daily' => 'Diário', + 'weekly' => 'Semanal', + 'monthly' => 'Mensal', + 'quarterly' => 'Trimestral', + 'half-year' => 'Semestral', + 'yearly' => 'Anual', + 'profile' => 'Perfil', // reports: - 'report_default' => 'Default financial report for :start until :end', - 'quick_link_reports' => 'Quick links', - 'quick_link_default_report' => 'Default financial report', - 'report_this_month_quick' => 'Current month, all accounts', - 'report_this_year_quick' => 'Current year, all accounts', - 'report_all_time_quick' => 'All-time, all accounts', - 'reports_can_bookmark' => 'Remember that reports can be bookmarked.', - 'incomeVsExpenses' => 'Renda vs. Despesas', - 'accountBalances' => 'Saldos de Contas', - 'balanceStartOfYear' => 'Balance at start of year', - 'balanceEndOfYear' => 'Balance at end of year', - 'balanceStartOfMonth' => 'Balance at start of month', - 'balanceEndOfMonth' => 'Balance at end of month', - 'balanceStart' => 'Balance at start of period', - 'balanceEnd' => 'Balance at end of period', - 'reportsOwnAccounts' => 'Reports for your own accounts', - 'reportsOwnAccountsAndShared' => 'Reports for your own accounts and shared accounts', - 'splitByAccount' => 'Split by account', - 'balancedByTransfersAndTags' => 'Balanced by transfers and tags', - 'coveredWithTags' => 'Covered with tags', - 'leftUnbalanced' => 'Left unbalanced', - 'expectedBalance' => 'Saldo Experado', - 'outsideOfBudgets' => 'Fora do orçamento', - 'leftInBudget' => 'Deixou no orçamento', - 'sumOfSums' => 'Soma dos montantes', - 'noCategory' => '(no category)', - 'notCharged' => 'Não cobrado (ainda)', - 'inactive' => 'Inativo', - 'difference' => 'Diferente', - 'in' => 'Entrada', - 'out' => 'Saída', - 'topX' => 'top :number', - 'showTheRest' => 'Mostrar tudo', - 'hideTheRest' => 'Mostrar apenas os top :number', - 'sum_of_year' => 'Soma do ano', - 'sum_of_years' => 'Sum of years', - 'average_of_year' => 'Média do ano', - 'average_of_years' => 'Average of years', - 'categories_earned_in_year' => 'Categories (by earnings)', - 'categories_spent_in_year' => 'Categories (by spendings)', - 'report_type' => 'Report type', - 'report_type_default' => 'Default financial report', - 'report_included_accounts' => 'Included accounts', - 'report_date_range' => 'Date range', - 'report_include_help' => 'In all cases, transfers to shared accounts count as expenses, and transfers from shared accounts count as income.', - 'report_preset_ranges' => 'Pre-set ranges', - 'shared' => 'Shared', + 'report_default' => 'Default financial report for :start until :end', + 'quick_link_reports' => 'Quick links', + 'quick_link_default_report' => 'Default financial report', + 'report_this_month_quick' => 'Current month, all accounts', + 'report_this_year_quick' => 'Current year, all accounts', + 'report_all_time_quick' => 'All-time, all accounts', + 'reports_can_bookmark' => 'Remember that reports can be bookmarked.', + 'incomeVsExpenses' => 'Renda vs. Despesas', + 'accountBalances' => 'Saldos de Contas', + 'balanceStartOfYear' => 'Balance at start of year', + 'balanceEndOfYear' => 'Balance at end of year', + 'balanceStartOfMonth' => 'Balance at start of month', + 'balanceEndOfMonth' => 'Balance at end of month', + 'balanceStart' => 'Balance at start of period', + 'balanceEnd' => 'Balance at end of period', + 'reportsOwnAccounts' => 'Reports for your own accounts', + 'reportsOwnAccountsAndShared' => 'Reports for your own accounts and shared accounts', + 'splitByAccount' => 'Split by account', + 'balancedByTransfersAndTags' => 'Balanced by transfers and tags', + 'coveredWithTags' => 'Covered with tags', + 'leftUnbalanced' => 'Left unbalanced', + 'expectedBalance' => 'Saldo Experado', + 'outsideOfBudgets' => 'Fora do orçamento', + 'leftInBudget' => 'Deixou no orçamento', + 'sumOfSums' => 'Soma dos montantes', + 'noCategory' => '(no category)', + 'notCharged' => 'Não cobrado (ainda)', + 'inactive' => 'Inativo', + 'difference' => 'Diferente', + 'in' => 'Entrada', + 'out' => 'Saída', + 'topX' => 'top :number', + 'showTheRest' => 'Mostrar tudo', + 'hideTheRest' => 'Mostrar apenas os top :number', + 'sum_of_year' => 'Soma do ano', + 'sum_of_years' => 'Sum of years', + 'average_of_year' => 'Média do ano', + 'average_of_years' => 'Average of years', + 'categories_earned_in_year' => 'Categories (by earnings)', + 'categories_spent_in_year' => 'Categories (by spendings)', + 'report_type' => 'Report type', + 'report_type_default' => 'Default financial report', + 'report_included_accounts' => 'Included accounts', + 'report_date_range' => 'Date range', + 'report_include_help' => 'In all cases, transfers to shared accounts count as expenses, and transfers from shared accounts count as income.', + 'report_preset_ranges' => 'Pre-set ranges', + 'shared' => 'Shared', // charts: - 'dayOfMonth' => 'Dia do mês', - 'month' => 'Mês', - 'budget' => 'Orçamento', - 'spent' => 'Gasto', - 'earned' => 'Ganho', - 'overspent' => 'Gasto excedido', - 'left' => 'Left', - 'noBudget' => '(sem orçamento)', - 'maxAmount' => 'Valor Máximo', - 'minAmount' => 'Valor Mínimo', - 'billEntry' => 'Current bill entry', - 'name' => 'Nome', - 'date' => 'Data', - 'paid' => 'Pago', - 'unpaid' => 'Não pago', - 'day' => 'Dia', - 'budgeted' => 'Orçado', - 'period' => 'Período', - 'balance' => 'Saldo', - 'summary' => 'Sumário', - 'sum' => 'Soma', - 'average' => 'Média', - 'balanceFor' => 'Saldo para ":name"', + 'dayOfMonth' => 'Dia do mês', + 'month' => 'Mês', + 'budget' => 'Orçamento', + 'spent' => 'Gasto', + 'earned' => 'Ganho', + 'overspent' => 'Gasto excedido', + 'left' => 'Left', + 'noBudget' => '(sem orçamento)', + 'maxAmount' => 'Valor Máximo', + 'minAmount' => 'Valor Mínimo', + 'billEntry' => 'Current bill entry', + 'name' => 'Nome', + 'date' => 'Data', + 'paid' => 'Pago', + 'unpaid' => 'Não pago', + 'day' => 'Dia', + 'budgeted' => 'Orçado', + 'period' => 'Período', + 'balance' => 'Saldo', + 'summary' => 'Sumário', + 'sum' => 'Soma', + 'average' => 'Média', + 'balanceFor' => 'Saldo para ":name"', // piggy banks: - 'piggy_bank' => 'Cofrinho', - 'new_piggy_bank' => 'Criar novo cofrinho', - 'store_piggy_bank' => 'Store new piggy bank', - 'account_status' => 'Account status', - 'left_for_piggy_banks' => 'Left for piggy banks', - 'sum_of_piggy_banks' => 'Sum of piggy banks', - 'saved_so_far' => 'Saved so far', - 'left_to_save' => 'Left to save', - 'add_money_to_piggy_title' => 'Add money to piggy bank ":name"', - 'remove_money_from_piggy_title' => 'Remove money from piggy bank ":name"', - 'add' => 'Adicionar', - 'remove' => 'Remover', - 'max_amount_add' => 'The maximum amount you can add is', - 'max_amount_remove' => 'The maximum amount you can remove is', - 'update_piggy_button' => 'Update piggy bank', - 'update_piggy_title' => 'Update piggy bank ":name"', - 'details' => 'Detalhes', - 'events' => 'Eventos', - 'target_amount' => 'Valor alvo', - 'start_date' => 'Data de Início', - 'target_date' => 'Data Alvo', - 'no_target_date' => 'Nenhum data', - 'todo' => 'A fazer', - 'table' => 'Tabela', - 'piggy_bank_not_exists' => 'Piggy bank no longer exists.', - 'add_any_amount_to_piggy' => 'Add money to this piggy bank to reach your target of :amount.', - 'add_set_amount_to_piggy' => 'Add :amount to fill this piggy bank on :date', - 'delete_piggy_bank' => 'Apagar cofrinho ":name"', + 'piggy_bank' => 'Cofrinho', + 'new_piggy_bank' => 'Criar novo cofrinho', + 'store_piggy_bank' => 'Store new piggy bank', + 'account_status' => 'Account status', + 'left_for_piggy_banks' => 'Left for piggy banks', + 'sum_of_piggy_banks' => 'Sum of piggy banks', + 'saved_so_far' => 'Saved so far', + 'left_to_save' => 'Left to save', + 'add_money_to_piggy_title' => 'Add money to piggy bank ":name"', + 'remove_money_from_piggy_title' => 'Remove money from piggy bank ":name"', + 'add' => 'Adicionar', + 'remove' => 'Remover', + 'max_amount_add' => 'The maximum amount you can add is', + 'max_amount_remove' => 'The maximum amount you can remove is', + 'update_piggy_button' => 'Update piggy bank', + 'update_piggy_title' => 'Update piggy bank ":name"', + 'details' => 'Detalhes', + 'events' => 'Eventos', + 'target_amount' => 'Valor alvo', + 'start_date' => 'Data de Início', + 'target_date' => 'Data Alvo', + 'no_target_date' => 'Nenhum data', + 'todo' => 'A fazer', + 'table' => 'Tabela', + 'piggy_bank_not_exists' => 'Piggy bank no longer exists.', + 'add_any_amount_to_piggy' => 'Add money to this piggy bank to reach your target of :amount.', + 'add_set_amount_to_piggy' => 'Add :amount to fill this piggy bank on :date', + 'delete_piggy_bank' => 'Apagar cofrinho ":name"', // tags - 'regular_tag' => 'Just a regular tag.', - 'balancing_act' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.', - 'advance_payment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.', - 'delete_tag' => 'Apagar tag ":tag"', - 'new_tag' => 'Fazer nova tag', - 'edit_tag' => 'Editar tag ":tag"', - 'no_year' => 'Nenhum ano definido', - 'no_month' => 'Nenhum mês definido', - 'tag_title_nothing' => 'Tags padrões', - 'tag_title_balancingAct' => 'Balancing act tags', - 'tag_title_advancePayment' => 'Advance payment tags', - 'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like expensive, bill or for-party. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called Christmas dinner with friends and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.', - 'tags_group' => 'Tags group transactions together, which makes it possible to store reimbursements (in case you front money for others) and other "balancing acts" where expenses are summed up (the payments on your new TV) or where expenses and deposits are cancelling each other out (buying something with saved money). It\'s all up to you. Using tags the old-fashioned way is of course always possible. ', - 'tags_start' => 'Create a tag to get started or enter tags when creating new transactions.', + 'regular_tag' => 'Just a regular tag.', + 'balancing_act' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.', + 'advance_payment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.', + 'delete_tag' => 'Apagar tag ":tag"', + 'new_tag' => 'Fazer nova tag', + 'edit_tag' => 'Editar tag ":tag"', + 'no_year' => 'Nenhum ano definido', + 'no_month' => 'Nenhum mês definido', + 'tag_title_nothing' => 'Tags padrões', + 'tag_title_balancingAct' => 'Balancing act tags', + 'tag_title_advancePayment' => 'Advance payment tags', + 'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like expensive, bill or for-party. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called Christmas dinner with friends and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.', + 'tags_group' => 'Tags group transactions together, which makes it possible to store reimbursements (in case you front money for others) and other "balancing acts" where expenses are summed up (the payments on your new TV) or where expenses and deposits are cancelling each other out (buying something with saved money). It\'s all up to you. Using tags the old-fashioned way is of course always possible.', + 'tags_start' => 'Create a tag to get started or enter tags when creating new transactions.', ]; diff --git a/resources/lang/pt_BR/form.php b/resources/lang/pt_BR/form.php old mode 100644 new mode 100755 index 03f40ccc90..322c358c9c --- a/resources/lang/pt_BR/form.php +++ b/resources/lang/pt_BR/form.php @@ -38,11 +38,11 @@ return [ 'amount' => 'Valor', 'date' => 'Data', 'category' => 'Categoria', - 'tags' => 'Tags', + 'tags' => 'Etiquetas', 'deletePermanently' => 'Apagar permanentemente', 'cancel' => 'Cancelar', 'targetdate' => 'Data Alvo', - 'tag' => 'Tag', + 'tag' => 'Etiqueta', 'under' => 'Debaixo', 'symbol' => 'Símbolo', 'code' => 'Código', @@ -53,6 +53,7 @@ return [ 'csv_config' => 'Importar CSV de configuração', 'specifix' => 'Bank- or file specific fixes', 'csv_import_account' => 'Default import account', + 'csv_delimiter' => 'CSV field delimiter', 'attachments[]' => 'Anexos', 'store_new_withdrawal' => 'Store new withdrawal', 'store_new_deposit' => 'Store new deposit', @@ -67,6 +68,12 @@ return [ 'filename' => 'Nome do arquivo', 'mime' => 'Mime type', 'size' => 'Tamanho', + 'trigger' => 'Trigger', + 'stop_processing' => 'Stop processing', + + 'csv_comma' => 'A comma (,)', + 'csv_semicolon' => 'A semicolon (;)', + 'csv_tab' => 'A tab (invisible)', 'delete_account' => 'Apagar conta ":name"', @@ -76,10 +83,14 @@ return [ 'delete_currency' => 'Delete currency ":name"', 'delete_journal' => 'Delete transaction with description ":description"', 'delete_attachment' => 'Apagar anexo ":name"', + 'delete_rule' => 'Delete rule ":title"', + 'delete_rule_group' => 'Delete rule group ":title"', 'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?', 'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?', 'bill_areYouSure' => 'Você tem certeza que quer apagar a fatura ":name"?', + 'rule_areYouSure' => 'Are you sure you want to delete the rule titled ":title"?', + 'ruleGroup_areYouSure' => 'Are you sure you want to delete the rule group titled ":title"?', 'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?', 'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?', 'currency_areYouSure' => 'Are you sure you want to delete the currency named ":name"?', @@ -89,6 +100,7 @@ return [ 'permDeleteWarning' => 'Deleting stuff from Firely is permanent and cannot be undone.', 'also_delete_transactions' => 'The only transaction connected to this account will be deleted as well.|All :count transactions connected to this account will be deleted as well.', + 'also_delete_rules' => 'The only rule connected to this rule group will be deleted as well.|All :count rules connected to this rule group will be deleted as well.', 'also_delete_piggyBanks' => 'The only piggy bank connected to this account will be deleted as well.|All :count piggy bank connected to this account will be deleted as well.', 'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.|All :count transactions connected to this bill will spared deletion.', 'budget_keep_transactions' => 'The only transaction connected to this budget will not be deleted.|All :count transactions connected to this budget will spared deletion.', diff --git a/resources/lang/pt_BR/help.php b/resources/lang/pt_BR/help.php old mode 100644 new mode 100755 index ca6f66c753..99e2295f4f --- a/resources/lang/pt_BR/help.php +++ b/resources/lang/pt_BR/help.php @@ -20,74 +20,65 @@ return [ 'main-content-end-text' => 'Remember that every page has a small question mark at the right top. Click it to get help about the page you\'re on.', - 'register' => 'register', - 'index' => 'The main index', - 'home' => 'home', - 'flush' => 'flush', - 'accounts-index' => 'accounts.index', - 'accounts-create' => 'accounts.create', - 'accounts-edit' => 'accounts.edit', - 'accounts-delete' => 'accounts.delete', - 'accounts-show' => 'accounts.show', - 'bills-index' => 'bills.index', - 'bills-rescan' => 'bills.rescan', - 'bills-create' => 'bills.create', - 'bills-edit' => 'bills.edit', - 'bills-delete' => 'bills.delete', - 'bills-show' => 'bills.show', - 'budgets-index' => 'budgets.index', - 'budgets-income' => 'budgets.income', - 'budgets-create' => 'budgets.create', - 'budgets-edit' => 'budgets.edit', - 'budgets-delete' => 'budgets.delete', - 'budgets-show' => 'budgets.show', - 'budgets-noBudget' => 'budgets.noBudget', - 'categories-index' => 'categories.index', - 'categories-create' => 'categories.create', - 'categories-edit' => 'categories.edit', - 'categories-delete' => 'categories.delete', - 'categories-show' => 'categories.show', - 'categories-noCategory' => 'categories.noCategory', - 'csv-index' => 'Carregar e importar um arquivo CSV', - 'currency-index' => 'currency.index', - 'currency-create' => 'currency.create', - 'currency-edit' => 'currency.edit', - 'currency-delete' => 'currency.delete', - 'currency-default' => 'currency.default', - 'help-show' => 'help.show', - 'json-expense-accounts' => 'json.expense-accounts', - 'json-revenue-accounts' => 'json.revenue-accounts', - 'json-categories' => 'json.categories', - 'json-tags' => 'json.tags', - 'json-box-in' => 'json.box.in', - 'json-box-out' => 'json.box.out', - 'json-box-paid' => 'json.box.paid', - 'json-box-unpaid' => 'json.box.unpaid', - 'new-user-index' => 'new-user.index', - 'piggy-banks-index' => 'piggy-banks.index', - 'piggy-banks-addMoney' => 'piggy-banks.addMoney', - 'piggy-banks-removeMoney' => 'piggy-banks.removeMoney', - 'piggy-banks-create' => 'piggy-banks.create', - 'piggy-banks-edit' => 'piggy-banks.edit', - 'piggy-banks-delete' => 'piggy-banks.delete', - 'piggy-banks-show' => 'piggy-banks.show', - 'preferences' => 'preferences', - 'profile' => 'profile', - 'profile-change-password' => 'profile.change-password', - 'profile-delete-account' => 'profile.delete-account', - 'reports-index' => 'reports.index', - 'reports-year' => 'reports.year', - 'reports-month' => 'reports.month', - 'search' => 'search', - 'tags-index' => 'tags.index', - 'tags-create' => 'tags.create', - 'tags-show' => 'tags.show', - 'tags-edit' => 'tags.edit', - 'tags-delete' => 'tags.delete', - 'transactions-index' => 'transactions.index', - 'transactions-create' => 'transactions.create', - 'transactions-edit' => 'transactions.edit', - 'transactions-delete' => 'transactions.delete', - 'transactions-show' => 'transactions.show', - 'logout' => 'logout', + 'index' => 'index', + 'home' => 'home', + 'accounts-index' => 'accounts.index', + 'accounts-create' => 'accounts.create', + 'accounts-edit' => 'accounts.edit', + 'accounts-delete' => 'accounts.delete', + 'accounts-show' => 'accounts.show', + 'attachments-edit' => 'attachments.edit', + 'attachments-delete' => 'attachments.delete', + 'attachments-show' => 'attachments.show', + 'attachments-preview' => 'attachments.preview', + 'bills-index' => 'bills.index', + 'bills-create' => 'bills.create', + 'bills-edit' => 'bills.edit', + 'bills-delete' => 'bills.delete', + 'bills-show' => 'bills.show', + 'budgets-index' => 'budgets.index', + 'budgets-create' => 'budgets.create', + 'budgets-edit' => 'budgets.edit', + 'budgets-delete' => 'budgets.delete', + 'budgets-show' => 'budgets.show', + 'budgets-noBudget' => 'budgets.noBudget', + 'categories-index' => 'categories.index', + 'categories-create' => 'categories.create', + 'categories-edit' => 'categories.edit', + 'categories-delete' => 'categories.delete', + 'categories-show' => 'categories.show', + 'categories-show-date' => 'categories.show.date', + 'categories-noCategory' => 'categories.noCategory', + 'csv-index' => 'Carregar e importar um arquivo CSV', + 'csv-column-roles' => 'csv.column-roles', + 'csv-map' => 'csv.map', + 'csv-download-config-page' => 'csv.download-config-page', + 'csv-process' => 'csv.process', + 'currency-index' => 'currency.index', + 'currency-create' => 'currency.create', + 'currency-edit' => 'currency.edit', + 'currency-delete' => 'currency.delete', + 'new-user-index' => 'new-user.index', + 'piggy-banks-index' => 'piggy-banks.index', + 'piggy-banks-create' => 'piggy-banks.create', + 'piggy-banks-edit' => 'piggy-banks.edit', + 'piggy-banks-delete' => 'piggy-banks.delete', + 'piggy-banks-show' => 'piggy-banks.show', + 'preferences' => 'preferences', + 'profile' => 'profile', + 'profile-change-password' => 'profile.change-password', + 'profile-delete-account' => 'profile.delete-account', + 'reports-index' => 'reports.index', + 'reports-report' => 'reports.report', + 'search' => 'search', + 'tags-index' => 'tags.index', + 'tags-create' => 'tags.create', + 'tags-show' => 'tags.show', + 'tags-edit' => 'tags.edit', + 'tags-delete' => 'tags.delete', + 'transactions-index' => 'transactions.index', + 'transactions-create' => 'transactions.create', + 'transactions-edit' => 'transactions.edit', + 'transactions-delete' => 'transactions.delete', + 'transactions-show' => 'transactions.show', ]; diff --git a/resources/lang/pt_BR/list.php b/resources/lang/pt_BR/list.php old mode 100644 new mode 100755 diff --git a/resources/lang/pt_BR/pagination.php b/resources/lang/pt_BR/pagination.php old mode 100644 new mode 100755 diff --git a/resources/lang/pt_BR/passwords.php b/resources/lang/pt_BR/passwords.php old mode 100644 new mode 100755 index 7e45ef4749..fa70e900ba --- a/resources/lang/pt_BR/passwords.php +++ b/resources/lang/pt_BR/passwords.php @@ -1,4 +1,11 @@ "Este token de redefinição de senha é inválido.", "sent" => "Nós te enviamos um email com um link para trocar a senha!", "reset" => "Sua senha foi redefinida!", - 'blocked' => 'Nice try though.' + 'blocked' => 'Boa tentativa.', ]; diff --git a/resources/lang/pt_BR/validation.php b/resources/lang/pt_BR/validation.php index 7819d30ce1..daf771cd96 100755 --- a/resources/lang/pt_BR/validation.php +++ b/resources/lang/pt_BR/validation.php @@ -1,11 +1,13 @@ 'Due to security constraints, you cannot register from this domain.', - 'file_already_attached' => 'Uploaded file ":name" is already attached to this object.', - 'file_attached' => 'Succesfully uploaded file ":name".', - 'file_invalid_mime' => 'File ":name" is of type ":mime" which is not accepted as a new upload.', - 'file_too_large' => 'File ":name" is too large.', + 'rule_trigger_value' => 'Este valor é inválido para o disparo selecionado.', + 'rule_action_value' => 'Este valor é inválido para a ação selecionada.', + 'invalid_domain' => 'Devido a restrições de segurança, você não pode registrar deste domínio.', + 'file_already_attached' => 'Arquivo ":name" carregado já está anexado para este objeto.', + 'file_attached' => 'Arquivo carregado com sucesso ":name".', + 'file_invalid_mime' => 'Arquivo ":name" é do tipo ":mime" que não é aceito como um novo upload.', + 'file_too_large' => 'Arquivo ":name" é muito grande.', "accepted" => "O campo :attribute deve ser aceito.", "active_url" => "O campo :attribute não contém um URL válido.", "after" => "O campo :attribute deverá conter uma data posterior a :date.", @@ -13,10 +15,10 @@ return [ "alpha_dash" => "O campo :attribute deverá conter apenas letras, números e traços.", "alpha_num" => "O campo :attribute deverá conter apenas letras e números .", "array" => "O campo :attribute precisa ser um conjunto.", - "unique_for_user" => "There already is an entry with this :attribute.", + "unique_for_user" => "Já existe uma entrada com este :attribute.", "before" => "O campo :attribute deverá conter uma data anterior a :date.", - 'unique_object_for_user' => 'This name is already in use', - 'unique_account_for_user' => 'This account name is already in use', + 'unique_object_for_user' => 'Este nome já está em uso', + 'unique_account_for_user' => 'Este nome de conta já está em uso', "between.numeric" => "O campo :attribute deverá ter um valor entre :min - :max.", "between.file" => "O campo :attribute deverá ter um tamanho entre :min - :max kilobytes.", "between.string" => "O campo :attribute deverá conter entre :min - :max caracteres.", diff --git a/resources/twig/auth/password.twig b/resources/twig/auth/password.twig deleted file mode 100644 index ecbc5a7750..0000000000 --- a/resources/twig/auth/password.twig +++ /dev/null @@ -1,48 +0,0 @@ -{% extends "./layout/guest.twig" %} - -{% block content %} - - - {% if session.status %} -
    - {{ session.status }} -
    - {% endif %} - - {% if errors|length > 0 %} -
    - Whoops! There were some problems with your input.

    -
      - {% for error in errors.all %} -
    • {{ error }}
    • - {% endfor %} -
    -
    - {% endif %} - - - -{% endblock %} diff --git a/resources/twig/accounts/create.twig b/resources/views/accounts/create.twig similarity index 100% rename from resources/twig/accounts/create.twig rename to resources/views/accounts/create.twig diff --git a/resources/twig/accounts/delete.twig b/resources/views/accounts/delete.twig similarity index 100% rename from resources/twig/accounts/delete.twig rename to resources/views/accounts/delete.twig diff --git a/resources/twig/accounts/edit.twig b/resources/views/accounts/edit.twig similarity index 100% rename from resources/twig/accounts/edit.twig rename to resources/views/accounts/edit.twig diff --git a/resources/twig/accounts/index.twig b/resources/views/accounts/index.twig similarity index 100% rename from resources/twig/accounts/index.twig rename to resources/views/accounts/index.twig diff --git a/resources/twig/accounts/show.twig b/resources/views/accounts/show.twig similarity index 100% rename from resources/twig/accounts/show.twig rename to resources/views/accounts/show.twig diff --git a/resources/twig/attachments/delete.twig b/resources/views/attachments/delete.twig similarity index 100% rename from resources/twig/attachments/delete.twig rename to resources/views/attachments/delete.twig diff --git a/resources/twig/attachments/edit.twig b/resources/views/attachments/edit.twig similarity index 100% rename from resources/twig/attachments/edit.twig rename to resources/views/attachments/edit.twig diff --git a/resources/twig/auth/login.twig b/resources/views/auth/login.twig similarity index 88% rename from resources/twig/auth/login.twig rename to resources/views/auth/login.twig index 88e8d4554e..7390c87879 100644 --- a/resources/twig/auth/login.twig +++ b/resources/views/auth/login.twig @@ -17,7 +17,7 @@ {% endblock %} diff --git a/resources/views/auth/password.twig b/resources/views/auth/password.twig new file mode 100644 index 0000000000..20323c501f --- /dev/null +++ b/resources/views/auth/password.twig @@ -0,0 +1,57 @@ +{% extends "./layout/guest.twig" %} + +{% block content %} + + + {% if session.status %} +
    + {{ session.status }} +
    + {% endif %} + + {% if errors|length > 0 %} +
    + Whoops! There were some problems with your input.

    +
      + {% for error in errors.all %} +
    • {{ error }}
    • + {% endfor %} +
    +
    + {% endif %} + + + + + +{% endblock %} diff --git a/resources/twig/auth/register.twig b/resources/views/auth/register.twig similarity index 92% rename from resources/twig/auth/register.twig rename to resources/views/auth/register.twig index 03970a73b9..4d7ab7394a 100644 --- a/resources/twig/auth/register.twig +++ b/resources/views/auth/register.twig @@ -22,7 +22,7 @@ work for one (1) month.

    {% endif %} -
    +
    @@ -46,8 +46,8 @@
    - I want to login
    - I forgot my password + I want to login
    + I forgot my password
    {% endblock %} diff --git a/resources/twig/auth/reset.twig b/resources/views/auth/reset.twig similarity index 92% rename from resources/twig/auth/reset.twig rename to resources/views/auth/reset.twig index b4a64a9ac7..c70b06e8a8 100644 --- a/resources/twig/auth/reset.twig +++ b/resources/views/auth/reset.twig @@ -13,12 +13,9 @@
    {% endif %} - -
    - -
    + @@ -44,7 +41,7 @@
    - I want to login
    + I want to login
    {% if Config.get('auth.allow_register') %} Register a new account
    {% endif %} diff --git a/resources/twig/bills/create.twig b/resources/views/bills/create.twig similarity index 100% rename from resources/twig/bills/create.twig rename to resources/views/bills/create.twig diff --git a/resources/twig/bills/delete.twig b/resources/views/bills/delete.twig similarity index 100% rename from resources/twig/bills/delete.twig rename to resources/views/bills/delete.twig diff --git a/resources/twig/bills/edit.twig b/resources/views/bills/edit.twig similarity index 100% rename from resources/twig/bills/edit.twig rename to resources/views/bills/edit.twig diff --git a/resources/twig/bills/index.twig b/resources/views/bills/index.twig similarity index 100% rename from resources/twig/bills/index.twig rename to resources/views/bills/index.twig diff --git a/resources/twig/bills/show.twig b/resources/views/bills/show.twig similarity index 100% rename from resources/twig/bills/show.twig rename to resources/views/bills/show.twig diff --git a/resources/twig/budgets/create.twig b/resources/views/budgets/create.twig similarity index 100% rename from resources/twig/budgets/create.twig rename to resources/views/budgets/create.twig diff --git a/resources/twig/budgets/delete.twig b/resources/views/budgets/delete.twig similarity index 100% rename from resources/twig/budgets/delete.twig rename to resources/views/budgets/delete.twig diff --git a/resources/twig/budgets/edit.twig b/resources/views/budgets/edit.twig similarity index 100% rename from resources/twig/budgets/edit.twig rename to resources/views/budgets/edit.twig diff --git a/resources/twig/budgets/income.twig b/resources/views/budgets/income.twig similarity index 100% rename from resources/twig/budgets/income.twig rename to resources/views/budgets/income.twig diff --git a/resources/twig/budgets/index.twig b/resources/views/budgets/index.twig similarity index 100% rename from resources/twig/budgets/index.twig rename to resources/views/budgets/index.twig diff --git a/resources/twig/budgets/noBudget.twig b/resources/views/budgets/noBudget.twig similarity index 100% rename from resources/twig/budgets/noBudget.twig rename to resources/views/budgets/noBudget.twig diff --git a/resources/twig/budgets/show.twig b/resources/views/budgets/show.twig similarity index 100% rename from resources/twig/budgets/show.twig rename to resources/views/budgets/show.twig diff --git a/resources/twig/categories/create.twig b/resources/views/categories/create.twig similarity index 100% rename from resources/twig/categories/create.twig rename to resources/views/categories/create.twig diff --git a/resources/twig/categories/delete.twig b/resources/views/categories/delete.twig similarity index 100% rename from resources/twig/categories/delete.twig rename to resources/views/categories/delete.twig diff --git a/resources/twig/categories/edit.twig b/resources/views/categories/edit.twig similarity index 100% rename from resources/twig/categories/edit.twig rename to resources/views/categories/edit.twig diff --git a/resources/twig/categories/index.twig b/resources/views/categories/index.twig similarity index 100% rename from resources/twig/categories/index.twig rename to resources/views/categories/index.twig diff --git a/resources/twig/categories/noCategory.twig b/resources/views/categories/noCategory.twig similarity index 100% rename from resources/twig/categories/noCategory.twig rename to resources/views/categories/noCategory.twig diff --git a/resources/twig/categories/show.twig b/resources/views/categories/show.twig similarity index 100% rename from resources/twig/categories/show.twig rename to resources/views/categories/show.twig diff --git a/resources/twig/categories/show_with_date.twig b/resources/views/categories/show_with_date.twig similarity index 100% rename from resources/twig/categories/show_with_date.twig rename to resources/views/categories/show_with_date.twig diff --git a/resources/twig/csv/column-roles.twig b/resources/views/csv/column-roles.twig similarity index 100% rename from resources/twig/csv/column-roles.twig rename to resources/views/csv/column-roles.twig diff --git a/resources/twig/csv/download-config.twig b/resources/views/csv/download-config.twig similarity index 100% rename from resources/twig/csv/download-config.twig rename to resources/views/csv/download-config.twig diff --git a/resources/twig/csv/index.twig b/resources/views/csv/index.twig similarity index 94% rename from resources/twig/csv/index.twig rename to resources/views/csv/index.twig index 4bd88729ce..9749ac83a1 100644 --- a/resources/twig/csv/index.twig +++ b/resources/views/csv/index.twig @@ -55,10 +55,12 @@ {{ ExpandedForm.checkbox('has_headers',1,null,{helpText: 'csv_header_help'|_}) }} - {{ ExpandedForm.text('date_format','Ymd',{helpText: 'csv_date_help'|_}) }} + {{ ExpandedForm.text('date_format','Ymd',{helpText: trans('firefly.csv_date_help', {dateExample: phpdate('Ymd')}) }) }} {{ ExpandedForm.file('csv',{helpText: 'csv_csv_file_help'|_}) }} + {{ ExpandedForm.select('csv_delimiter', delimiters, 0, {helpText: 'csv_delimiter_help'|_} ) }} + {{ ExpandedForm.file('csv_config',{helpText: 'csv_csv_config_file_help'|_}) }} {{ ExpandedForm.select('csv_import_account', accounts, 0, {helpText: 'csv_import_account_help'|_} ) }} diff --git a/resources/twig/csv/map.twig b/resources/views/csv/map.twig similarity index 100% rename from resources/twig/csv/map.twig rename to resources/views/csv/map.twig diff --git a/resources/twig/csv/process.twig b/resources/views/csv/process.twig similarity index 100% rename from resources/twig/csv/process.twig rename to resources/views/csv/process.twig diff --git a/resources/twig/currency/create.twig b/resources/views/currency/create.twig similarity index 100% rename from resources/twig/currency/create.twig rename to resources/views/currency/create.twig diff --git a/resources/twig/currency/delete.twig b/resources/views/currency/delete.twig similarity index 100% rename from resources/twig/currency/delete.twig rename to resources/views/currency/delete.twig diff --git a/resources/twig/currency/edit.twig b/resources/views/currency/edit.twig similarity index 100% rename from resources/twig/currency/edit.twig rename to resources/views/currency/edit.twig diff --git a/resources/twig/currency/index.twig b/resources/views/currency/index.twig similarity index 85% rename from resources/twig/currency/index.twig rename to resources/views/currency/index.twig index 8449d1a9fa..f8fd9dbb50 100644 --- a/resources/twig/currency/index.twig +++ b/resources/views/currency/index.twig @@ -9,18 +9,18 @@
    -

    Currencies

    +

    {{ 'currencies'|_ }}

    - Firefly III supports various currencies which you can set and enable here. + {{ 'currencies_intro'|_ }}

    {% if currencies|length > 0 %} - + @@ -35,9 +35,9 @@ @@ -47,7 +47,7 @@ {% endif %} diff --git a/resources/twig/emails/password.twig b/resources/views/emails/password.twig similarity index 100% rename from resources/twig/emails/password.twig rename to resources/views/emails/password.twig diff --git a/resources/twig/emails/registered-html.twig b/resources/views/emails/registered-html.twig similarity index 93% rename from resources/twig/emails/registered-html.twig rename to resources/views/emails/registered-html.twig index 532322e75a..683ca0737a 100644 --- a/resources/twig/emails/registered-html.twig +++ b/resources/views/emails/registered-html.twig @@ -19,7 +19,7 @@
    • If you have forgotten your password already, please reset it using - the password reset tool. + the password reset tool.
    • There is a help-icon in the top right corner of each page. If you need help, click it! @@ -49,7 +49,7 @@ "potentialAction": { "@type": "ViewAction", "target": "https://geld.nder.be/", - "name": "Watch movie" + "name": "Visit Firefly III" }, "publisher": { "@type": "Organization", @@ -62,6 +62,7 @@ + diff --git a/resources/twig/emails/registered.twig b/resources/views/emails/registered.twig similarity index 95% rename from resources/twig/emails/registered.twig rename to resources/views/emails/registered.twig index 400ea17887..6ff499f117 100644 --- a/resources/twig/emails/registered.twig +++ b/resources/views/emails/registered.twig @@ -12,7 +12,7 @@ Firefly III: {{ address }} Password reset: -{{ address }}/password/email +{{ address }}/password/reset Documentation: https://github.com/JC5/firefly-iii/wiki/First-use diff --git a/resources/twig/error.twig b/resources/views/error.twig similarity index 100% rename from resources/twig/error.twig rename to resources/views/error.twig diff --git a/resources/twig/errors/404.twig b/resources/views/errors/404.twig similarity index 100% rename from resources/twig/errors/404.twig rename to resources/views/errors/404.twig diff --git a/resources/twig/errors/503.twig b/resources/views/errors/503.twig similarity index 100% rename from resources/twig/errors/503.twig rename to resources/views/errors/503.twig diff --git a/resources/twig/form/amount.twig b/resources/views/form/amount.twig similarity index 100% rename from resources/twig/form/amount.twig rename to resources/views/form/amount.twig diff --git a/resources/twig/form/balance.twig b/resources/views/form/balance.twig similarity index 100% rename from resources/twig/form/balance.twig rename to resources/views/form/balance.twig diff --git a/resources/twig/form/checkbox.twig b/resources/views/form/checkbox.twig similarity index 100% rename from resources/twig/form/checkbox.twig rename to resources/views/form/checkbox.twig diff --git a/resources/twig/form/date.twig b/resources/views/form/date.twig similarity index 100% rename from resources/twig/form/date.twig rename to resources/views/form/date.twig diff --git a/resources/twig/form/feedback.twig b/resources/views/form/feedback.twig similarity index 100% rename from resources/twig/form/feedback.twig rename to resources/views/form/feedback.twig diff --git a/resources/twig/form/file.twig b/resources/views/form/file.twig similarity index 100% rename from resources/twig/form/file.twig rename to resources/views/form/file.twig diff --git a/resources/twig/form/help.twig b/resources/views/form/help.twig similarity index 100% rename from resources/twig/form/help.twig rename to resources/views/form/help.twig diff --git a/resources/twig/form/integer.twig b/resources/views/form/integer.twig similarity index 100% rename from resources/twig/form/integer.twig rename to resources/views/form/integer.twig diff --git a/resources/twig/form/location.twig b/resources/views/form/location.twig similarity index 100% rename from resources/twig/form/location.twig rename to resources/views/form/location.twig diff --git a/resources/twig/form/multiCheckbox.twig b/resources/views/form/multiCheckbox.twig similarity index 100% rename from resources/twig/form/multiCheckbox.twig rename to resources/views/form/multiCheckbox.twig diff --git a/resources/twig/form/multiRadio.twig b/resources/views/form/multiRadio.twig similarity index 100% rename from resources/twig/form/multiRadio.twig rename to resources/views/form/multiRadio.twig diff --git a/resources/twig/form/options.twig b/resources/views/form/options.twig similarity index 100% rename from resources/twig/form/options.twig rename to resources/views/form/options.twig diff --git a/resources/twig/form/select.twig b/resources/views/form/select.twig similarity index 100% rename from resources/twig/form/select.twig rename to resources/views/form/select.twig diff --git a/resources/twig/form/static.twig b/resources/views/form/static.twig similarity index 100% rename from resources/twig/form/static.twig rename to resources/views/form/static.twig diff --git a/resources/twig/form/tags.twig b/resources/views/form/tags.twig similarity index 100% rename from resources/twig/form/tags.twig rename to resources/views/form/tags.twig diff --git a/resources/twig/form/text.twig b/resources/views/form/text.twig similarity index 100% rename from resources/twig/form/text.twig rename to resources/views/form/text.twig diff --git a/resources/twig/form/textarea.twig b/resources/views/form/textarea.twig similarity index 100% rename from resources/twig/form/textarea.twig rename to resources/views/form/textarea.twig diff --git a/resources/twig/index.twig b/resources/views/index.twig similarity index 100% rename from resources/twig/index.twig rename to resources/views/index.twig diff --git a/resources/twig/json/tour.twig b/resources/views/json/tour.twig similarity index 100% rename from resources/twig/json/tour.twig rename to resources/views/json/tour.twig diff --git a/resources/twig/layout/default.twig b/resources/views/layout/default.twig similarity index 100% rename from resources/twig/layout/default.twig rename to resources/views/layout/default.twig diff --git a/resources/twig/layout/empty.twig b/resources/views/layout/empty.twig similarity index 100% rename from resources/twig/layout/empty.twig rename to resources/views/layout/empty.twig diff --git a/resources/twig/layout/guest.twig b/resources/views/layout/guest.twig similarity index 100% rename from resources/twig/layout/guest.twig rename to resources/views/layout/guest.twig diff --git a/resources/twig/list/accounts.twig b/resources/views/list/accounts.twig similarity index 100% rename from resources/twig/list/accounts.twig rename to resources/views/list/accounts.twig diff --git a/resources/twig/list/bills.twig b/resources/views/list/bills.twig similarity index 100% rename from resources/twig/list/bills.twig rename to resources/views/list/bills.twig diff --git a/resources/twig/list/categories.twig b/resources/views/list/categories.twig similarity index 100% rename from resources/twig/list/categories.twig rename to resources/views/list/categories.twig diff --git a/resources/twig/list/journals-tiny.twig b/resources/views/list/journals-tiny.twig similarity index 100% rename from resources/twig/list/journals-tiny.twig rename to resources/views/list/journals-tiny.twig diff --git a/resources/twig/list/journals.twig b/resources/views/list/journals.twig similarity index 100% rename from resources/twig/list/journals.twig rename to resources/views/list/journals.twig diff --git a/resources/twig/list/piggy-bank-events.twig b/resources/views/list/piggy-bank-events.twig similarity index 100% rename from resources/twig/list/piggy-bank-events.twig rename to resources/views/list/piggy-bank-events.twig diff --git a/resources/twig/list/piggy-banks.twig b/resources/views/list/piggy-banks.twig similarity index 100% rename from resources/twig/list/piggy-banks.twig rename to resources/views/list/piggy-banks.twig diff --git a/resources/twig/new-user/index.twig b/resources/views/new-user/index.twig similarity index 100% rename from resources/twig/new-user/index.twig rename to resources/views/new-user/index.twig diff --git a/resources/twig/partials/boxes.twig b/resources/views/partials/boxes.twig similarity index 100% rename from resources/twig/partials/boxes.twig rename to resources/views/partials/boxes.twig diff --git a/resources/twig/partials/control-bar.twig b/resources/views/partials/control-bar.twig similarity index 100% rename from resources/twig/partials/control-bar.twig rename to resources/views/partials/control-bar.twig diff --git a/resources/twig/partials/flashes.twig b/resources/views/partials/flashes.twig similarity index 100% rename from resources/twig/partials/flashes.twig rename to resources/views/partials/flashes.twig diff --git a/resources/twig/partials/menu-sidebar.twig b/resources/views/partials/menu-sidebar.twig similarity index 95% rename from resources/twig/partials/menu-sidebar.twig rename to resources/views/partials/menu-sidebar.twig index 3c900ab06d..1683986cbc 100644 --- a/resources/twig/partials/menu-sidebar.twig +++ b/resources/views/partials/menu-sidebar.twig @@ -86,7 +86,7 @@
    • -
    • +
    • {{ 'moneyManagement'|_ }} @@ -101,6 +101,10 @@ {{ 'bills'|_ }}
    • +
    • + + {{ 'rules'|_ }} +
    diff --git a/resources/twig/partials/page-header.twig b/resources/views/partials/page-header.twig similarity index 100% rename from resources/twig/partials/page-header.twig rename to resources/views/partials/page-header.twig diff --git a/resources/twig/piggy-banks/add.twig b/resources/views/piggy-banks/add.twig similarity index 100% rename from resources/twig/piggy-banks/add.twig rename to resources/views/piggy-banks/add.twig diff --git a/resources/twig/piggy-banks/create.twig b/resources/views/piggy-banks/create.twig similarity index 100% rename from resources/twig/piggy-banks/create.twig rename to resources/views/piggy-banks/create.twig diff --git a/resources/twig/piggy-banks/delete.twig b/resources/views/piggy-banks/delete.twig similarity index 100% rename from resources/twig/piggy-banks/delete.twig rename to resources/views/piggy-banks/delete.twig diff --git a/resources/twig/piggy-banks/edit.twig b/resources/views/piggy-banks/edit.twig similarity index 100% rename from resources/twig/piggy-banks/edit.twig rename to resources/views/piggy-banks/edit.twig diff --git a/resources/twig/piggy-banks/index.twig b/resources/views/piggy-banks/index.twig similarity index 100% rename from resources/twig/piggy-banks/index.twig rename to resources/views/piggy-banks/index.twig diff --git a/resources/twig/piggy-banks/remove.twig b/resources/views/piggy-banks/remove.twig similarity index 100% rename from resources/twig/piggy-banks/remove.twig rename to resources/views/piggy-banks/remove.twig diff --git a/resources/twig/piggy-banks/show.twig b/resources/views/piggy-banks/show.twig similarity index 100% rename from resources/twig/piggy-banks/show.twig rename to resources/views/piggy-banks/show.twig diff --git a/resources/twig/preferences/index.twig b/resources/views/preferences/index.twig similarity index 100% rename from resources/twig/preferences/index.twig rename to resources/views/preferences/index.twig diff --git a/resources/twig/profile/change-password.twig b/resources/views/profile/change-password.twig similarity index 100% rename from resources/twig/profile/change-password.twig rename to resources/views/profile/change-password.twig diff --git a/resources/twig/profile/delete-account.twig b/resources/views/profile/delete-account.twig similarity index 100% rename from resources/twig/profile/delete-account.twig rename to resources/views/profile/delete-account.twig diff --git a/resources/twig/profile/index.twig b/resources/views/profile/index.twig similarity index 100% rename from resources/twig/profile/index.twig rename to resources/views/profile/index.twig diff --git a/resources/twig/reminders/index.twig b/resources/views/reminders/index.twig similarity index 100% rename from resources/twig/reminders/index.twig rename to resources/views/reminders/index.twig diff --git a/resources/twig/reminders/show.twig b/resources/views/reminders/show.twig similarity index 100% rename from resources/twig/reminders/show.twig rename to resources/views/reminders/show.twig diff --git a/resources/twig/reports/default/month.twig b/resources/views/reports/default/month.twig similarity index 100% rename from resources/twig/reports/default/month.twig rename to resources/views/reports/default/month.twig diff --git a/resources/twig/reports/default/multi-year.twig b/resources/views/reports/default/multi-year.twig similarity index 100% rename from resources/twig/reports/default/multi-year.twig rename to resources/views/reports/default/multi-year.twig diff --git a/resources/twig/reports/default/year.twig b/resources/views/reports/default/year.twig similarity index 100% rename from resources/twig/reports/default/year.twig rename to resources/views/reports/default/year.twig diff --git a/resources/twig/reports/index.twig b/resources/views/reports/index.twig similarity index 94% rename from resources/twig/reports/index.twig rename to resources/views/reports/index.twig index 93ca24c200..9be5d59c57 100644 --- a/resources/twig/reports/index.twig +++ b/resources/views/reports/index.twig @@ -95,16 +95,16 @@
  • {{ 'report_this_month_quick'|_ }}
  • {{ 'report_this_year_quick'|_ }}
  • @@ -112,7 +112,7 @@ {{ 'report_all_time_quick'|_ }} @@ -131,7 +131,7 @@ {% block scripts %} diff --git a/resources/twig/reports/partials/accounts.twig b/resources/views/reports/partials/accounts.twig similarity index 100% rename from resources/twig/reports/partials/accounts.twig rename to resources/views/reports/partials/accounts.twig diff --git a/resources/twig/reports/partials/balance.twig b/resources/views/reports/partials/balance.twig similarity index 100% rename from resources/twig/reports/partials/balance.twig rename to resources/views/reports/partials/balance.twig diff --git a/resources/twig/reports/partials/bills.twig b/resources/views/reports/partials/bills.twig similarity index 100% rename from resources/twig/reports/partials/bills.twig rename to resources/views/reports/partials/bills.twig diff --git a/resources/twig/reports/partials/budgets.twig b/resources/views/reports/partials/budgets.twig similarity index 100% rename from resources/twig/reports/partials/budgets.twig rename to resources/views/reports/partials/budgets.twig diff --git a/resources/twig/reports/partials/categories.twig b/resources/views/reports/partials/categories.twig similarity index 100% rename from resources/twig/reports/partials/categories.twig rename to resources/views/reports/partials/categories.twig diff --git a/resources/twig/reports/partials/expenses.twig b/resources/views/reports/partials/expenses.twig similarity index 100% rename from resources/twig/reports/partials/expenses.twig rename to resources/views/reports/partials/expenses.twig diff --git a/resources/twig/reports/partials/income-vs-expenses.twig b/resources/views/reports/partials/income-vs-expenses.twig similarity index 100% rename from resources/twig/reports/partials/income-vs-expenses.twig rename to resources/views/reports/partials/income-vs-expenses.twig diff --git a/resources/twig/reports/partials/income.twig b/resources/views/reports/partials/income.twig similarity index 100% rename from resources/twig/reports/partials/income.twig rename to resources/views/reports/partials/income.twig diff --git a/resources/views/rules/index.twig b/resources/views/rules/index.twig new file mode 100644 index 0000000000..546e74043b --- /dev/null +++ b/resources/views/rules/index.twig @@ -0,0 +1,199 @@ +{% extends "./layout/default.twig" %} +{% block breadcrumbs %} + {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }} +{% endblock %} +{% block content %} + +
    +
    +
    +
    +

    {{ 'rules'|_ }}

    + +
    + +
    +
    +
    +

    + {{ 'rules_explanation'|_ }} +

    +
    +
    +
    +
    + + {% for ruleGroup in ruleGroups %} +
    +
    +
    +
    +

    + {% if ruleGroup.active %} + {{ ruleGroup.title }} + {% else %} + {{ ruleGroup.title }} (inactive) + {% endif %} +

    + + +
    + +
    + + +
    +
    + +
    +
    +

    + {{ ruleGroup.description }} +

    + + {% if ruleGroup.rules.count > 0 %} +
     Currency{{ 'currency'|_ }}
    {{ currency.name }} ({{ currency.code }}) ({{ currency.symbol|raw }}) {% if currency.id == defaultCurrency.id %} - default + {{ 'default_currency'|_ }} {% else %} - make default + {{ 'make_default_currency'|_ }} {% endif %}
    + + + + + + + + + {% for rule in ruleGroup.rules %} + + + + + + + {% endfor %} + +
    {{ 'rule_name'|_ }}{{ 'rule_triggers'|_ }}{{ 'rule_actions'|_ }}
    +
    + {% if rule.order > 1 %} + + {% else %} + + {% endif %} + {% if rule.order < ruleGroup.rules.count %} + + + {% else %} + + {% endif %} + + +
    + +
    + {% if rule.active %} + {{ rule.title }} + {% else %} + {{ rule.title }} (inactive) + {% endif %} + {% if rule.stop_processing %} + + {% endif %} + + {% if rule.description != "" %} +
    {{ rule.description }}
    + {% endif %} + +
    + {% if rule.ruleTriggers.count > 0 %} +
      + {% for trigger in rule.ruleTriggers %} + {% if trigger.trigger_type != "user_action" %} +
    • {{ trans(('firefly.rule_trigger_' ~ trigger.trigger_type), {trigger_value: trigger.trigger_value}) }} + + {% if trigger.stop_processing %} + + {% endif %} +
    • + {% endif %} + {% endfor %} +
    + {% endif %} +
    + {% if rule.ruleActions.count > 0 %} +
      + {% for action in rule.ruleActions %} +
    • {{ trans(('firefly.rule_action_' ~ action.action_type), {action_value: action.action_value}) }} + {% if action.stop_processing %} + + {% endif %} +
    • + {% endfor %} +
    + {% endif %} +
    + {% else %} +

    + {{ 'no_rules_in_group'|_ }} +

    + {% endif %} +

    +
    + {{ 'new_rule'|_ }} +

    +
    +
    +
    +
    + {% endfor %} + + + +{% endblock %} +{% block scripts %} + + +{% endblock %} \ No newline at end of file diff --git a/resources/views/rules/partials/action.twig b/resources/views/rules/partials/action.twig new file mode 100644 index 0000000000..1e5d1247bc --- /dev/null +++ b/resources/views/rules/partials/action.twig @@ -0,0 +1,40 @@ + + + + + + {% if errors.has('rule-action.'~count) %} + +

    {{ errors.first('rule-action.'~count) }}

    + {% endif %} + + + + + + + {% if errors.has(('rule-action-value.'~count)) %} +

    + {{ errors.first('rule-action-value.'~count) }} +

    + {% endif %} + + +
    + +
    + + \ No newline at end of file diff --git a/resources/views/rules/partials/trigger.twig b/resources/views/rules/partials/trigger.twig new file mode 100644 index 0000000000..bc5df80649 --- /dev/null +++ b/resources/views/rules/partials/trigger.twig @@ -0,0 +1,40 @@ + + + + + + {% if errors.has('rule-trigger.'~count) %} + +

    {{ errors.first('rule-trigger.'~count) }}

    + {% endif %} + + + + + + + {% if errors.has(('rule-trigger-value.'~count)) %} +

    + {{ errors.first('rule-trigger-value.'~count) }} +

    + {% endif %} + + +
    + +
    + + \ No newline at end of file diff --git a/resources/views/rules/rule-group/create.twig b/resources/views/rules/rule-group/create.twig new file mode 100644 index 0000000000..4bff91f4f3 --- /dev/null +++ b/resources/views/rules/rule-group/create.twig @@ -0,0 +1,51 @@ +{% extends "./layout/default.twig" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }} +{% endblock %} + +{% block content %} + {{ Form.open({'class' : 'form-horizontal','id' : 'store','url' : route('rules.rule-group.store')}) }} +
    +
    +
    +
    +

    {{ 'mandatoryFields'|_ }}

    +
    +
    + {{ ExpandedForm.text('title') }} +
    +
    +
    +
    + + +
    +
    +

    {{ 'optionalFields'|_ }}

    +
    +
    + {{ ExpandedForm.textarea('description') }} +
    +
    + + +
    +
    +

    {{ 'options'|_ }}

    +
    +
    + {{ ExpandedForm.optionsList('create','rule-group') }} +
    + +
    + +
    + +
    + {{ Form.close|raw }} + + +{% endblock %} diff --git a/resources/views/rules/rule-group/delete.twig b/resources/views/rules/rule-group/delete.twig new file mode 100644 index 0000000000..17aa5a2bd5 --- /dev/null +++ b/resources/views/rules/rule-group/delete.twig @@ -0,0 +1,53 @@ +{% extends "./layout/default.twig" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, ruleGroup) }} +{% endblock %} + +{% block content %} + {{ Form.open({'class' : 'form-horizontal','id' : 'destroy','url' : route('rules.rule-group.destroy',ruleGroup.id) }) }} +
    +
    +
    +
    +

    {{ trans('form.delete_rule_group', {'title': ruleGroup.title}) }}

    +
    +
    +

    + {{ trans('form.permDeleteWarning') }} +

    + +

    + {{ trans('form.ruleGroup_areYouSure', {'title': ruleGroup.title}) }} +

    + +

    + {% if ruleGroup.rules|length > 0 %} + {{ Lang.choice('form.also_delete_rules', ruleGroup.rules|length, {count: ruleGroup.rules|length}) }} + {% endif %} +

    + + {% if ruleGroup.rules|length > 0 %} +

    + {{ 'save_rules_by_moving'|_ }} +

    + +

    + {{ Form.select('move_rules_before_delete', ruleGroupList, null, {class: 'form-control'}) }} +

    + {% else %} + + {% endif %} + +
    + + + +
    +
    +
    + {{ Form.close|raw }} +{% endblock %} diff --git a/resources/views/rules/rule-group/edit.twig b/resources/views/rules/rule-group/edit.twig new file mode 100644 index 0000000000..4156879820 --- /dev/null +++ b/resources/views/rules/rule-group/edit.twig @@ -0,0 +1,52 @@ +{% extends "./layout/default.twig" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, ruleGroup) }} +{% endblock %} + +{% block content %} + {{ Form.model(ruleGroup, {'class' : 'form-horizontal','id' : 'update','url' : route('rules.rule-group.update',ruleGroup.id) } ) }} + +
    +
    +
    +
    +

    {{ 'mandatoryFields'|_ }}

    +
    +
    + {{ ExpandedForm.checkbox('active') }} + {{ ExpandedForm.text('title') }} +
    +
    + +
    +
    + + +
    +
    +

    {{ 'optionalFields'|_ }}

    +
    +
    + {{ ExpandedForm.textarea('description') }} +
    +
    + + +
    +
    +

    {{ 'options'|_ }}

    +
    +
    + {{ ExpandedForm.optionsList('update','rule-group') }} +
    + +
    +
    +
    + + {{ Form.close|raw }} + +{% endblock %} diff --git a/resources/views/rules/rule/create.twig b/resources/views/rules/rule/create.twig new file mode 100644 index 0000000000..87a8482e2a --- /dev/null +++ b/resources/views/rules/rule/create.twig @@ -0,0 +1,131 @@ +{% extends "./layout/default.twig" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }} +{% endblock %} + +{% block content %} + {{ Form.open({'class' : 'form-horizontal','id' : 'store','url' : route('rules.rule.store', ruleGroup.id)}) }} + +
    +
    +
    +
    +

    {{ 'mandatoryFields'|_ }}

    +
    +
    + {{ ExpandedForm.text('title') }} + {{ ExpandedForm.select('trigger',allJournalTriggers()) }} + {{ ExpandedForm.checkbox('stop_processing',1,null, {helpText: trans('firefly.rule_help_stop_processing')}) }} +
    +
    +
    +
    + + +
    +
    +

    {{ 'optionalFields'|_ }}

    +
    +
    + {{ ExpandedForm.textarea('description') }} +
    +
    +
    +
    + + +
    +
    +
    +
    +

    {{ 'rule_triggers'|_ }}

    +
    + +
    + + + + + + + + + + {% for trigger in oldTriggers %} + {{ trigger|raw }} + {% endfor %} + + +
    {{ 'trigger'|_ }}{{ 'trigger_value'|_ }}{{ 'stop_processing_other_triggers'|_ }}
    +

    +
    + {{ 'add_rule_trigger'|_ }} +

    +
    +
    +
    +
    + + +
    +
    +
    +
    +

    {{ 'rule_actions'|_ }}

    +
    +
    + + + + + + + + + + {% for action in oldActions %} + {{ action|raw }} + {% endfor %} + + +
    {{ 'action'|_ }}{{ 'action_value'|_ }}{{ 'stop_executing_other_actions'|_ }}
    +

    +
    + {{ 'add_rule_action'|_ }} +

    +
    +
    +
    +
    + +
    +
    + +
    +
    +

    {{ 'options'|_ }}

    +
    +
    + {{ ExpandedForm.optionsList('create','rule') }} +
    + +
    + +
    + +
    + {{ Form.close|raw }} + + +{% endblock %} +{% block scripts %} + + + +{% endblock %} diff --git a/resources/views/rules/rule/delete.twig b/resources/views/rules/rule/delete.twig new file mode 100644 index 0000000000..c468dcfa47 --- /dev/null +++ b/resources/views/rules/rule/delete.twig @@ -0,0 +1,32 @@ +{% extends "./layout/default.twig" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, rule) }} +{% endblock %} + +{% block content %} + {{ Form.open({'class' : 'form-horizontal','id' : 'destroy','url' : route('rules.rule.destroy',rule.id) }) }} +
    +
    +
    +
    +

    {{ trans('form.delete_rule', {'title': rule.title}) }}

    +
    +
    +

    + {{ trans('form.permDeleteWarning') }} +

    + +

    + {{ trans('form.rule_areYouSure', {'title': rule.title}) }} +

    +
    + +
    +
    +
    + {{ Form.close|raw }} +{% endblock %} diff --git a/resources/views/rules/rule/edit.twig b/resources/views/rules/rule/edit.twig new file mode 100644 index 0000000000..e14ac079d5 --- /dev/null +++ b/resources/views/rules/rule/edit.twig @@ -0,0 +1,132 @@ +{% extends "./layout/default.twig" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }} +{% endblock %} + +{% block content %} + {{ Form.model(rule, {'class' : 'form-horizontal','id' : 'store','url' : route('rules.rule.update', rule.id)}) }} + +
    +
    +
    +
    +

    {{ 'mandatoryFields'|_ }}

    +
    +
    + {{ ExpandedForm.text('title') }} + {{ ExpandedForm.select('trigger',allJournalTriggers(), primaryTrigger) }} + {{ ExpandedForm.checkbox('active',1,rule.active, {helpText: trans('firefly.rule_help_active')}) }} + {{ ExpandedForm.checkbox('stop_processing',1,rule.stop_processing, {helpText: trans('firefly.rule_help_stop_processing')}) }} +
    +
    +
    +
    + + +
    +
    +

    {{ 'optionalFields'|_ }}

    +
    +
    + {{ ExpandedForm.textarea('description') }} +
    +
    +
    +
    + + +
    +
    +
    +
    +

    {{ 'rule_triggers'|_ }}

    +
    + +
    + + + + + + + + + + {% for trigger in oldTriggers %} + {{ trigger|raw }} + {% endfor %} + + +
    {{ 'trigger'|_ }}{{ 'trigger_value'|_ }}{{ 'stop_processing_other_triggers'|_ }}
    +

    +
    + {{ 'add_rule_trigger'|_ }} +

    +
    +
    +
    +
    + + +
    +
    +
    +
    +

    {{ 'rule_actions'|_ }}

    +
    +
    + + + + + + + + + + {% for action in oldActions %} + {{ action|raw }} + {% endfor %} + + +
    {{ 'action'|_ }}{{ 'action_value'|_ }}{{ 'stop_executing_other_actions'|_ }}
    +

    +
    + {{ 'add_rule_action'|_ }} +

    +
    +
    +
    +
    + +
    +
    + +
    +
    +

    {{ 'options'|_ }}

    +
    +
    + {{ ExpandedForm.optionsList('update','rule') }} +
    + +
    + +
    + +
    + {{ Form.close|raw }} + + +{% endblock %} +{% block scripts %} + + + +{% endblock %} diff --git a/resources/twig/search/index.twig b/resources/views/search/index.twig similarity index 100% rename from resources/twig/search/index.twig rename to resources/views/search/index.twig diff --git a/resources/twig/tags/create.twig b/resources/views/tags/create.twig similarity index 100% rename from resources/twig/tags/create.twig rename to resources/views/tags/create.twig diff --git a/resources/twig/tags/delete.twig b/resources/views/tags/delete.twig similarity index 100% rename from resources/twig/tags/delete.twig rename to resources/views/tags/delete.twig diff --git a/resources/twig/tags/edit.twig b/resources/views/tags/edit.twig similarity index 100% rename from resources/twig/tags/edit.twig rename to resources/views/tags/edit.twig diff --git a/resources/twig/tags/index.twig b/resources/views/tags/index.twig similarity index 100% rename from resources/twig/tags/index.twig rename to resources/views/tags/index.twig diff --git a/resources/twig/tags/show.twig b/resources/views/tags/show.twig similarity index 100% rename from resources/twig/tags/show.twig rename to resources/views/tags/show.twig diff --git a/resources/twig/transactions/create.twig b/resources/views/transactions/create.twig similarity index 100% rename from resources/twig/transactions/create.twig rename to resources/views/transactions/create.twig diff --git a/resources/twig/transactions/delete.twig b/resources/views/transactions/delete.twig similarity index 100% rename from resources/twig/transactions/delete.twig rename to resources/views/transactions/delete.twig diff --git a/resources/twig/transactions/edit.twig b/resources/views/transactions/edit.twig similarity index 100% rename from resources/twig/transactions/edit.twig rename to resources/views/transactions/edit.twig diff --git a/resources/twig/transactions/index.twig b/resources/views/transactions/index.twig similarity index 100% rename from resources/twig/transactions/index.twig rename to resources/views/transactions/index.twig diff --git a/resources/twig/transactions/show.twig b/resources/views/transactions/show.twig similarity index 100% rename from resources/twig/transactions/show.twig rename to resources/views/transactions/show.twig diff --git a/resources/views/vendor/.gitkeep b/resources/views/vendor/.gitkeep new file mode 100755 index 0000000000..e69de29bb2 diff --git a/server.php b/server.php old mode 100644 new mode 100755 index c6499cf326..f65c7c444f --- a/server.php +++ b/server.php @@ -1,4 +1,5 @@ assertTrue(true); + + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php old mode 100644 new mode 100755 index c5a49310ed..9ed7149f88 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,10 +1,17 @@ make('Illuminate\Contracts\Console\Kernel')->bootstrap(); + $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); return $app; } + /** + * @return User + */ + public function emptyUser() + { + return User::find(2); + } + /** * Sets up the fixture, for example, opens a network connection. * This method is called before a test is executed. @@ -28,16 +43,37 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase public function setUp() { parent::setUp(); - } - /** - * This method is called before the first test of this test class is run. - * - * @since Method available since Release 3.4.0 - */ - public static function setUpBeforeClass() - { - parent::setUpBeforeClass(); + // if the database copy does not exist, call migrate. + $copy = storage_path('database') . '/testing-copy.db'; + $original = storage_path('database') . '/testing.db'; + + // move .env file over? + if (!file_exists($copy)) { + + // maybe original does? + if (!file_exists($original)) { + touch($original); + Artisan::call('migrate', ['--seed' => true]); + } + + copy($original, $copy); + } else { + if (file_exists($copy)) { + copy($copy, $original); + } + } + // if the database copy does exists, copy back as original. + + $this->session( + [ + 'start' => Carbon::now()->startOfMonth(), + 'end' => Carbon::now()->endOfMonth(), + 'first' => Carbon::now()->startOfYear(), + ] + ); + + } /** @@ -47,5 +83,35 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase public function tearDown() { parent::tearDown(); + + // delete copy original. + //$original = __DIR__.'/../storage/database/testing.db'; + //unlink($original); + } + + /** + * @return User + */ + public function user() + { + return User::find(1); + } + + /** + * @param string $class + * + * @return \Mockery\MockInterface + */ + protected function mock($class) + { + $object = Mockery::mock($class); + + + $this->app->instance($class, $object); + + return $object; + } + + } diff --git a/tests/_bootstrap.php b/tests/_bootstrap.php deleted file mode 100644 index 243f9c85bc..0000000000 --- a/tests/_bootstrap.php +++ /dev/null @@ -1,2 +0,0 @@ -setHeader('X-Requested-With', 'Codeception'); - * $I->amOnPage('test-headers.php'); - * ?> - * ``` - * - * @param string $name the name of the request header - * @param string $value the value to set it to for subsequent - * requests - * @see \Codeception\Module\PhpBrowser::setHeader() - */ - public function setHeader($name, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('setHeader', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Deletes the header with the passed name. Subsequent requests - * will not have the deleted header in its request. - * - * Example: - * ```php - * setHeader('X-Requested-With', 'Codeception'); - * $I->amOnPage('test-headers.php'); - * // ... - * $I->deleteHeader('X-Requested-With'); - * $I->amOnPage('some-other-page.php'); - * ?> - * ``` - * - * @param string $name the name of the header to delete. - * @see \Codeception\Module\PhpBrowser::deleteHeader() - */ - public function deleteHeader($name) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('deleteHeader', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Authenticates user for HTTP_AUTH - * - * @param $username - * @param $password - * @see \Codeception\Module\PhpBrowser::amHttpAuthenticated() - */ - public function amHttpAuthenticated($username, $password) { - return $this->getScenario()->runStep(new \Codeception\Step\Condition('amHttpAuthenticated', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Open web page at the given absolute URL and sets its hostname as the base host. - * - * ``` php - * amOnUrl('http://codeception.com'); - * $I->amOnPage('/quickstart'); // moves to http://codeception.com/quickstart - * ?> - * ``` - * @see \Codeception\Module\PhpBrowser::amOnUrl() - */ - public function amOnUrl($url) { - return $this->getScenario()->runStep(new \Codeception\Step\Condition('amOnUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Changes the subdomain for the 'url' configuration parameter. - * Does not open a page; use `amOnPage` for that. - * - * ``` php - * amOnSubdomain('user'); - * $I->amOnPage('/'); - * // moves to http://user.mysite.com/ - * ?> - * ``` - * - * @param $subdomain - * - * @return mixed - * @see \Codeception\Module\PhpBrowser::amOnSubdomain() - */ - public function amOnSubdomain($subdomain) { - return $this->getScenario()->runStep(new \Codeception\Step\Condition('amOnSubdomain', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Low-level API method. - * If Codeception commands are not enough, use [Guzzle HTTP Client](http://guzzlephp.org/) methods directly - * - * Example: - * - * ``` php - * executeInGuzzle(function (\GuzzleHttp\Client $client) { - * $client->get('/get', ['query' => ['foo' => 'bar']]); - * }); - * ?> - * ``` - * - * It is not recommended to use this command on a regular basis. - * If Codeception lacks important Guzzle Client methods, implement them and submit patches. - * - * @param callable $function - * @see \Codeception\Module\PhpBrowser::executeInGuzzle() - */ - public function executeInGuzzle($function) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('executeInGuzzle', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Opens the page for the given relative URI. - * - * ``` php - * amOnPage('/'); - * // opens /register page - * $I->amOnPage('/register'); - * ?> - * ``` - * - * @param $page - * @see \Codeception\Lib\InnerBrowser::amOnPage() - */ - public function amOnPage($page) { - return $this->getScenario()->runStep(new \Codeception\Step\Condition('amOnPage', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Perform a click on a link or a button, given by a locator. - * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. - * For buttons, the "value" attribute, "name" attribute, and inner text are searched. - * For links, the link text is searched. - * For images, the "alt" attribute and inner text of any parent links are searched. - * - * The second parameter is a context (CSS or XPath locator) to narrow the search. - * - * Note that if the locator matches a button of type `submit`, the form will be submitted. - * - * ``` php - * click('Logout'); - * // button of form - * $I->click('Submit'); - * // CSS button - * $I->click('#form input[type=submit]'); - * // XPath - * $I->click('//form/*[@type=submit]'); - * // link in context - * $I->click('Logout', '#nav'); - * // using strict locator - * $I->click(['link' => 'Login']); - * ?> - * ``` - * - * @param $link - * @param $context - * @see \Codeception\Lib\InnerBrowser::click() - */ - public function click($link, $context = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('click', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page contains the given string. - * Specify a locator as the second parameter to match a specific region. - * - * ``` php - * see('Logout'); // I can suppose user is logged in - * $I->see('Sign Up','h1'); // I can suppose it's a signup page - * $I->see('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::see() - */ - public function canSee($text, $selector = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('see', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page contains the given string. - * Specify a locator as the second parameter to match a specific region. - * - * ``` php - * see('Logout'); // I can suppose user is logged in - * $I->see('Sign Up','h1'); // I can suppose it's a signup page - * $I->see('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * @see \Codeception\Lib\InnerBrowser::see() - */ - public function see($text, $selector = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('see', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page doesn't contain the text specified. - * Give a locator as the second parameter to match a specific region. - * - * ```php - * dontSee('Login'); // I can suppose user is already logged in - * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page - * $I->dontSee('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSee() - */ - public function cantSee($text, $selector = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSee', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page doesn't contain the text specified. - * Give a locator as the second parameter to match a specific region. - * - * ```php - * dontSee('Login'); // I can suppose user is already logged in - * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page - * $I->dontSee('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * @see \Codeception\Lib\InnerBrowser::dontSee() - */ - public function dontSee($text, $selector = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSee', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there's a link with the specified text. - * Give a full URL as the second parameter to match links with that exact URL. - * - * ``` php - * seeLink('Logout'); // matches Logout - * $I->seeLink('Logout','/logout'); // matches Logout - * ?> - * ``` - * - * @param $text - * @param null $url - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeLink() - */ - public function canSeeLink($text, $url = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeLink', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there's a link with the specified text. - * Give a full URL as the second parameter to match links with that exact URL. - * - * ``` php - * seeLink('Logout'); // matches Logout - * $I->seeLink('Logout','/logout'); // matches Logout - * ?> - * ``` - * - * @param $text - * @param null $url - * @see \Codeception\Lib\InnerBrowser::seeLink() - */ - public function seeLink($text, $url = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeLink', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page doesn't contain a link with the given string. - * If the second parameter is given, only links with a matching "href" attribute will be checked. - * - * ``` php - * dontSeeLink('Logout'); // I suppose user is not logged in - * $I->dontSeeLink('Checkout now', '/store/cart.php'); - * ?> - * ``` - * - * @param $text - * @param null $url - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeLink() - */ - public function cantSeeLink($text, $url = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeLink', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page doesn't contain a link with the given string. - * If the second parameter is given, only links with a matching "href" attribute will be checked. - * - * ``` php - * dontSeeLink('Logout'); // I suppose user is not logged in - * $I->dontSeeLink('Checkout now', '/store/cart.php'); - * ?> - * ``` - * - * @param $text - * @param null $url - * @see \Codeception\Lib\InnerBrowser::dontSeeLink() - */ - public function dontSeeLink($text, $url = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeLink', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current URI contains the given string. - * - * ``` php - * seeInCurrentUrl('home'); - * // to match: /users/1 - * $I->seeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInCurrentUrl() - */ - public function canSeeInCurrentUrl($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInCurrentUrl', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current URI contains the given string. - * - * ``` php - * seeInCurrentUrl('home'); - * // to match: /users/1 - * $I->seeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::seeInCurrentUrl() - */ - public function seeInCurrentUrl($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInCurrentUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URI doesn't contain the given string. - * - * ``` php - * dontSeeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInCurrentUrl() - */ - public function cantSeeInCurrentUrl($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInCurrentUrl', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URI doesn't contain the given string. - * - * ``` php - * dontSeeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::dontSeeInCurrentUrl() - */ - public function dontSeeInCurrentUrl($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeInCurrentUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL is equal to the given string. - * Unlike `seeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * seeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlEquals() - */ - public function canSeeCurrentUrlEquals($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlEquals', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL is equal to the given string. - * Unlike `seeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * seeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlEquals() - */ - public function seeCurrentUrlEquals($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeCurrentUrlEquals', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL doesn't equal the given string. - * Unlike `dontSeeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * dontSeeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlEquals() - */ - public function cantSeeCurrentUrlEquals($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlEquals', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL doesn't equal the given string. - * Unlike `dontSeeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * dontSeeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlEquals() - */ - public function dontSeeCurrentUrlEquals($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlEquals', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL matches the given regular expression. - * - * ``` php - * seeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlMatches() - */ - public function canSeeCurrentUrlMatches($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlMatches', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL matches the given regular expression. - * - * ``` php - * seeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlMatches() - */ - public function seeCurrentUrlMatches($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeCurrentUrlMatches', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current url doesn't match the given regular expression. - * - * ``` php - * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlMatches() - */ - public function cantSeeCurrentUrlMatches($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlMatches', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current url doesn't match the given regular expression. - * - * ``` php - * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlMatches() - */ - public function dontSeeCurrentUrlMatches($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlMatches', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Executes the given regular expression against the current URI and returns the first match. - * If no parameters are provided, the full URI is returned. - * - * ``` php - * grabFromCurrentUrl('~$/user/(\d+)/~'); - * $uri = $I->grabFromCurrentUrl(); - * ?> - * ``` - * - * @param null $uri - * - * @internal param $url - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabFromCurrentUrl() - */ - public function grabFromCurrentUrl($uri = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabFromCurrentUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the specified checkbox is checked. - * - * ``` php - * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. - * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); - * ?> - * ``` - * - * @param $checkbox - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCheckboxIsChecked() - */ - public function canSeeCheckboxIsChecked($checkbox) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeCheckboxIsChecked', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the specified checkbox is checked. - * - * ``` php - * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. - * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); - * ?> - * ``` - * - * @param $checkbox - * @see \Codeception\Lib\InnerBrowser::seeCheckboxIsChecked() - */ - public function seeCheckboxIsChecked($checkbox) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeCheckboxIsChecked', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Check that the specified checkbox is unchecked. - * - * ``` php - * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. - * ?> - * ``` - * - * @param $checkbox - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCheckboxIsChecked() - */ - public function cantSeeCheckboxIsChecked($checkbox) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCheckboxIsChecked', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Check that the specified checkbox is unchecked. - * - * ``` php - * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. - * ?> - * ``` - * - * @param $checkbox - * @see \Codeception\Lib\InnerBrowser::dontSeeCheckboxIsChecked() - */ - public function dontSeeCheckboxIsChecked($checkbox) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeCheckboxIsChecked', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given input field or textarea contains the given value. - * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. - * - * ``` php - * seeInField('Body','Type your comment here'); - * $I->seeInField('form textarea[name=body]','Type your comment here'); - * $I->seeInField('form input[type=hidden]','hidden_value'); - * $I->seeInField('#searchform input','Search'); - * $I->seeInField('//form/*[@name=search]','Search'); - * $I->seeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInField() - */ - public function canSeeInField($field, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInField', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given input field or textarea contains the given value. - * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. - * - * ``` php - * seeInField('Body','Type your comment here'); - * $I->seeInField('form textarea[name=body]','Type your comment here'); - * $I->seeInField('form input[type=hidden]','hidden_value'); - * $I->seeInField('#searchform input','Search'); - * $I->seeInField('//form/*[@name=search]','Search'); - * $I->seeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * @see \Codeception\Lib\InnerBrowser::seeInField() - */ - public function seeInField($field, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInField', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that an input field or textarea doesn't contain the given value. - * For fuzzy locators, the field is matched by label text, CSS and XPath. - * - * ``` php - * dontSeeInField('Body','Type your comment here'); - * $I->dontSeeInField('form textarea[name=body]','Type your comment here'); - * $I->dontSeeInField('form input[type=hidden]','hidden_value'); - * $I->dontSeeInField('#searchform input','Search'); - * $I->dontSeeInField('//form/*[@name=search]','Search'); - * $I->dontSeeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInField() - */ - public function cantSeeInField($field, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInField', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that an input field or textarea doesn't contain the given value. - * For fuzzy locators, the field is matched by label text, CSS and XPath. - * - * ``` php - * dontSeeInField('Body','Type your comment here'); - * $I->dontSeeInField('form textarea[name=body]','Type your comment here'); - * $I->dontSeeInField('form input[type=hidden]','hidden_value'); - * $I->dontSeeInField('#searchform input','Search'); - * $I->dontSeeInField('//form/*[@name=search]','Search'); - * $I->dontSeeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * @see \Codeception\Lib\InnerBrowser::dontSeeInField() - */ - public function dontSeeInField($field, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeInField', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if the array of form parameters (name => value) are set on the form matched with the - * passed selector. - * - * ``` php - * seeInFormFields('form[name=myform]', [ - * 'input1' => 'value', - * 'input2' => 'other value', - * ]); - * ?> - * ``` - * - * For multi-select elements, or to check values of multiple elements with the same name, an - * array may be passed: - * - * ``` php - * seeInFormFields('.form-class', [ - * 'multiselect' => [ - * 'value1', - * 'value2', - * ], - * 'checkbox[]' => [ - * 'a checked value', - * 'another checked value', - * ], - * ]); - * ?> - * ``` - * - * Additionally, checkbox values can be checked with a boolean. - * - * ``` php - * seeInFormFields('#form-id', [ - * 'checkbox1' => true, // passes if checked - * 'checkbox2' => false, // passes if unchecked - * ]); - * ?> - * ``` - * - * Pair this with submitForm for quick testing magic. - * - * ``` php - * 'value', - * 'field2' => 'another value', - * 'checkbox1' => true, - * // ... - * ]; - * $I->submitForm('//form[@id=my-form]', $form, 'submitButton'); - * // $I->amOnPage('/path/to/form-page') may be needed - * $I->seeInFormFields('//form[@id=my-form]', $form); - * ?> - * ``` - * - * @param $formSelector - * @param $params - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInFormFields() - */ - public function canSeeInFormFields($formSelector, $params) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInFormFields', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if the array of form parameters (name => value) are set on the form matched with the - * passed selector. - * - * ``` php - * seeInFormFields('form[name=myform]', [ - * 'input1' => 'value', - * 'input2' => 'other value', - * ]); - * ?> - * ``` - * - * For multi-select elements, or to check values of multiple elements with the same name, an - * array may be passed: - * - * ``` php - * seeInFormFields('.form-class', [ - * 'multiselect' => [ - * 'value1', - * 'value2', - * ], - * 'checkbox[]' => [ - * 'a checked value', - * 'another checked value', - * ], - * ]); - * ?> - * ``` - * - * Additionally, checkbox values can be checked with a boolean. - * - * ``` php - * seeInFormFields('#form-id', [ - * 'checkbox1' => true, // passes if checked - * 'checkbox2' => false, // passes if unchecked - * ]); - * ?> - * ``` - * - * Pair this with submitForm for quick testing magic. - * - * ``` php - * 'value', - * 'field2' => 'another value', - * 'checkbox1' => true, - * // ... - * ]; - * $I->submitForm('//form[@id=my-form]', $form, 'submitButton'); - * // $I->amOnPage('/path/to/form-page') may be needed - * $I->seeInFormFields('//form[@id=my-form]', $form); - * ?> - * ``` - * - * @param $formSelector - * @param $params - * @see \Codeception\Lib\InnerBrowser::seeInFormFields() - */ - public function seeInFormFields($formSelector, $params) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInFormFields', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if the array of form parameters (name => value) are not set on the form matched with - * the passed selector. - * - * ``` php - * dontSeeInFormFields('form[name=myform]', [ - * 'input1' => 'non-existent value', - * 'input2' => 'other non-existent value', - * ]); - * ?> - * ``` - * - * To check that an element hasn't been assigned any one of many values, an array can be passed - * as the value: - * - * ``` php - * dontSeeInFormFields('.form-class', [ - * 'fieldName' => [ - * 'This value shouldn\'t be set', - * 'And this value shouldn\'t be set', - * ], - * ]); - * ?> - * ``` - * - * Additionally, checkbox values can be checked with a boolean. - * - * ``` php - * dontSeeInFormFields('#form-id', [ - * 'checkbox1' => true, // fails if checked - * 'checkbox2' => false, // fails if unchecked - * ]); - * ?> - * ``` - * - * @param $formSelector - * @param $params - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInFormFields() - */ - public function cantSeeInFormFields($formSelector, $params) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInFormFields', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if the array of form parameters (name => value) are not set on the form matched with - * the passed selector. - * - * ``` php - * dontSeeInFormFields('form[name=myform]', [ - * 'input1' => 'non-existent value', - * 'input2' => 'other non-existent value', - * ]); - * ?> - * ``` - * - * To check that an element hasn't been assigned any one of many values, an array can be passed - * as the value: - * - * ``` php - * dontSeeInFormFields('.form-class', [ - * 'fieldName' => [ - * 'This value shouldn\'t be set', - * 'And this value shouldn\'t be set', - * ], - * ]); - * ?> - * ``` - * - * Additionally, checkbox values can be checked with a boolean. - * - * ``` php - * dontSeeInFormFields('#form-id', [ - * 'checkbox1' => true, // fails if checked - * 'checkbox2' => false, // fails if unchecked - * ]); - * ?> - * ``` - * - * @param $formSelector - * @param $params - * @see \Codeception\Lib\InnerBrowser::dontSeeInFormFields() - */ - public function dontSeeInFormFields($formSelector, $params) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeInFormFields', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Submits the given form on the page, optionally with the given form - * values. Give the form fields values as an array. - * - * Skipped fields will be filled by their values from the page. - * You don't need to click the 'Submit' button afterwards. - * This command itself triggers the request to form's action. - * - * You can optionally specify what button's value to include - * in the request with the last parameter as an alternative to - * explicitly setting its value in the second parameter, as - * button values are not otherwise included in the request. - * - * Examples: - * - * ``` php - * submitForm('#login', [ - * 'login' => 'davert', - * 'password' => '123456' - * ]); - * // or - * $I->submitForm('#login', [ - * 'login' => 'davert', - * 'password' => '123456' - * ], 'submitButtonName'); - * - * ``` - * - * For example, given this sample "Sign Up" form: - * - * ``` html - *
    - * Login: - *
    - * Password: - *
    - * Do you agree to out terms? - *
    - * Select pricing plan: - * - * - *
    - * ``` - * - * You could write the following to submit it: - * - * ``` php - * submitForm( - * '#userForm', - * [ - * 'user' => [ - * 'login' => 'Davert', - * 'password' => '123456', - * 'agree' => true - * ] - * ], - * 'submitButton' - * ); - * ``` - * Note that "2" will be the submitted value for the "plan" field, as it is - * the selected option. - * - * You can also emulate a JavaScript submission by not specifying any - * buttons in the third parameter to submitForm. - * - * ```php - * submitForm( - * '#userForm', - * [ - * 'user' => [ - * 'login' => 'Davert', - * 'password' => '123456', - * 'agree' => true - * ] - * ] - * ); - * ``` - * - * Pair this with seeInFormFields for quick testing magic. - * - * ``` php - * 'value', - * 'field2' => 'another value', - * 'checkbox1' => true, - * // ... - * ]; - * $I->submitForm('//form[@id=my-form]', $form, 'submitButton'); - * // $I->amOnPage('/path/to/form-page') may be needed - * $I->seeInFormFields('//form[@id=my-form]', $form); - * ?> - * ``` - * - * Parameter values can be set to arrays for multiple input fields - * of the same name, or multi-select combo boxes. For checkboxes, - * either the string value can be used, or boolean values which will - * be replaced by the checkbox's value in the DOM. - * - * ``` php - * submitForm('#my-form', [ - * 'field1' => 'value', - * 'checkbox' => [ - * 'value of first checkbox', - * 'value of second checkbox, - * ], - * 'otherCheckboxes' => [ - * true, - * false, - * false - * ], - * 'multiselect' => [ - * 'first option value', - * 'second option value' - * ] - * ]); - * ?> - * ``` - * - * Mixing string and boolean values for a checkbox's value is not supported - * and may produce unexpected results. - * - * Field names ending in "[]" must be passed without the trailing square - * bracket characters, and must contain an array for its value. This allows - * submitting multiple values with the same name, consider: - * - * ```php - * $I->submitForm('#my-form', [ - * 'field[]' => 'value', - * 'field[]' => 'another value', // 'field[]' is already a defined key - * ]); - * ``` - * - * The solution is to pass an array value: - * - * ```php - * // this way both values are submitted - * $I->submitForm('#my-form', [ - * 'field' => [ - * 'value', - * 'another value', - * ] - * ]); - * ``` - * - * @param $selector - * @param $params - * @param $button - * @see \Codeception\Lib\InnerBrowser::submitForm() - */ - public function submitForm($selector, $params, $button = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('submitForm', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Fills a text field or textarea with the given string. - * - * ``` php - * fillField("//input[@type='text']", "Hello World!"); - * $I->fillField(['name' => 'email'], 'jon@mail.com'); - * ?> - * ``` - * - * @param $field - * @param $value - * @see \Codeception\Lib\InnerBrowser::fillField() - */ - public function fillField($field, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('fillField', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Selects an option in a select tag or in radio button group. - * - * ``` php - * selectOption('form select[name=account]', 'Premium'); - * $I->selectOption('form input[name=payment]', 'Monthly'); - * $I->selectOption('//form/select[@name=account]', 'Monthly'); - * ?> - * ``` - * - * Provide an array for the second argument to select multiple options: - * - * ``` php - * selectOption('Which OS do you use?', array('Windows','Linux')); - * ?> - * ``` - * - * @param $select - * @param $option - * @see \Codeception\Lib\InnerBrowser::selectOption() - */ - public function selectOption($select, $option) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('selectOption', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Ticks a checkbox. For radio buttons, use the `selectOption` method instead. - * - * ``` php - * checkOption('#agree'); - * ?> - * ``` - * - * @param $option - * @see \Codeception\Lib\InnerBrowser::checkOption() - */ - public function checkOption($option) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('checkOption', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Unticks a checkbox. - * - * ``` php - * uncheckOption('#notify'); - * ?> - * ``` - * - * @param $option - * @see \Codeception\Lib\InnerBrowser::uncheckOption() - */ - public function uncheckOption($option) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('uncheckOption', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Attaches a file relative to the Codeception data directory to the given file upload field. - * - * ``` php - * attachFile('input[@type="file"]', 'prices.xls'); - * ?> - * ``` - * - * @param $field - * @param $filename - * @see \Codeception\Lib\InnerBrowser::attachFile() - */ - public function attachFile($field, $filename) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('attachFile', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * If your page triggers an ajax request, you can perform it manually. - * This action sends a GET ajax request with specified params. - * - * See ->sendAjaxPostRequest for examples. - * - * @param $uri - * @param $params - * @see \Codeception\Lib\InnerBrowser::sendAjaxGetRequest() - */ - public function sendAjaxGetRequest($uri, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('sendAjaxGetRequest', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * If your page triggers an ajax request, you can perform it manually. - * This action sends a POST ajax request with specified params. - * Additional params can be passed as array. - * - * Example: - * - * Imagine that by clicking checkbox you trigger ajax request which updates user settings. - * We emulate that click by running this ajax request manually. - * - * ``` php - * sendAjaxPostRequest('/updateSettings', array('notifications' => true)); // POST - * $I->sendAjaxGetRequest('/updateSettings', array('notifications' => true)); // GET - * - * ``` - * - * @param $uri - * @param $params - * @see \Codeception\Lib\InnerBrowser::sendAjaxPostRequest() - */ - public function sendAjaxPostRequest($uri, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('sendAjaxPostRequest', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * If your page triggers an ajax request, you can perform it manually. - * This action sends an ajax request with specified method and params. - * - * Example: - * - * You need to perform an ajax request specifying the HTTP method. - * - * ``` php - * sendAjaxRequest('PUT', '/posts/7', array('title' => 'new title')); - * - * ``` - * - * @param $method - * @param $uri - * @param $params - * @see \Codeception\Lib\InnerBrowser::sendAjaxRequest() - */ - public function sendAjaxRequest($method, $uri, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('sendAjaxRequest', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Finds and returns the text contents of the given element. - * If a fuzzy locator is used, the element is found using CSS, XPath, and by matching the full page source by regular expression. - * - * ``` php - * grabTextFrom('h1'); - * $heading = $I->grabTextFrom('descendant-or-self::h1'); - * $value = $I->grabTextFrom('~ - * ``` - * - * @param $cssOrXPathOrRegex - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabTextFrom() - */ - public function grabTextFrom($cssOrXPathOrRegex) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabTextFrom', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Grabs the value of the given attribute value from the given element. - * Fails if element is not found. - * - * ``` php - * grabAttributeFrom('#tooltip', 'title'); - * ?> - * ``` - * - * - * @param $cssOrXpath - * @param $attribute - * @internal param $element - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabAttributeFrom() - */ - public function grabAttributeFrom($cssOrXpath, $attribute) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabAttributeFrom', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * - * @see \Codeception\Lib\InnerBrowser::grabMultiple() - */ - public function grabMultiple($cssOrXpath, $attribute = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabMultiple', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * @param $field - * - * @return array|mixed|null|string - * @see \Codeception\Lib\InnerBrowser::grabValueFrom() - */ - public function grabValueFrom($field) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabValueFrom', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sets a cookie with the given name and value. - * You can set additional cookie params like `domain`, `path`, `expire`, `secure` in array passed as last argument. - * - * ``` php - * setCookie('PHPSESSID', 'el4ukv0kqbvoirg7nkp4dncpk3'); - * ?> - * ``` - * - * @param $name - * @param $val - * @param array $params - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::setCookie() - */ - public function setCookie($name, $val, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('setCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Grabs a cookie value. - * You can set additional cookie params like `domain`, `path` in array passed as last argument. - * - * @param $cookie - * - * @param array $params - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabCookie() - */ - public function grabCookie($cookie, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that a cookie with the given name is set. - * You can set additional cookie params like `domain`, `path` as array passed in last argument. - * - * ``` php - * seeCookie('PHPSESSID'); - * ?> - * ``` - * - * @param $cookie - * @param array $params - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCookie() - */ - public function canSeeCookie($cookie, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeCookie', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that a cookie with the given name is set. - * You can set additional cookie params like `domain`, `path` as array passed in last argument. - * - * ``` php - * seeCookie('PHPSESSID'); - * ?> - * ``` - * - * @param $cookie - * @param array $params - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeCookie() - */ - public function seeCookie($cookie, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there isn't a cookie with the given name. - * You can set additional cookie params like `domain`, `path` as array passed in last argument. - * - * @param $cookie - * - * @param array $params - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCookie() - */ - public function cantSeeCookie($cookie, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCookie', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there isn't a cookie with the given name. - * You can set additional cookie params like `domain`, `path` as array passed in last argument. - * - * @param $cookie - * - * @param array $params - * @return mixed - * @see \Codeception\Lib\InnerBrowser::dontSeeCookie() - */ - public function dontSeeCookie($cookie, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Unsets cookie with the given name. - * You can set additional cookie params like `domain`, `path` in array passed as last argument. - * - * @param $cookie - * - * @param array $params - * @return mixed - * @see \Codeception\Lib\InnerBrowser::resetCookie() - */ - public function resetCookie($name, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('resetCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element exists on the page and is visible. - * You can also specify expected attributes of this element. - * - * ``` php - * seeElement('.error'); - * $I->seeElement('//form/input[1]'); - * $I->seeElement('input', ['name' => 'login']); - * $I->seeElement('input', ['value' => '123456']); - * - * // strict locator in first arg, attributes in second - * $I->seeElement(['css' => 'form input'], ['name' => 'login']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * @return - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeElement() - */ - public function canSeeElement($selector, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeElement', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element exists on the page and is visible. - * You can also specify expected attributes of this element. - * - * ``` php - * seeElement('.error'); - * $I->seeElement('//form/input[1]'); - * $I->seeElement('input', ['name' => 'login']); - * $I->seeElement('input', ['value' => '123456']); - * - * // strict locator in first arg, attributes in second - * $I->seeElement(['css' => 'form input'], ['name' => 'login']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * @return - * @see \Codeception\Lib\InnerBrowser::seeElement() - */ - public function seeElement($selector, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeElement', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element is invisible or not present on the page. - * You can also specify expected attributes of this element. - * - * ``` php - * dontSeeElement('.error'); - * $I->dontSeeElement('//form/input[1]'); - * $I->dontSeeElement('input', ['name' => 'login']); - * $I->dontSeeElement('input', ['value' => '123456']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeElement() - */ - public function cantSeeElement($selector, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeElement', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element is invisible or not present on the page. - * You can also specify expected attributes of this element. - * - * ``` php - * dontSeeElement('.error'); - * $I->dontSeeElement('//form/input[1]'); - * $I->dontSeeElement('input', ['name' => 'login']); - * $I->dontSeeElement('input', ['value' => '123456']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * @see \Codeception\Lib\InnerBrowser::dontSeeElement() - */ - public function dontSeeElement($selector, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeElement', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there are a certain number of elements matched by the given locator on the page. - * - * ``` php - * seeNumberOfElements('tr', 10); - * $I->seeNumberOfElements('tr', [0,10]); //between 0 and 10 elements - * ?> - * ``` - * @param $selector - * @param mixed $expected : - * - string: strict number - * - array: range of numbers [0,10] - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeNumberOfElements() - */ - public function canSeeNumberOfElements($selector, $expected) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeNumberOfElements', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there are a certain number of elements matched by the given locator on the page. - * - * ``` php - * seeNumberOfElements('tr', 10); - * $I->seeNumberOfElements('tr', [0,10]); //between 0 and 10 elements - * ?> - * ``` - * @param $selector - * @param mixed $expected : - * - string: strict number - * - array: range of numbers [0,10] - * @see \Codeception\Lib\InnerBrowser::seeNumberOfElements() - */ - public function seeNumberOfElements($selector, $expected) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeNumberOfElements', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is selected. - * - * ``` php - * seeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeOptionIsSelected() - */ - public function canSeeOptionIsSelected($selector, $optionText) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeOptionIsSelected', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is selected. - * - * ``` php - * seeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeOptionIsSelected() - */ - public function seeOptionIsSelected($selector, $optionText) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeOptionIsSelected', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is not selected. - * - * ``` php - * dontSeeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeOptionIsSelected() - */ - public function cantSeeOptionIsSelected($selector, $optionText) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeOptionIsSelected', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is not selected. - * - * ``` php - * dontSeeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::dontSeeOptionIsSelected() - */ - public function dontSeeOptionIsSelected($selector, $optionText) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeOptionIsSelected', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Asserts that current page has 404 response status code. - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seePageNotFound() - */ - public function canSeePageNotFound() { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seePageNotFound', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Asserts that current page has 404 response status code. - * @see \Codeception\Lib\InnerBrowser::seePageNotFound() - */ - public function seePageNotFound() { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seePageNotFound', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that response code is equal to value provided. - * - * @param $code - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeResponseCodeIs() - */ - public function canSeeResponseCodeIs($code) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseCodeIs', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that response code is equal to value provided. - * - * @param $code - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeResponseCodeIs() - */ - public function seeResponseCodeIs($code) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeResponseCodeIs', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title contains the given string. - * - * ``` php - * seeInTitle('Blog - Post #1'); - * ?> - * ``` - * - * @param $title - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInTitle() - */ - public function canSeeInTitle($title) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInTitle', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title contains the given string. - * - * ``` php - * seeInTitle('Blog - Post #1'); - * ?> - * ``` - * - * @param $title - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeInTitle() - */ - public function seeInTitle($title) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInTitle', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title does not contain the given string. - * - * @param $title - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInTitle() - */ - public function cantSeeInTitle($title) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInTitle', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title does not contain the given string. - * - * @param $title - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::dontSeeInTitle() - */ - public function dontSeeInTitle($title) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeInTitle', func_get_args())); - } -} diff --git a/tests/_support/_generated/FunctionalTesterActions.php b/tests/_support/_generated/FunctionalTesterActions.php deleted file mode 100644 index 293b5d56ef..0000000000 --- a/tests/_support/_generated/FunctionalTesterActions.php +++ /dev/null @@ -1,23 +0,0 @@ -getScenario()->runStep(new \Codeception\Step\Action('getApplication', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Opens web page using route name and parameters. - * - * ``` php - * amOnRoute('posts.create'); - * ?> - * ``` - * - * @param $routeName - * @param array $params - * @see \Codeception\Module\Laravel5::amOnRoute() - */ - public function amOnRoute($routeName, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Condition('amOnRoute', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Opens web page by action name - * - * ``` php - * amOnAction('PostsController@index'); - * ?> - * ``` - * - * @param $action - * @param array $params - * @see \Codeception\Module\Laravel5::amOnAction() - */ - public function amOnAction($action, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Condition('amOnAction', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current url matches route - * - * ``` php - * seeCurrentRouteIs('posts.index'); - * ?> - * ``` - * @param $route - * @param array $params - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::seeCurrentRouteIs() - */ - public function canSeeCurrentRouteIs($route, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeCurrentRouteIs', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current url matches route - * - * ``` php - * seeCurrentRouteIs('posts.index'); - * ?> - * ``` - * @param $route - * @param array $params - * @see \Codeception\Module\Laravel5::seeCurrentRouteIs() - */ - public function seeCurrentRouteIs($route, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeCurrentRouteIs', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current url matches action - * - * ``` php - * seeCurrentActionIs('PostsController@index'); - * ?> - * ``` - * - * @param $action - * @param array $params - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::seeCurrentActionIs() - */ - public function canSeeCurrentActionIs($action, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeCurrentActionIs', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current url matches action - * - * ``` php - * seeCurrentActionIs('PostsController@index'); - * ?> - * ``` - * - * @param $action - * @param array $params - * @see \Codeception\Module\Laravel5::seeCurrentActionIs() - */ - public function seeCurrentActionIs($action, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeCurrentActionIs', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Assert that a session variable exists. - * - * ``` php - * seeInSession('key'); - * $I->seeInSession('key', 'value'); - * ?> - * ``` - * - * @param string|array $key - * @param mixed $value - * @return void - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::seeInSession() - */ - public function canSeeInSession($key, $value = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInSession', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Assert that a session variable exists. - * - * ``` php - * seeInSession('key'); - * $I->seeInSession('key', 'value'); - * ?> - * ``` - * - * @param string|array $key - * @param mixed $value - * @return void - * @see \Codeception\Module\Laravel5::seeInSession() - */ - public function seeInSession($key, $value = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInSession', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Assert that the session has a given list of values. - * - * ``` php - * seeSessionHasValues(['key1', 'key2']); - * $I->seeSessionHasValues(['key1' => 'value1', 'key2' => 'value2']); - * ?> - * ``` - * - * @param array $bindings - * @return void - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::seeSessionHasValues() - */ - public function canSeeSessionHasValues($bindings) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeSessionHasValues', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Assert that the session has a given list of values. - * - * ``` php - * seeSessionHasValues(['key1', 'key2']); - * $I->seeSessionHasValues(['key1' => 'value1', 'key2' => 'value2']); - * ?> - * ``` - * - * @param array $bindings - * @return void - * @see \Codeception\Module\Laravel5::seeSessionHasValues() - */ - public function seeSessionHasValues($bindings) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeSessionHasValues', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Assert that form errors are bound to the View. - * - * ``` php - * seeFormHasErrors(); - * ?> - * ``` - * - * @return bool - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::seeFormHasErrors() - */ - public function canSeeFormHasErrors() { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeFormHasErrors', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Assert that form errors are bound to the View. - * - * ``` php - * seeFormHasErrors(); - * ?> - * ``` - * - * @return bool - * @see \Codeception\Module\Laravel5::seeFormHasErrors() - */ - public function seeFormHasErrors() { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeFormHasErrors', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Assert that specific form error messages are set in the view. - * - * Useful for validation messages e.g. - * return `Redirect::to('register')->withErrors($validator);` - * - * Example of Usage - * - * ``` php - * seeFormErrorMessages(array('username'=>'Invalid Username')); - * ?> - * ``` - * @param array $bindings - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::seeFormErrorMessages() - */ - public function canSeeFormErrorMessages($bindings) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeFormErrorMessages', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Assert that specific form error messages are set in the view. - * - * Useful for validation messages e.g. - * return `Redirect::to('register')->withErrors($validator);` - * - * Example of Usage - * - * ``` php - * seeFormErrorMessages(array('username'=>'Invalid Username')); - * ?> - * ``` - * @param array $bindings - * @see \Codeception\Module\Laravel5::seeFormErrorMessages() - */ - public function seeFormErrorMessages($bindings) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeFormErrorMessages', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Assert that specific form error message is set in the view. - * - * Useful for validation messages and generally messages array - * e.g. - * return `Redirect::to('register')->withErrors($validator);` - * - * Example of Usage - * - * ``` php - * seeFormErrorMessage('username', 'Invalid Username'); - * ?> - * ``` - * @param string $key - * @param string $errorMessage - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::seeFormErrorMessage() - */ - public function canSeeFormErrorMessage($key, $errorMessage) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeFormErrorMessage', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Assert that specific form error message is set in the view. - * - * Useful for validation messages and generally messages array - * e.g. - * return `Redirect::to('register')->withErrors($validator);` - * - * Example of Usage - * - * ``` php - * seeFormErrorMessage('username', 'Invalid Username'); - * ?> - * ``` - * @param string $key - * @param string $errorMessage - * @see \Codeception\Module\Laravel5::seeFormErrorMessage() - */ - public function seeFormErrorMessage($key, $errorMessage) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeFormErrorMessage', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Set the currently logged in user for the application. - * Takes either an object that implements the User interface or - * an array of credentials. - * - * @param \Illuminate\Contracts\Auth\User|array $user - * @param string $driver - * @return void - * @see \Codeception\Module\Laravel5::amLoggedAs() - */ - public function amLoggedAs($user, $driver = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Condition('amLoggedAs', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Logs user out - * @see \Codeception\Module\Laravel5::logout() - */ - public function logout() { - return $this->getScenario()->runStep(new \Codeception\Step\Action('logout', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that user is authenticated - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::seeAuthentication() - */ - public function canSeeAuthentication() { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeAuthentication', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that user is authenticated - * @see \Codeception\Module\Laravel5::seeAuthentication() - */ - public function seeAuthentication() { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeAuthentication', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Check that user is not authenticated - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::dontSeeAuthentication() - */ - public function cantSeeAuthentication() { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeAuthentication', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Check that user is not authenticated - * @see \Codeception\Module\Laravel5::dontSeeAuthentication() - */ - public function dontSeeAuthentication() { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeAuthentication', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Return an instance of a class from the IoC Container. - * (http://laravel.com/docs/ioc) - * - * Example - * ``` php - * grabService('foo'); - * - * // Will return an instance of FooBar, also works for singletons. - * ?> - * ``` - * - * @param string $class - * @return mixed - * @see \Codeception\Module\Laravel5::grabService() - */ - public function grabService($class) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabService', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Inserts record into the database. - * - * ``` php - * haveRecord('users', array('name' => 'Davert')); - * ?> - * ``` - * - * @param $tableName - * @param array $attributes - * @return mixed - * @part orm - * @see \Codeception\Module\Laravel5::haveRecord() - */ - public function haveRecord($tableName, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('haveRecord', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that record exists in database. - * - * ``` php - * seeRecord('users', array('name' => 'davert')); - * ?> - * ``` - * - * @param $tableName - * @param array $attributes - * @part orm - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::seeRecord() - */ - public function canSeeRecord($tableName, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeRecord', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that record exists in database. - * - * ``` php - * seeRecord('users', array('name' => 'davert')); - * ?> - * ``` - * - * @param $tableName - * @param array $attributes - * @part orm - * @see \Codeception\Module\Laravel5::seeRecord() - */ - public function seeRecord($tableName, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeRecord', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that record does not exist in database. - * - * ``` php - * dontSeeRecord('users', array('name' => 'davert')); - * ?> - * ``` - * - * @param $tableName - * @param array $attributes - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\Laravel5::dontSeeRecord() - */ - public function cantSeeRecord($tableName, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeRecord', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that record does not exist in database. - * - * ``` php - * dontSeeRecord('users', array('name' => 'davert')); - * ?> - * ``` - * - * @param $tableName - * @param array $attributes - * @see \Codeception\Module\Laravel5::dontSeeRecord() - */ - public function dontSeeRecord($tableName, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeRecord', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Retrieves record from database - * - * ``` php - * grabRecord('users', array('name' => 'davert')); - * ?> - * ``` - * - * @param $tableName - * @param array $attributes - * @return mixed - * @part orm - * @see \Codeception\Module\Laravel5::grabRecord() - */ - public function grabRecord($tableName, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabRecord', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Authenticates user for HTTP_AUTH - * - * @param $username - * @param $password - * @see \Codeception\Lib\InnerBrowser::amHttpAuthenticated() - */ - public function amHttpAuthenticated($username, $password) { - return $this->getScenario()->runStep(new \Codeception\Step\Condition('amHttpAuthenticated', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Opens the page for the given relative URI. - * - * ``` php - * amOnPage('/'); - * // opens /register page - * $I->amOnPage('/register'); - * ?> - * ``` - * - * @param $page - * @see \Codeception\Lib\InnerBrowser::amOnPage() - */ - public function amOnPage($page) { - return $this->getScenario()->runStep(new \Codeception\Step\Condition('amOnPage', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Perform a click on a link or a button, given by a locator. - * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. - * For buttons, the "value" attribute, "name" attribute, and inner text are searched. - * For links, the link text is searched. - * For images, the "alt" attribute and inner text of any parent links are searched. - * - * The second parameter is a context (CSS or XPath locator) to narrow the search. - * - * Note that if the locator matches a button of type `submit`, the form will be submitted. - * - * ``` php - * click('Logout'); - * // button of form - * $I->click('Submit'); - * // CSS button - * $I->click('#form input[type=submit]'); - * // XPath - * $I->click('//form/*[@type=submit]'); - * // link in context - * $I->click('Logout', '#nav'); - * // using strict locator - * $I->click(['link' => 'Login']); - * ?> - * ``` - * - * @param $link - * @param $context - * @see \Codeception\Lib\InnerBrowser::click() - */ - public function click($link, $context = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('click', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page contains the given string. - * Specify a locator as the second parameter to match a specific region. - * - * ``` php - * see('Logout'); // I can suppose user is logged in - * $I->see('Sign Up','h1'); // I can suppose it's a signup page - * $I->see('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::see() - */ - public function canSee($text, $selector = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('see', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page contains the given string. - * Specify a locator as the second parameter to match a specific region. - * - * ``` php - * see('Logout'); // I can suppose user is logged in - * $I->see('Sign Up','h1'); // I can suppose it's a signup page - * $I->see('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * @see \Codeception\Lib\InnerBrowser::see() - */ - public function see($text, $selector = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('see', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page doesn't contain the text specified. - * Give a locator as the second parameter to match a specific region. - * - * ```php - * dontSee('Login'); // I can suppose user is already logged in - * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page - * $I->dontSee('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSee() - */ - public function cantSee($text, $selector = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSee', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page doesn't contain the text specified. - * Give a locator as the second parameter to match a specific region. - * - * ```php - * dontSee('Login'); // I can suppose user is already logged in - * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page - * $I->dontSee('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * @see \Codeception\Lib\InnerBrowser::dontSee() - */ - public function dontSee($text, $selector = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSee', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there's a link with the specified text. - * Give a full URL as the second parameter to match links with that exact URL. - * - * ``` php - * seeLink('Logout'); // matches Logout - * $I->seeLink('Logout','/logout'); // matches Logout - * ?> - * ``` - * - * @param $text - * @param null $url - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeLink() - */ - public function canSeeLink($text, $url = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeLink', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there's a link with the specified text. - * Give a full URL as the second parameter to match links with that exact URL. - * - * ``` php - * seeLink('Logout'); // matches Logout - * $I->seeLink('Logout','/logout'); // matches Logout - * ?> - * ``` - * - * @param $text - * @param null $url - * @see \Codeception\Lib\InnerBrowser::seeLink() - */ - public function seeLink($text, $url = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeLink', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page doesn't contain a link with the given string. - * If the second parameter is given, only links with a matching "href" attribute will be checked. - * - * ``` php - * dontSeeLink('Logout'); // I suppose user is not logged in - * $I->dontSeeLink('Checkout now', '/store/cart.php'); - * ?> - * ``` - * - * @param $text - * @param null $url - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeLink() - */ - public function cantSeeLink($text, $url = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeLink', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page doesn't contain a link with the given string. - * If the second parameter is given, only links with a matching "href" attribute will be checked. - * - * ``` php - * dontSeeLink('Logout'); // I suppose user is not logged in - * $I->dontSeeLink('Checkout now', '/store/cart.php'); - * ?> - * ``` - * - * @param $text - * @param null $url - * @see \Codeception\Lib\InnerBrowser::dontSeeLink() - */ - public function dontSeeLink($text, $url = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeLink', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current URI contains the given string. - * - * ``` php - * seeInCurrentUrl('home'); - * // to match: /users/1 - * $I->seeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInCurrentUrl() - */ - public function canSeeInCurrentUrl($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInCurrentUrl', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current URI contains the given string. - * - * ``` php - * seeInCurrentUrl('home'); - * // to match: /users/1 - * $I->seeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::seeInCurrentUrl() - */ - public function seeInCurrentUrl($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInCurrentUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URI doesn't contain the given string. - * - * ``` php - * dontSeeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInCurrentUrl() - */ - public function cantSeeInCurrentUrl($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInCurrentUrl', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URI doesn't contain the given string. - * - * ``` php - * dontSeeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::dontSeeInCurrentUrl() - */ - public function dontSeeInCurrentUrl($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeInCurrentUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL is equal to the given string. - * Unlike `seeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * seeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlEquals() - */ - public function canSeeCurrentUrlEquals($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlEquals', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL is equal to the given string. - * Unlike `seeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * seeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlEquals() - */ - public function seeCurrentUrlEquals($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeCurrentUrlEquals', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL doesn't equal the given string. - * Unlike `dontSeeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * dontSeeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlEquals() - */ - public function cantSeeCurrentUrlEquals($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlEquals', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL doesn't equal the given string. - * Unlike `dontSeeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * dontSeeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlEquals() - */ - public function dontSeeCurrentUrlEquals($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlEquals', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL matches the given regular expression. - * - * ``` php - * seeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlMatches() - */ - public function canSeeCurrentUrlMatches($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlMatches', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL matches the given regular expression. - * - * ``` php - * seeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlMatches() - */ - public function seeCurrentUrlMatches($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeCurrentUrlMatches', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current url doesn't match the given regular expression. - * - * ``` php - * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlMatches() - */ - public function cantSeeCurrentUrlMatches($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlMatches', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current url doesn't match the given regular expression. - * - * ``` php - * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlMatches() - */ - public function dontSeeCurrentUrlMatches($uri) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlMatches', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Executes the given regular expression against the current URI and returns the first match. - * If no parameters are provided, the full URI is returned. - * - * ``` php - * grabFromCurrentUrl('~$/user/(\d+)/~'); - * $uri = $I->grabFromCurrentUrl(); - * ?> - * ``` - * - * @param null $uri - * - * @internal param $url - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabFromCurrentUrl() - */ - public function grabFromCurrentUrl($uri = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabFromCurrentUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the specified checkbox is checked. - * - * ``` php - * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. - * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); - * ?> - * ``` - * - * @param $checkbox - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCheckboxIsChecked() - */ - public function canSeeCheckboxIsChecked($checkbox) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeCheckboxIsChecked', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the specified checkbox is checked. - * - * ``` php - * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. - * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); - * ?> - * ``` - * - * @param $checkbox - * @see \Codeception\Lib\InnerBrowser::seeCheckboxIsChecked() - */ - public function seeCheckboxIsChecked($checkbox) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeCheckboxIsChecked', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Check that the specified checkbox is unchecked. - * - * ``` php - * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. - * ?> - * ``` - * - * @param $checkbox - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCheckboxIsChecked() - */ - public function cantSeeCheckboxIsChecked($checkbox) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCheckboxIsChecked', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Check that the specified checkbox is unchecked. - * - * ``` php - * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. - * ?> - * ``` - * - * @param $checkbox - * @see \Codeception\Lib\InnerBrowser::dontSeeCheckboxIsChecked() - */ - public function dontSeeCheckboxIsChecked($checkbox) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeCheckboxIsChecked', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given input field or textarea contains the given value. - * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. - * - * ``` php - * seeInField('Body','Type your comment here'); - * $I->seeInField('form textarea[name=body]','Type your comment here'); - * $I->seeInField('form input[type=hidden]','hidden_value'); - * $I->seeInField('#searchform input','Search'); - * $I->seeInField('//form/*[@name=search]','Search'); - * $I->seeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInField() - */ - public function canSeeInField($field, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInField', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given input field or textarea contains the given value. - * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. - * - * ``` php - * seeInField('Body','Type your comment here'); - * $I->seeInField('form textarea[name=body]','Type your comment here'); - * $I->seeInField('form input[type=hidden]','hidden_value'); - * $I->seeInField('#searchform input','Search'); - * $I->seeInField('//form/*[@name=search]','Search'); - * $I->seeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * @see \Codeception\Lib\InnerBrowser::seeInField() - */ - public function seeInField($field, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInField', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that an input field or textarea doesn't contain the given value. - * For fuzzy locators, the field is matched by label text, CSS and XPath. - * - * ``` php - * dontSeeInField('Body','Type your comment here'); - * $I->dontSeeInField('form textarea[name=body]','Type your comment here'); - * $I->dontSeeInField('form input[type=hidden]','hidden_value'); - * $I->dontSeeInField('#searchform input','Search'); - * $I->dontSeeInField('//form/*[@name=search]','Search'); - * $I->dontSeeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInField() - */ - public function cantSeeInField($field, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInField', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that an input field or textarea doesn't contain the given value. - * For fuzzy locators, the field is matched by label text, CSS and XPath. - * - * ``` php - * dontSeeInField('Body','Type your comment here'); - * $I->dontSeeInField('form textarea[name=body]','Type your comment here'); - * $I->dontSeeInField('form input[type=hidden]','hidden_value'); - * $I->dontSeeInField('#searchform input','Search'); - * $I->dontSeeInField('//form/*[@name=search]','Search'); - * $I->dontSeeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * @see \Codeception\Lib\InnerBrowser::dontSeeInField() - */ - public function dontSeeInField($field, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeInField', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if the array of form parameters (name => value) are set on the form matched with the - * passed selector. - * - * ``` php - * seeInFormFields('form[name=myform]', [ - * 'input1' => 'value', - * 'input2' => 'other value', - * ]); - * ?> - * ``` - * - * For multi-select elements, or to check values of multiple elements with the same name, an - * array may be passed: - * - * ``` php - * seeInFormFields('.form-class', [ - * 'multiselect' => [ - * 'value1', - * 'value2', - * ], - * 'checkbox[]' => [ - * 'a checked value', - * 'another checked value', - * ], - * ]); - * ?> - * ``` - * - * Additionally, checkbox values can be checked with a boolean. - * - * ``` php - * seeInFormFields('#form-id', [ - * 'checkbox1' => true, // passes if checked - * 'checkbox2' => false, // passes if unchecked - * ]); - * ?> - * ``` - * - * Pair this with submitForm for quick testing magic. - * - * ``` php - * 'value', - * 'field2' => 'another value', - * 'checkbox1' => true, - * // ... - * ]; - * $I->submitForm('//form[@id=my-form]', $form, 'submitButton'); - * // $I->amOnPage('/path/to/form-page') may be needed - * $I->seeInFormFields('//form[@id=my-form]', $form); - * ?> - * ``` - * - * @param $formSelector - * @param $params - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInFormFields() - */ - public function canSeeInFormFields($formSelector, $params) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInFormFields', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if the array of form parameters (name => value) are set on the form matched with the - * passed selector. - * - * ``` php - * seeInFormFields('form[name=myform]', [ - * 'input1' => 'value', - * 'input2' => 'other value', - * ]); - * ?> - * ``` - * - * For multi-select elements, or to check values of multiple elements with the same name, an - * array may be passed: - * - * ``` php - * seeInFormFields('.form-class', [ - * 'multiselect' => [ - * 'value1', - * 'value2', - * ], - * 'checkbox[]' => [ - * 'a checked value', - * 'another checked value', - * ], - * ]); - * ?> - * ``` - * - * Additionally, checkbox values can be checked with a boolean. - * - * ``` php - * seeInFormFields('#form-id', [ - * 'checkbox1' => true, // passes if checked - * 'checkbox2' => false, // passes if unchecked - * ]); - * ?> - * ``` - * - * Pair this with submitForm for quick testing magic. - * - * ``` php - * 'value', - * 'field2' => 'another value', - * 'checkbox1' => true, - * // ... - * ]; - * $I->submitForm('//form[@id=my-form]', $form, 'submitButton'); - * // $I->amOnPage('/path/to/form-page') may be needed - * $I->seeInFormFields('//form[@id=my-form]', $form); - * ?> - * ``` - * - * @param $formSelector - * @param $params - * @see \Codeception\Lib\InnerBrowser::seeInFormFields() - */ - public function seeInFormFields($formSelector, $params) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInFormFields', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if the array of form parameters (name => value) are not set on the form matched with - * the passed selector. - * - * ``` php - * dontSeeInFormFields('form[name=myform]', [ - * 'input1' => 'non-existent value', - * 'input2' => 'other non-existent value', - * ]); - * ?> - * ``` - * - * To check that an element hasn't been assigned any one of many values, an array can be passed - * as the value: - * - * ``` php - * dontSeeInFormFields('.form-class', [ - * 'fieldName' => [ - * 'This value shouldn\'t be set', - * 'And this value shouldn\'t be set', - * ], - * ]); - * ?> - * ``` - * - * Additionally, checkbox values can be checked with a boolean. - * - * ``` php - * dontSeeInFormFields('#form-id', [ - * 'checkbox1' => true, // fails if checked - * 'checkbox2' => false, // fails if unchecked - * ]); - * ?> - * ``` - * - * @param $formSelector - * @param $params - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInFormFields() - */ - public function cantSeeInFormFields($formSelector, $params) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInFormFields', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if the array of form parameters (name => value) are not set on the form matched with - * the passed selector. - * - * ``` php - * dontSeeInFormFields('form[name=myform]', [ - * 'input1' => 'non-existent value', - * 'input2' => 'other non-existent value', - * ]); - * ?> - * ``` - * - * To check that an element hasn't been assigned any one of many values, an array can be passed - * as the value: - * - * ``` php - * dontSeeInFormFields('.form-class', [ - * 'fieldName' => [ - * 'This value shouldn\'t be set', - * 'And this value shouldn\'t be set', - * ], - * ]); - * ?> - * ``` - * - * Additionally, checkbox values can be checked with a boolean. - * - * ``` php - * dontSeeInFormFields('#form-id', [ - * 'checkbox1' => true, // fails if checked - * 'checkbox2' => false, // fails if unchecked - * ]); - * ?> - * ``` - * - * @param $formSelector - * @param $params - * @see \Codeception\Lib\InnerBrowser::dontSeeInFormFields() - */ - public function dontSeeInFormFields($formSelector, $params) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeInFormFields', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Submits the given form on the page, optionally with the given form - * values. Give the form fields values as an array. - * - * Skipped fields will be filled by their values from the page. - * You don't need to click the 'Submit' button afterwards. - * This command itself triggers the request to form's action. - * - * You can optionally specify what button's value to include - * in the request with the last parameter as an alternative to - * explicitly setting its value in the second parameter, as - * button values are not otherwise included in the request. - * - * Examples: - * - * ``` php - * submitForm('#login', [ - * 'login' => 'davert', - * 'password' => '123456' - * ]); - * // or - * $I->submitForm('#login', [ - * 'login' => 'davert', - * 'password' => '123456' - * ], 'submitButtonName'); - * - * ``` - * - * For example, given this sample "Sign Up" form: - * - * ``` html - *
    - * Login: - *
    - * Password: - *
    - * Do you agree to out terms? - *
    - * Select pricing plan: - * - * - *
    - * ``` - * - * You could write the following to submit it: - * - * ``` php - * submitForm( - * '#userForm', - * [ - * 'user' => [ - * 'login' => 'Davert', - * 'password' => '123456', - * 'agree' => true - * ] - * ], - * 'submitButton' - * ); - * ``` - * Note that "2" will be the submitted value for the "plan" field, as it is - * the selected option. - * - * You can also emulate a JavaScript submission by not specifying any - * buttons in the third parameter to submitForm. - * - * ```php - * submitForm( - * '#userForm', - * [ - * 'user' => [ - * 'login' => 'Davert', - * 'password' => '123456', - * 'agree' => true - * ] - * ] - * ); - * ``` - * - * Pair this with seeInFormFields for quick testing magic. - * - * ``` php - * 'value', - * 'field2' => 'another value', - * 'checkbox1' => true, - * // ... - * ]; - * $I->submitForm('//form[@id=my-form]', $form, 'submitButton'); - * // $I->amOnPage('/path/to/form-page') may be needed - * $I->seeInFormFields('//form[@id=my-form]', $form); - * ?> - * ``` - * - * Parameter values can be set to arrays for multiple input fields - * of the same name, or multi-select combo boxes. For checkboxes, - * either the string value can be used, or boolean values which will - * be replaced by the checkbox's value in the DOM. - * - * ``` php - * submitForm('#my-form', [ - * 'field1' => 'value', - * 'checkbox' => [ - * 'value of first checkbox', - * 'value of second checkbox, - * ], - * 'otherCheckboxes' => [ - * true, - * false, - * false - * ], - * 'multiselect' => [ - * 'first option value', - * 'second option value' - * ] - * ]); - * ?> - * ``` - * - * Mixing string and boolean values for a checkbox's value is not supported - * and may produce unexpected results. - * - * Field names ending in "[]" must be passed without the trailing square - * bracket characters, and must contain an array for its value. This allows - * submitting multiple values with the same name, consider: - * - * ```php - * $I->submitForm('#my-form', [ - * 'field[]' => 'value', - * 'field[]' => 'another value', // 'field[]' is already a defined key - * ]); - * ``` - * - * The solution is to pass an array value: - * - * ```php - * // this way both values are submitted - * $I->submitForm('#my-form', [ - * 'field' => [ - * 'value', - * 'another value', - * ] - * ]); - * ``` - * - * @param $selector - * @param $params - * @param $button - * @see \Codeception\Lib\InnerBrowser::submitForm() - */ - public function submitForm($selector, $params, $button = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('submitForm', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Fills a text field or textarea with the given string. - * - * ``` php - * fillField("//input[@type='text']", "Hello World!"); - * $I->fillField(['name' => 'email'], 'jon@mail.com'); - * ?> - * ``` - * - * @param $field - * @param $value - * @see \Codeception\Lib\InnerBrowser::fillField() - */ - public function fillField($field, $value) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('fillField', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Selects an option in a select tag or in radio button group. - * - * ``` php - * selectOption('form select[name=account]', 'Premium'); - * $I->selectOption('form input[name=payment]', 'Monthly'); - * $I->selectOption('//form/select[@name=account]', 'Monthly'); - * ?> - * ``` - * - * Provide an array for the second argument to select multiple options: - * - * ``` php - * selectOption('Which OS do you use?', array('Windows','Linux')); - * ?> - * ``` - * - * @param $select - * @param $option - * @see \Codeception\Lib\InnerBrowser::selectOption() - */ - public function selectOption($select, $option) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('selectOption', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Ticks a checkbox. For radio buttons, use the `selectOption` method instead. - * - * ``` php - * checkOption('#agree'); - * ?> - * ``` - * - * @param $option - * @see \Codeception\Lib\InnerBrowser::checkOption() - */ - public function checkOption($option) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('checkOption', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Unticks a checkbox. - * - * ``` php - * uncheckOption('#notify'); - * ?> - * ``` - * - * @param $option - * @see \Codeception\Lib\InnerBrowser::uncheckOption() - */ - public function uncheckOption($option) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('uncheckOption', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Attaches a file relative to the Codeception data directory to the given file upload field. - * - * ``` php - * attachFile('input[@type="file"]', 'prices.xls'); - * ?> - * ``` - * - * @param $field - * @param $filename - * @see \Codeception\Lib\InnerBrowser::attachFile() - */ - public function attachFile($field, $filename) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('attachFile', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * If your page triggers an ajax request, you can perform it manually. - * This action sends a GET ajax request with specified params. - * - * See ->sendAjaxPostRequest for examples. - * - * @param $uri - * @param $params - * @see \Codeception\Lib\InnerBrowser::sendAjaxGetRequest() - */ - public function sendAjaxGetRequest($uri, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('sendAjaxGetRequest', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * If your page triggers an ajax request, you can perform it manually. - * This action sends a POST ajax request with specified params. - * Additional params can be passed as array. - * - * Example: - * - * Imagine that by clicking checkbox you trigger ajax request which updates user settings. - * We emulate that click by running this ajax request manually. - * - * ``` php - * sendAjaxPostRequest('/updateSettings', array('notifications' => true)); // POST - * $I->sendAjaxGetRequest('/updateSettings', array('notifications' => true)); // GET - * - * ``` - * - * @param $uri - * @param $params - * @see \Codeception\Lib\InnerBrowser::sendAjaxPostRequest() - */ - public function sendAjaxPostRequest($uri, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('sendAjaxPostRequest', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * If your page triggers an ajax request, you can perform it manually. - * This action sends an ajax request with specified method and params. - * - * Example: - * - * You need to perform an ajax request specifying the HTTP method. - * - * ``` php - * sendAjaxRequest('PUT', '/posts/7', array('title' => 'new title')); - * - * ``` - * - * @param $method - * @param $uri - * @param $params - * @see \Codeception\Lib\InnerBrowser::sendAjaxRequest() - */ - public function sendAjaxRequest($method, $uri, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('sendAjaxRequest', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Finds and returns the text contents of the given element. - * If a fuzzy locator is used, the element is found using CSS, XPath, and by matching the full page source by regular expression. - * - * ``` php - * grabTextFrom('h1'); - * $heading = $I->grabTextFrom('descendant-or-self::h1'); - * $value = $I->grabTextFrom('~ - * ``` - * - * @param $cssOrXPathOrRegex - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabTextFrom() - */ - public function grabTextFrom($cssOrXPathOrRegex) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabTextFrom', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Grabs the value of the given attribute value from the given element. - * Fails if element is not found. - * - * ``` php - * grabAttributeFrom('#tooltip', 'title'); - * ?> - * ``` - * - * - * @param $cssOrXpath - * @param $attribute - * @internal param $element - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabAttributeFrom() - */ - public function grabAttributeFrom($cssOrXpath, $attribute) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabAttributeFrom', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * - * @see \Codeception\Lib\InnerBrowser::grabMultiple() - */ - public function grabMultiple($cssOrXpath, $attribute = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabMultiple', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * @param $field - * - * @return array|mixed|null|string - * @see \Codeception\Lib\InnerBrowser::grabValueFrom() - */ - public function grabValueFrom($field) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabValueFrom', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sets a cookie with the given name and value. - * You can set additional cookie params like `domain`, `path`, `expire`, `secure` in array passed as last argument. - * - * ``` php - * setCookie('PHPSESSID', 'el4ukv0kqbvoirg7nkp4dncpk3'); - * ?> - * ``` - * - * @param $name - * @param $val - * @param array $params - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::setCookie() - */ - public function setCookie($name, $val, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('setCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Grabs a cookie value. - * You can set additional cookie params like `domain`, `path` in array passed as last argument. - * - * @param $cookie - * - * @param array $params - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabCookie() - */ - public function grabCookie($cookie, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('grabCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that a cookie with the given name is set. - * You can set additional cookie params like `domain`, `path` as array passed in last argument. - * - * ``` php - * seeCookie('PHPSESSID'); - * ?> - * ``` - * - * @param $cookie - * @param array $params - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCookie() - */ - public function canSeeCookie($cookie, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeCookie', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that a cookie with the given name is set. - * You can set additional cookie params like `domain`, `path` as array passed in last argument. - * - * ``` php - * seeCookie('PHPSESSID'); - * ?> - * ``` - * - * @param $cookie - * @param array $params - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeCookie() - */ - public function seeCookie($cookie, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there isn't a cookie with the given name. - * You can set additional cookie params like `domain`, `path` as array passed in last argument. - * - * @param $cookie - * - * @param array $params - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCookie() - */ - public function cantSeeCookie($cookie, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCookie', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there isn't a cookie with the given name. - * You can set additional cookie params like `domain`, `path` as array passed in last argument. - * - * @param $cookie - * - * @param array $params - * @return mixed - * @see \Codeception\Lib\InnerBrowser::dontSeeCookie() - */ - public function dontSeeCookie($cookie, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Unsets cookie with the given name. - * You can set additional cookie params like `domain`, `path` in array passed as last argument. - * - * @param $cookie - * - * @param array $params - * @return mixed - * @see \Codeception\Lib\InnerBrowser::resetCookie() - */ - public function resetCookie($name, $params = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('resetCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element exists on the page and is visible. - * You can also specify expected attributes of this element. - * - * ``` php - * seeElement('.error'); - * $I->seeElement('//form/input[1]'); - * $I->seeElement('input', ['name' => 'login']); - * $I->seeElement('input', ['value' => '123456']); - * - * // strict locator in first arg, attributes in second - * $I->seeElement(['css' => 'form input'], ['name' => 'login']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * @return - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeElement() - */ - public function canSeeElement($selector, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeElement', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element exists on the page and is visible. - * You can also specify expected attributes of this element. - * - * ``` php - * seeElement('.error'); - * $I->seeElement('//form/input[1]'); - * $I->seeElement('input', ['name' => 'login']); - * $I->seeElement('input', ['value' => '123456']); - * - * // strict locator in first arg, attributes in second - * $I->seeElement(['css' => 'form input'], ['name' => 'login']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * @return - * @see \Codeception\Lib\InnerBrowser::seeElement() - */ - public function seeElement($selector, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeElement', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element is invisible or not present on the page. - * You can also specify expected attributes of this element. - * - * ``` php - * dontSeeElement('.error'); - * $I->dontSeeElement('//form/input[1]'); - * $I->dontSeeElement('input', ['name' => 'login']); - * $I->dontSeeElement('input', ['value' => '123456']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeElement() - */ - public function cantSeeElement($selector, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeElement', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element is invisible or not present on the page. - * You can also specify expected attributes of this element. - * - * ``` php - * dontSeeElement('.error'); - * $I->dontSeeElement('//form/input[1]'); - * $I->dontSeeElement('input', ['name' => 'login']); - * $I->dontSeeElement('input', ['value' => '123456']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * @see \Codeception\Lib\InnerBrowser::dontSeeElement() - */ - public function dontSeeElement($selector, $attributes = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeElement', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there are a certain number of elements matched by the given locator on the page. - * - * ``` php - * seeNumberOfElements('tr', 10); - * $I->seeNumberOfElements('tr', [0,10]); //between 0 and 10 elements - * ?> - * ``` - * @param $selector - * @param mixed $expected : - * - string: strict number - * - array: range of numbers [0,10] - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeNumberOfElements() - */ - public function canSeeNumberOfElements($selector, $expected) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeNumberOfElements', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there are a certain number of elements matched by the given locator on the page. - * - * ``` php - * seeNumberOfElements('tr', 10); - * $I->seeNumberOfElements('tr', [0,10]); //between 0 and 10 elements - * ?> - * ``` - * @param $selector - * @param mixed $expected : - * - string: strict number - * - array: range of numbers [0,10] - * @see \Codeception\Lib\InnerBrowser::seeNumberOfElements() - */ - public function seeNumberOfElements($selector, $expected) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeNumberOfElements', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is selected. - * - * ``` php - * seeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeOptionIsSelected() - */ - public function canSeeOptionIsSelected($selector, $optionText) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeOptionIsSelected', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is selected. - * - * ``` php - * seeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeOptionIsSelected() - */ - public function seeOptionIsSelected($selector, $optionText) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeOptionIsSelected', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is not selected. - * - * ``` php - * dontSeeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeOptionIsSelected() - */ - public function cantSeeOptionIsSelected($selector, $optionText) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeOptionIsSelected', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is not selected. - * - * ``` php - * dontSeeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::dontSeeOptionIsSelected() - */ - public function dontSeeOptionIsSelected($selector, $optionText) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeOptionIsSelected', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Asserts that current page has 404 response status code. - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seePageNotFound() - */ - public function canSeePageNotFound() { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seePageNotFound', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Asserts that current page has 404 response status code. - * @see \Codeception\Lib\InnerBrowser::seePageNotFound() - */ - public function seePageNotFound() { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seePageNotFound', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that response code is equal to value provided. - * - * @param $code - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeResponseCodeIs() - */ - public function canSeeResponseCodeIs($code) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseCodeIs', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that response code is equal to value provided. - * - * @param $code - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeResponseCodeIs() - */ - public function seeResponseCodeIs($code) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeResponseCodeIs', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title contains the given string. - * - * ``` php - * seeInTitle('Blog - Post #1'); - * ?> - * ``` - * - * @param $title - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInTitle() - */ - public function canSeeInTitle($title) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('seeInTitle', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title contains the given string. - * - * ``` php - * seeInTitle('Blog - Post #1'); - * ?> - * ``` - * - * @param $title - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeInTitle() - */ - public function seeInTitle($title) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('seeInTitle', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title does not contain the given string. - * - * @param $title - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInTitle() - */ - public function cantSeeInTitle($title) { - return $this->getScenario()->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInTitle', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title does not contain the given string. - * - * @param $title - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::dontSeeInTitle() - */ - public function dontSeeInTitle($title) { - return $this->getScenario()->runStep(new \Codeception\Step\Assertion('dontSeeInTitle', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that two variables are equal. - * - * @param $expected - * @param $actual - * @param string $message - * - * @return mixed - * @see \Codeception\Module\Asserts::assertEquals() - */ - public function assertEquals($expected, $actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEquals', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that two variables are not equal - * - * @param $expected - * @param $actual - * @param string $message - * @see \Codeception\Module\Asserts::assertNotEquals() - */ - public function assertNotEquals($expected, $actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotEquals', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that two variables are same - * - * @param $expected - * @param $actual - * @param string $message - * - * @return mixed - * @see \Codeception\Module\Asserts::assertSame() - */ - public function assertSame($expected, $actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertSame', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that two variables are not same - * - * @param $expected - * @param $actual - * @param string $message - * @see \Codeception\Module\Asserts::assertNotSame() - */ - public function assertNotSame($expected, $actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotSame', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that actual is greater than expected - * - * @param $expected - * @param $actual - * @param string $message - * @see \Codeception\Module\Asserts::assertGreaterThan() - */ - public function assertGreaterThan($expected, $actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThan', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * @deprecated - * @see \Codeception\Module\Asserts::assertGreaterThen() - */ - public function assertGreaterThen($expected, $actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThen', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that actual is greater or equal than expected - * - * @param $expected - * @param $actual - * @param string $message - * @see \Codeception\Module\Asserts::assertGreaterThanOrEqual() - */ - public function assertGreaterThanOrEqual($expected, $actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThanOrEqual', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * @deprecated - * @see \Codeception\Module\Asserts::assertGreaterThenOrEqual() - */ - public function assertGreaterThenOrEqual($expected, $actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThenOrEqual', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that actual is less than expected - * - * @param $expected - * @param $actual - * @param string $message - * @see \Codeception\Module\Asserts::assertLessThan() - */ - public function assertLessThan($expected, $actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertLessThan', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that actual is less or equal than expected - * - * @param $expected - * @param $actual - * @param string $message - * @see \Codeception\Module\Asserts::assertLessThanOrEqual() - */ - public function assertLessThanOrEqual($expected, $actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertLessThanOrEqual', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that haystack contains needle - * - * @param $needle - * @param $haystack - * @param string $message - * @see \Codeception\Module\Asserts::assertContains() - */ - public function assertContains($needle, $haystack, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertContains', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that haystack doesn't contain needle. - * - * @param $needle - * @param $haystack - * @param string $message - * @see \Codeception\Module\Asserts::assertNotContains() - */ - public function assertNotContains($needle, $haystack, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotContains', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that string match with pattern - * - * @param string $pattern - * @param string $string - * @param string $message - * @see \Codeception\Module\Asserts::assertRegExp() - */ - public function assertRegExp($pattern, $string, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertRegExp', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that string not match with pattern - * - * @param string $pattern - * @param string $string - * @param string $message - * @see \Codeception\Module\Asserts::assertNotRegExp() - */ - public function assertNotRegExp($pattern, $string, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotRegExp', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that variable is empty. - * - * @param $actual - * @param string $message - * @see \Codeception\Module\Asserts::assertEmpty() - */ - public function assertEmpty($actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEmpty', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that variable is not empty. - * - * @param $actual - * @param string $message - * @see \Codeception\Module\Asserts::assertNotEmpty() - */ - public function assertNotEmpty($actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotEmpty', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that variable is NULL - * - * @param $actual - * @param string $message - * @see \Codeception\Module\Asserts::assertNull() - */ - public function assertNull($actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNull', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that variable is not NULL - * - * @param $actual - * @param string $message - * @see \Codeception\Module\Asserts::assertNotNull() - */ - public function assertNotNull($actual, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotNull', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that condition is positive. - * - * @param $condition - * @param string $message - * @see \Codeception\Module\Asserts::assertTrue() - */ - public function assertTrue($condition, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertTrue', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that condition is negative. - * - * @param $condition - * @param string $message - * @see \Codeception\Module\Asserts::assertFalse() - */ - public function assertFalse($condition, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFalse', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if file exists - * - * @param string $filename - * @param string $message - * @see \Codeception\Module\Asserts::assertFileExists() - */ - public function assertFileExists($filename, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFileExists', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if file doesn't exists - * - * @param string $filename - * @param string $message - * @see \Codeception\Module\Asserts::assertFileNotExists() - */ - public function assertFileNotExists($filename, $message = null) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFileNotExists', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Fails the test with message. - * - * @param $message - * @see \Codeception\Module\Asserts::fail() - */ - public function fail($message) { - return $this->getScenario()->runStep(new \Codeception\Step\Action('fail', func_get_args())); - } -} diff --git a/tests/acceptance.suite.yml b/tests/acceptance.suite.yml deleted file mode 100644 index 3f02674248..0000000000 --- a/tests/acceptance.suite.yml +++ /dev/null @@ -1,12 +0,0 @@ -# Codeception Test Suite Configuration -# -# Suite for acceptance tests. -# Perform tests in browser using the WebDriver or PhpBrowser. -# If you need both WebDriver and PHPBrowser tests - create a separate suite. - -class_name: AcceptanceTester -modules: - enabled: - - PhpBrowser: - url: http://localhost/myapp - - \Helper\Acceptance diff --git a/tests/acceptance/Controllers/AccountControllerTest.php b/tests/acceptance/Controllers/AccountControllerTest.php new file mode 100644 index 0000000000..e38518d2f2 --- /dev/null +++ b/tests/acceptance/Controllers/AccountControllerTest.php @@ -0,0 +1,117 @@ +be($this->user()); + $this->call('GET', '/accounts/create/asset'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\AccountController::delete + */ + public function testDelete() + { + $this->be($this->user()); + $this->call('GET', '/accounts/delete/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\AccountController::destroy + */ + public function testDestroy() + { + $this->be($this->user()); + $this->session(['accounts.delete.url' => 'http://localhost']); + $this->call('POST', '/accounts/destroy/6'); + $this->assertSessionHas('success'); + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\AccountController::edit + */ + public function testEdit() + { + $this->be($this->user()); + $this->call('GET', '/accounts/edit/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\AccountController::index + * @covers FireflyIII\Http\Controllers\AccountController::isInArray + */ + public function testIndex() + { + $this->be($this->user()); + $this->call('GET', '/accounts/asset'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\AccountController::show + */ + public function testShow() + { + $this->be($this->user()); + $this->call('GET', '/accounts/show/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\AccountController::store + */ + public function testStore() + { + $this->be($this->user()); + $this->session(['accounts.create.url' => 'http://localhost']); + $args = [ + 'name' => 'Some kind of test account.', + 'what' => 'asset', + 'amount_currency_id_virtualBalance' => 1, + 'amount_currency_id_openingBalance' => 1, + ]; + + $this->call('POST', '/accounts/store', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + + } + + /** + * @covers FireflyIII\Http\Controllers\AccountController::update + */ + public function testUpdate() + { + $this->session(['accounts.edit.url' => 'http://localhost']); + $args = [ + 'id' => 1, + 'name' => 'TestData new name', + 'active' => 1, + ]; + $this->be($this->user()); + + $this->call('POST', '/accounts/update/1', $args); + $this->assertResponseStatus(302); + + $this->assertSessionHas('success'); + + } +} diff --git a/tests/acceptance/Controllers/AttachmentControllerTest.php b/tests/acceptance/Controllers/AttachmentControllerTest.php new file mode 100644 index 0000000000..6ad10b9bb2 --- /dev/null +++ b/tests/acceptance/Controllers/AttachmentControllerTest.php @@ -0,0 +1,85 @@ +be($this->user()); + $this->call('GET', '/attachment/delete/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\AttachmentController::destroy + */ + public function testDestroy() + { + $this->be($this->user()); + $this->session(['attachments.delete.url' => 'http://localhost']); + $this->call('POST', '/attachment/destroy/2'); + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\AttachmentController::download + */ + public function testDownload() + { + $this->be($this->user()); + $this->call('GET', '/attachment/download/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\AttachmentController::edit + */ + public function testEdit() + { + $this->be($this->user()); + $this->call('GET', '/attachment/edit/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\AttachmentController::preview + */ + public function testPreview() + { + $this->be($this->user()); + $this->call('GET', '/attachment/preview/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\AttachmentController::update + */ + public function testUpdate() + { + $this->session(['attachments.edit.url' => 'http://localhost']); + + $args = [ + 'title' => 'New title', + 'description' => 'New descr', + 'notes' => 'New notes', + ]; + $this->be($this->user()); + + $this->call('POST', '/attachment/update/1', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } +} diff --git a/tests/acceptance/Controllers/Auth/AuthControllerTest.php b/tests/acceptance/Controllers/Auth/AuthControllerTest.php new file mode 100644 index 0000000000..0631aee89f --- /dev/null +++ b/tests/acceptance/Controllers/Auth/AuthControllerTest.php @@ -0,0 +1,111 @@ +call('GET', '/login'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Auth\AuthController::getLogout + */ + public function testGetLogout() + { + $this->be($this->user()); + $this->call('GET', '/logout'); + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\Auth\AuthController::getRegister + */ + public function testGetRegister() + { + $this->call('GET', '/register'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Auth\AuthController::login + */ + public function testLogin() + { + $this->call('GET', '/login'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Auth\AuthController::logout + */ + public function testLogout() + { + $this->be($this->user()); + $this->call('GET', '/logout'); + $this->assertResponseStatus(302); + + // index should now redirect: + $this->call('GET', '/'); + $this->assertResponseStatus(302); + + + } + + /** + * @covers FireflyIII\Http\Controllers\Auth\AuthController::postLogin + */ + public function testPostLogin() + { + $args = [ + 'email' => 'thegrumpydictator@gmail.com', + 'password' => 'james', + 'remember' => 1, + ]; + $this->call('POST', '/login', $args); + $this->assertResponseStatus(302); + + $this->call('GET', '/'); + $this->assertResponseStatus(200); + + + } + + /** + * @covers FireflyIII\Http\Controllers\Auth\AuthController::postRegister + */ + public function testPostRegister() + { + $args = [ + 'email' => 'thegrumpydictator+test@gmail.com', + 'password' => 'james123', + 'password_confirmation' => 'james123', + ]; + $this->call('POST', '/register', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('start'); + } + + /** + * @covers FireflyIII\Http\Controllers\Auth\AuthController::register + */ + public function testRegister() + { + $this->call('GET', '/register'); + $this->assertResponseStatus(200); + } +} diff --git a/tests/acceptance/Controllers/Auth/PasswordControllerTest.php b/tests/acceptance/Controllers/Auth/PasswordControllerTest.php new file mode 100644 index 0000000000..ed82798e4f --- /dev/null +++ b/tests/acceptance/Controllers/Auth/PasswordControllerTest.php @@ -0,0 +1,27 @@ + 'thegrumpydictator@gmail.com', + ]; + $this->call('POST', '/password/email', $args); + $this->assertResponseStatus(302); + } + +} diff --git a/tests/acceptance/Controllers/BillControllerTest.php b/tests/acceptance/Controllers/BillControllerTest.php new file mode 100644 index 0000000000..9917620b5b --- /dev/null +++ b/tests/acceptance/Controllers/BillControllerTest.php @@ -0,0 +1,141 @@ +be($this->user()); + $this->call('GET', '/bills/create'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BillController::delete + * @todo Implement testDelete(). + */ + public function testDelete() + { + $this->be($this->user()); + $this->call('GET', '/bills/delete/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BillController::destroy + */ + public function testDestroy() + { + $this->session(['bills.delete.url' => 'http://localhost']); + $this->be($this->user()); + $this->call('POST', '/bills/destroy/2'); + $this->assertSessionHas('success'); + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\BillController::edit + */ + public function testEdit() + { + $this->be($this->user()); + $this->call('GET', '/bills/edit/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BillController::index + */ + public function testIndex() + { + $this->be($this->user()); + $this->call('GET', '/bills'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BillController::rescan + */ + public function testRescan() + { + $this->be($this->user()); + $this->call('GET', '/bills/rescan/1'); + $this->assertSessionHas('success'); + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\BillController::show + */ + public function testShow() + { + $this->be($this->user()); + $this->call('GET', '/bills/show/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BillController::store + */ + public function testStore() + { + $this->session(['bills.create.url' => 'http://localhost']); + $args = [ + 'name' => 'Some test', + 'match' => 'words', + 'amount_min' => 10, + 'amount_max' => 100, + 'amount_currency_id_amount_min' => 1, + 'amount_currency_id_amount_max' => 1, + 'date' => '20160101', + 'repeat_freq' => 'monthly', + 'skip' => 0, + ]; + + $this->be($this->user()); + $this->call('POST', '/bills/store', $args); + $this->assertSessionHas('success'); + + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\BillController::update + */ + public function testUpdate() + { + $this->session(['bills.edit.url' => 'http://localhost']); + $args = [ + 'id' => 1, + 'name' => 'Some test', + 'match' => 'words', + 'amount_min' => 10, + 'amount_max' => 100, + 'amount_currency_id_amount_min' => 1, + 'amount_currency_id_amount_max' => 1, + 'date' => '20160101', + 'repeat_freq' => 'monthly', + 'skip' => 0, + ]; + + $this->be($this->user()); + $this->call('POST', '/bills/update/1', $args); + $this->assertSessionHas('success'); + + $this->assertResponseStatus(302); + } +} diff --git a/tests/acceptance/Controllers/BudgetControllerTest.php b/tests/acceptance/Controllers/BudgetControllerTest.php new file mode 100644 index 0000000000..806805cb0f --- /dev/null +++ b/tests/acceptance/Controllers/BudgetControllerTest.php @@ -0,0 +1,158 @@ + 1200, + ]; + $this->be($this->user()); + + $this->call('POST', '/budgets/amount/1', $args); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::create + */ + public function testCreate() + { + $this->be($this->user()); + $this->call('GET', '/budgets/create'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::delete + */ + public function testDelete() + { + $this->be($this->user()); + $this->call('GET', '/budgets/delete/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::destroy + */ + public function testDestroy() + { + $this->be($this->user()); + + $this->session(['budgets.delete.url' => 'http://localhost']); + $this->call('POST', '/budgets/destroy/2'); + $this->assertSessionHas('success'); + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::edit + */ + public function testEdit() + { + $this->be($this->user()); + $this->call('GET', '/budgets/edit/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::index + */ + public function testIndex() + { + $this->be($this->user()); + $this->call('GET', '/budgets'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::noBudget + */ + public function testNoBudget() + { + $this->be($this->user()); + $this->call('GET', '/budgets/list/noBudget'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::postUpdateIncome + */ + public function testPostUpdateIncome() + { + $args = [ + 'amount' => 1200, + ]; + $this->be($this->user()); + + $this->call('POST', '/budgets/income', $args); + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::show + */ + public function testShow() + { + $this->be($this->user()); + $this->call('GET', '/budgets/show/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::store + */ + public function testStore() + { + $this->be($this->user()); + $this->session(['budgets.create.url' => 'http://localhost']); + $args = [ + 'name' => 'Some kind of test budget.', + ]; + + $this->call('POST', '/budgets/store', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::update + */ + public function testUpdate() + { + $this->be($this->user()); + $this->session(['budgets.edit.url' => 'http://localhost']); + $args = [ + 'name' => 'Some kind of test budget.', + ]; + + $this->call('POST', '/budgets/update/1', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } + + /** + * @covers FireflyIII\Http\Controllers\BudgetController::updateIncome + */ + public function testUpdateIncome() + { + $this->be($this->user()); + $this->call('GET', '/budgets/income'); + $this->assertResponseStatus(200); + } +} diff --git a/tests/acceptance/Controllers/CategoryControllerTest.php b/tests/acceptance/Controllers/CategoryControllerTest.php new file mode 100644 index 0000000000..2d2bb291e3 --- /dev/null +++ b/tests/acceptance/Controllers/CategoryControllerTest.php @@ -0,0 +1,134 @@ +be($this->user()); + $this->call('GET', '/categories/create'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CategoryController::delete + */ + public function testDelete() + { + $this->be($this->user()); + $this->call('GET', '/categories/delete/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CategoryController::destroy + */ + public function testDestroy() + { + $this->be($this->user()); + + $this->session(['categories.delete.url' => 'http://localhost']); + + $this->call('POST', '/categories/destroy/2'); + $this->assertSessionHas('success'); + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\CategoryController::edit + */ + public function testEdit() + { + $this->be($this->user()); + $this->call('GET', '/categories/edit/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CategoryController::index + */ + public function testIndex() + { + $this->be($this->user()); + $this->call('GET', '/categories'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CategoryController::noCategory + */ + public function testNoCategory() + { + $this->be($this->user()); + $this->call('GET', '/categories/list/noCategory'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CategoryController::show + * @covers FireflyIII\Http\Controllers\Controller::getSumOfRange + */ + public function testShow() + { + $this->be($this->user()); + $this->call('GET', '/categories/show/1'); + $this->assertResponseStatus(200); + + } + + /** + * @covers FireflyIII\Http\Controllers\CategoryController::showWithDate + */ + public function testShowWithDate() + { + $this->be($this->user()); + $this->call('GET', '/categories/show/1/20150101'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CategoryController::store + */ + public function testStore() + { + $this->be($this->user()); + $this->session(['categories.create.url' => 'http://localhost']); + $args = [ + 'name' => 'Some kind of test cat.', + ]; + + $this->call('POST', '/categories/store', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } + + /** + * @covers FireflyIII\Http\Controllers\CategoryController::update + */ + public function testUpdate() + { + $this->be($this->user()); + $this->session(['categories.edit.url' => 'http://localhost']); + $args = [ + 'name' => 'Some kind of test category.', + ]; + + $this->call('POST', '/categories/update/1', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } +} diff --git a/tests/acceptance/Controllers/Chart/ChartAccountControllerTest.php b/tests/acceptance/Controllers/Chart/ChartAccountControllerTest.php new file mode 100644 index 0000000000..4f02f165f8 --- /dev/null +++ b/tests/acceptance/Controllers/Chart/ChartAccountControllerTest.php @@ -0,0 +1,58 @@ +be($this->user()); + $this->call('GET', '/chart/account/expense'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\AccountController::frontpage + */ + public function testFrontpage() + { + $this->be($this->user()); + $this->call('GET', '/chart/account/frontpage'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\AccountController::report + */ + public function testReport() + { + $this->be($this->user()); + $this->call('GET', '/chart/account/report/default/20160101/20160131/1'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\AccountController::single + */ + public function testSingle() + { + $this->be($this->user()); + $this->call('GET', '/chart/account/1'); + + $this->assertResponseStatus(200); + } +} diff --git a/tests/acceptance/Controllers/Chart/ChartBillControllerTest.php b/tests/acceptance/Controllers/Chart/ChartBillControllerTest.php new file mode 100644 index 0000000000..97fb4704eb --- /dev/null +++ b/tests/acceptance/Controllers/Chart/ChartBillControllerTest.php @@ -0,0 +1,37 @@ +be($this->user()); + $this->call('GET', '/chart/bill/frontpage'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\BillController::single + */ + public function testSingle() + { + $this->be($this->user()); + $this->call('GET', '/chart/bill/1'); + + $this->assertResponseStatus(200); + } +} diff --git a/tests/acceptance/Controllers/Chart/ChartBudgetControllerTest.php b/tests/acceptance/Controllers/Chart/ChartBudgetControllerTest.php new file mode 100644 index 0000000000..ab8cc339ee --- /dev/null +++ b/tests/acceptance/Controllers/Chart/ChartBudgetControllerTest.php @@ -0,0 +1,90 @@ +mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $repository->shouldReceive('getExpensesPerMonth')->once()->andReturn(new Collection([new Budget])); + $repository->shouldReceive('getFirstBudgetLimitDate')->once()->andReturn(new Carbon); + + $this->be($this->user()); + $this->call('GET', '/chart/budget/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\BudgetController::budgetLimit + */ + public function testBudgetLimit() + { + $this->be($this->user()); + $this->call('GET', '/chart/budget/1/1'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\BudgetController::frontpage + */ + public function testFrontpage() + { + $this->be($this->user()); + $this->call('GET', '/chart/budget/frontpage'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\BudgetController::multiYear + */ + public function testMultiYear() + { + + $budget = new Budget; + $budget->id = 1; + $budget->dateFormatted = '2015'; + $budget->budgeted = 120; + + $repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $repository->shouldReceive('getBudgetedPerYear')->once()->andReturn(new Collection([$budget])); + $repository->shouldReceive('getBudgetsAndExpensesPerYear')->once()->andReturn([]); + + $this->be($this->user()); + $this->call('GET', '/chart/budget/multi-year/default/20150101/20160101/1/1'); + $this->assertResponseStatus(200); + + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\BudgetController::year + */ + public function testYear() + { + $repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $repository->shouldReceive('getBudgetsAndExpensesPerMonth')->once()->andReturn([]); + + $this->be($this->user()); + $this->call('GET', '/chart/budget/year/default/20150101/20151231/1'); + $this->assertResponseStatus(200); + + } +} diff --git a/tests/acceptance/Controllers/Chart/ChartCategoryControllerTest.php b/tests/acceptance/Controllers/Chart/ChartCategoryControllerTest.php new file mode 100644 index 0000000000..0a6ccb44b0 --- /dev/null +++ b/tests/acceptance/Controllers/Chart/ChartCategoryControllerTest.php @@ -0,0 +1,105 @@ +be($this->user()); + $this->call('GET', '/chart/category/1/all'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\CategoryController::currentPeriod + */ + public function testCurrentPeriod() + { + $this->be($this->user()); + $this->call('GET', '/chart/category/1/period'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\CategoryController::earnedInPeriod + */ + public function testEarnedInPeriod() + { + $repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface'); + $repository->shouldReceive('earnedForAccountsPerMonth')->once()->andReturn(new Collection); + + $this->be($this->user()); + $this->call('GET', '/chart/category/earned-in-period/default/20150101/20151231/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\CategoryController::frontpage + */ + public function testFrontpage() + { + $repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface'); + $repository->shouldReceive('spentForAccountsPerMonth')->once()->andReturn(new Collection); + $repository->shouldReceive('sumSpentNoCategory')->once()->andReturn('120'); + + $this->be($this->user()); + $this->call('GET', '/chart/category/frontpage'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\CategoryController::multiYear + */ + public function testMultiYear() + { + $repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface'); + $repository->shouldReceive('listMultiYear')->once()->andReturn(new Collection); + + $this->be($this->user()); + $this->call('GET', '/chart/category/multi-year/default/20150101/20151231/1/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\CategoryController::specificPeriod + */ + public function testSpecificPeriod() + { + $this->be($this->user()); + $this->call('GET', '/chart/category/1/period/20150101'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\CategoryController::spentInPeriod + */ + public function testSpentInPeriod() + { + + + $repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface'); + $repository->shouldReceive('spentForAccountsPerMonth')->once()->andReturn(new Collection); + + $this->be($this->user()); + $this->call('GET', '/chart/category/spent-in-period/default/20150101/20151231/1'); + $this->assertResponseStatus(200); + + } +} diff --git a/tests/acceptance/Controllers/Chart/ChartPiggyBankControllerTest.php b/tests/acceptance/Controllers/Chart/ChartPiggyBankControllerTest.php new file mode 100644 index 0000000000..ce3ae5beba --- /dev/null +++ b/tests/acceptance/Controllers/Chart/ChartPiggyBankControllerTest.php @@ -0,0 +1,25 @@ +be($this->user()); + $this->call('GET', '/chart/piggy-bank/1'); + $this->assertResponseStatus(200); + } +} diff --git a/tests/acceptance/Controllers/Chart/ChartReportControllerTest.php b/tests/acceptance/Controllers/Chart/ChartReportControllerTest.php new file mode 100644 index 0000000000..93fdba8cd1 --- /dev/null +++ b/tests/acceptance/Controllers/Chart/ChartReportControllerTest.php @@ -0,0 +1,42 @@ +mock('FireflyIII\Helpers\Report\ReportQueryInterface'); + $repository->shouldReceive('spentPerMonth')->once()->andReturn([]); + $repository->shouldReceive('earnedPerMonth')->once()->andReturn([]); + + $this->be($this->user()); + $this->call('GET', '/chart/report/in-out/default/20150101/20151231/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\Chart\ReportController::yearInOutSummarized + */ + public function testYearInOutSummarized() + { + $repository = $this->mock('FireflyIII\Helpers\Report\ReportQueryInterface'); + $repository->shouldReceive('spentPerMonth')->once()->andReturn([]); + $repository->shouldReceive('earnedPerMonth')->once()->andReturn([]); + + $this->be($this->user()); + $this->call('GET', '/chart/report/in-out-sum/default/20150101/20151231/1'); + $this->assertResponseStatus(200); + } +} diff --git a/tests/acceptance/Controllers/CsvControllerTest.php b/tests/acceptance/Controllers/CsvControllerTest.php new file mode 100644 index 0000000000..9b46be9a58 --- /dev/null +++ b/tests/acceptance/Controllers/CsvControllerTest.php @@ -0,0 +1,251 @@ +be($this->user()); + + // create session data: + $this->session($this->getSessionData()); + + $this->call('GET', '/csv/column_roles'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CsvController::downloadConfig + */ + public function testDownloadConfig() + { + $this->be($this->user()); + $this->session($this->getSessionData()); + $this->call('GET', '/csv/download-config'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CsvController::downloadConfigPage + */ + public function testDownloadConfigPage() + { + $this->be($this->user()); + $this->session($this->getSessionData()); + $this->call('GET', '/csv/download'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CsvController::index + */ + public function testIndex() + { + + $this->be($this->user()); + $this->call('GET', '/csv'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CsvController::initialParse + */ + public function testInitialParse() + { + $this->be($this->user()); + // post data: + $postData = [ + 'role' => [ + 0 => 'account-iban', + 1 => 'opposing-iban', + 2 => 'description', + 3 => 'date-transaction', + 4 => 'amount', + 5 => 'category-name', + 6 => 'budget-name', + ], + 'map' => [0 => 1, 1 => 1], + ]; + + // create session data: + $this->session($this->getSessionData()); + + + $this->call('POST', '/csv/initial_parse', $postData); + // should be redirect + $this->assertResponseStatus(302); + + // should be redirected to mapping: + $this->assertRedirectedToRoute('csv.map'); + } + + /** + * @covers FireflyIII\Http\Controllers\CsvController::initialParse + */ + public function testInitialParseNoMap() + { + $this->be($this->user()); + // post data: + $postData = [ + 'role' => [ + 0 => 'account-iban', + 1 => 'opposing-iban', + 2 => 'description', + 3 => 'date-transaction', + 4 => 'amount', + 5 => 'category-name', + 6 => 'budget-name', + ], + 'map' => [], + ]; + + // create session data: + $this->session($this->getSessionData()); + + + $this->call('POST', '/csv/initial_parse', $postData); + // should be redirect + $this->assertResponseStatus(302); + + // should be redirected to download config: + $this->assertRedirectedToRoute('csv.download-config-page'); + } + + /** + * @covers FireflyIII\Http\Controllers\CsvController::map + */ + public function testMap() + { + $this->be($this->user()); + + $this->session($this->getSessionData()); + + $this->call('GET', '/csv/map'); + $this->assertResponseStatus(200); + + } + + /** + * @covers FireflyIII\Http\Controllers\CsvController::process + */ + public function testProcess() + { + $this->be($this->user()); + $this->session($this->getSessionData()); + $this->call('GET', '/csv/process'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CsvController::saveMapping + */ + public function testSaveMapping() + { + $this->be($this->user()); + $this->session($this->getSessionData()); + $postData = [ + 'mapping' + => [0 => ['NL11XOLA6707795988' => '1',], + 1 => ['NL10TAPT8906262744' => '0', 'NL93UPSZ1261542703' => '0', 'NL86IHAL3264575116' => '0', 'NL63BKBO9993148806' => '0', + 'NL22EZVA6611573534' => '0', 'NL40KZVR5107424627' => '0', 'NL29RHEE6437366575' => '0', 'NL63IEPJ7437420074' => '0', + 'NL62HQWJ8837203470' => '0', 'NL89FPEA1494900858' => '0', 'NL76MDMU3222445567' => '0', 'NL07TDQA3309954056' => '0', + 'NL35MKIY9736938778' => '0', 'NL56DNGY5455310496' => '0', 'NL17LKFR7594179781' => '0', 'NL76UJQI9524250446' => '0', + 'NL45YTPP6157249080' => '0', 'NL46TFVH5548690248' => '0', 'NL79XZWN0846248670' => '0', 'NL52MKIO8325583045' => '0', + 'NL47YVJU4419567422' => '0', 'NL04TNIP4218080631' => '0', 'NL68SOAC3516744723' => '0', 'NL53YVTS7223912863' => '0', + 'NL40QRBS9553175317' => '0', 'NL54TZNZ2922111989' => '0', 'NL04BAGX3284775110' => '0', 'NL49LULH7261231215' => '0', + 'NL11YHMI8046080217' => '0', 'NL89BXNF2470379032' => '0', 'NL74SHGG7300113478' => '0', 'NL48ZPLO1718215436' => '0', + 'NL13BJMO5341591615' => '0', 'NL59PKVU0116767154' => '0', 'NL72BQRL1220175315' => '0', 'NL53QHDG0329036955' => '0', + 'NL48BLDJ9721843563' => '0', 'NL48BHXI9733658006' => '0', 'NL33VPSU8067103542' => '0', 'NL62UDLY8957139303' => '0', + 'NL28EDMD2653501341' => '0', 'NL92QMZD6854625548' => '0', 'NL37VSLJ0853659915' => '0', 'NL95NQHS4363870109' => '0', + 'NL81LEJP9477634344' => '0', 'NL14JYVJ1041891180' => '0', 'NL57SPBS0788124528' => '0', + 'NL96DZCO4665940223' => '2',],],]; + + $this->call('POST', '/csv/save_mapping', $postData); + + $this->assertResponseStatus(302); + $this->assertRedirectedToRoute('csv.download-config-page'); + + } + + /** + * @covers FireflyIII\Http\Controllers\CsvController::upload + */ + public function testUpload() + { + $this->be($this->user()); + + $file = new UploadedFile(storage_path('build/test-upload.csv'), 'test-file.csv', 'text/plain', 446); + $args = [ + 'date_format' => 'Ymd', + 'csv_import_account' => 1, + ]; + + $this->call('POST', '/csv/upload', $args, [], ['csv' => $file]); + + // csv data set: + //$this->assertSessionHas('csv-file', 'abc'); + $this->assertSessionHas('csv-date-format', 'Ymd'); + $this->assertSessionHas('csv-has-headers', false); + $this->assertSessionHas('csv-map', []); + $this->assertSessionHas('csv-mapped', []); + $this->assertSessionHas('csv-roles', []); + $this->assertSessionHas('csv-specifix', []); + $this->assertSessionHas('csv-import-account', 1); + $this->assertSessionHas('csv-delimiter', ','); + + $this->assertResponseStatus(302); + } + + /** + * @return string + */ + protected function createUploadedFile() + { + $original = storage_path('build/test-upload.csv'); + $time = '12345'; + $fileName = 'csv-upload-' . $this->user()->id . '-' . $time . '.csv.encrypted'; + $fullPath = storage_path('build') . DIRECTORY_SEPARATOR . $fileName; + + if (!file_exists($fullPath)) { + $content = file_get_contents($original); + $contentEncrypted = Crypt::encrypt($content); + file_put_contents($fullPath, $contentEncrypted); + } + + return $fullPath; + } + + /** + * @return array + */ + protected function getSessionData() + { + return [ + 'csv-file' => $this->createUploadedFile(), + 'csv-date-format' => 'Ymd', + 'csv-has-headers' => false, + 'csv-import-account' => 1, + 'csv-delimiter' => ',', + 'csv-specifix' => ['Dummy'], + 'csv-roles' => [0 => 'account-iban', 1 => 'opposing-iban', 2 => 'description', 3 => 'date-transaction', 4 => 'amount', + 5 => 'category-name', 6 => 'budget-name',], + 'csv-map' => [0 => 'account-iban', 1 => 'opposing-iban',], + 'csv-mapped' => [0 => ['NL11XOLA6707795988' => '1',], 1 => ['NL96DZCO4665940223' => '2',]], + ]; + } +} diff --git a/tests/acceptance/Controllers/CurrencyControllerTest.php b/tests/acceptance/Controllers/CurrencyControllerTest.php new file mode 100644 index 0000000000..eafd8d193e --- /dev/null +++ b/tests/acceptance/Controllers/CurrencyControllerTest.php @@ -0,0 +1,123 @@ +be($this->user()); + $this->call('GET', '/currency/create'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CurrencyController::defaultCurrency + */ + public function testDefaultCurrency() + { + $this->be($this->user()); + $this->call('GET', '/currency/default/2'); + $this->assertResponseStatus(302); + $this->assertRedirectedToRoute('currency.index'); + $this->assertSessionHas('success'); + } + + /** + * @covers FireflyIII\Http\Controllers\CurrencyController::delete + */ + public function testDelete() + { + $this->be($this->user()); + $this->call('GET', '/currency/delete/2'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CurrencyController::destroy + */ + public function testDestroy() + { + $this->session(['currency.delete.url' => 'http://localhost/currency']); + $this->be($this->user()); + $this->call('POST', '/currency/destroy/3'); + $this->assertSessionHas('success'); + $this->assertRedirectedToRoute('currency.index'); + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\CurrencyController::edit + */ + public function testEdit() + { + $this->be($this->user()); + $this->call('GET', '/currency/edit/2'); + $this->assertResponseStatus(200); + + } + + /** + * @covers FireflyIII\Http\Controllers\CurrencyController::index + */ + public function testIndex() + { + $this->be($this->user()); + $this->call('GET', '/currency'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\CurrencyController::store + */ + public function testStore() + { + $this->be($this->user()); + $this->session(['currency.create.url' => 'http://localhost/currency']); + $args = [ + 'name' => 'New Euro.', + 'symbol' => 'Y', + 'code' => 'IUY', + ]; + + $this->call('POST', '/currency/store', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + $this->assertRedirectedToRoute('currency.index'); + } + + /** + * @covers FireflyIII\Http\Controllers\CurrencyController::update + */ + public function testUpdate() + { + $this->session(['currency.edit.url' => 'http://localhost/currency']); + + $args = [ + 'id' => 1, + 'name' => 'New Euro.', + 'symbol' => 'Y', + 'code' => 'IUY', + ]; + $this->be($this->user()); + + $this->call('POST', '/currency/update/1', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + $this->assertRedirectedToRoute('currency.index'); + + } +} diff --git a/tests/acceptance/Controllers/HelpControllerTest.php b/tests/acceptance/Controllers/HelpControllerTest.php new file mode 100644 index 0000000000..e327a9f57f --- /dev/null +++ b/tests/acceptance/Controllers/HelpControllerTest.php @@ -0,0 +1,38 @@ +be($this->user()); + $this->call('GET', '/help/index'); + + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\HelpController::show + */ + public function testShowNoRoute() + { + $this->be($this->user()); + $this->call('GET', '/help/indxxex'); + + $this->assertResponseStatus(200); + } +} diff --git a/tests/acceptance/Controllers/HomeControllerTest.php b/tests/acceptance/Controllers/HomeControllerTest.php new file mode 100644 index 0000000000..fdb855aac6 --- /dev/null +++ b/tests/acceptance/Controllers/HomeControllerTest.php @@ -0,0 +1,51 @@ +be($this->user()); + + $args = [ + 'start' => '2012-01-01', + 'end' => '2012-04-01', + ]; + + // if date range is > 50, should have flash. + $this->call('POST', '/daterange', $args); + $this->assertResponseStatus(200); + $this->assertSessionHas('warning', '91 days of data may take a while to load.'); + } + + /** + * @covers FireflyIII\Http\Controllers\HomeController::flush + */ + public function testFlush() + { + $this->be($this->user()); + $this->call('GET', '/flush'); + $this->assertResponseStatus(302); + } + + /** + * @covers FireflyIII\Http\Controllers\HomeController::index + * @covers FireflyIII\Http\Controllers\Controller::__construct + */ + public function testIndex() + { + $this->be($this->user()); + $this->call('GET', '/'); + $this->assertResponseStatus(200); + } +} \ No newline at end of file diff --git a/tests/acceptance/Controllers/JsonControllerTest.php b/tests/acceptance/Controllers/JsonControllerTest.php new file mode 100644 index 0000000000..e8ba9f8c16 --- /dev/null +++ b/tests/acceptance/Controllers/JsonControllerTest.php @@ -0,0 +1,154 @@ +be($this->user()); + $this->call('GET', '/json/action'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::boxBillsPaid + */ + public function testBoxBillsPaid() + { + $this->be($this->user()); + $this->call('GET', '/json/box/bills-paid'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::boxBillsUnpaid + */ + public function testBoxBillsUnpaid() + { + $this->be($this->user()); + $this->call('GET', '/json/box/bills-unpaid'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::boxIn + */ + public function testBoxIn() + { + $this->be($this->user()); + $this->call('GET', '/json/box/in'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::boxOut + */ + public function testBoxOut() + { + $this->be($this->user()); + $this->call('GET', '/json/box/out'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::categories + */ + public function testCategories() + { + $this->be($this->user()); + $this->call('GET', '/json/categories'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::endTour + */ + public function testEndTour() + { + $this->be($this->user()); + $response = $this->call('POST', '/json/end-tour'); + $this->assertResponseStatus(200); + $this->assertEquals('"true"', $response->content()); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::expenseAccounts + */ + public function testExpenseAccounts() + { + $this->be($this->user()); + $this->call('GET', '/json/expense-accounts'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::revenueAccounts + */ + public function testRevenueAccounts() + { + $this->be($this->user()); + $this->call('GET', '/json/revenue-accounts'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::tags + */ + public function testTags() + { + $this->be($this->user()); + $this->call('GET', '/json/tags'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::tour + */ + public function testTour() + { + $this->be($this->user()); + $this->call('GET', '/json/tour'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::transactionJournals + */ + public function testTransactionJournals() + { + $type = factory(FireflyIII\Models\TransactionType::class)->make(); + $repository = $this->mock('FireflyIII\Repositories\Journal\JournalRepositoryInterface'); + + $repository->shouldReceive('getTransactionType')->with('deposit')->once()->andReturn($type); + $repository->shouldReceive('getJournalsOfType')->with($type)->once()->andReturn(new Collection); + + $this->be($this->user()); + $this->call('GET', '/json/transaction-journals/deposit'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\JsonController::trigger + */ + public function testTrigger() + { + $this->be($this->user()); + $this->call('GET', '/json/trigger'); + $this->assertResponseStatus(200); + } +} diff --git a/tests/acceptance/Controllers/NewUserControllerTest.php b/tests/acceptance/Controllers/NewUserControllerTest.php new file mode 100644 index 0000000000..01841352f4 --- /dev/null +++ b/tests/acceptance/Controllers/NewUserControllerTest.php @@ -0,0 +1,54 @@ +be($this->emptyUser()); + $this->call('GET', '/'); + $this->assertResponseStatus(302); + $this->assertRedirectedToRoute('new-user.index'); + } + + /** + * @covers FireflyIII\Http\Controllers\NewUserController::index + */ + public function testIndexGo() + { + $this->be($this->emptyUser()); + $this->call('GET', '/new-user'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\NewUserController::submit + */ + public function testSubmit() + { + $this->be($this->emptyUser()); + + $args = [ + 'bank_name' => 'New bank', + 'bank_balance' => 100, + ]; + + $this->call('POST', '/new-user/submit', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } +} diff --git a/tests/acceptance/Controllers/PiggyBankControllerTest.php b/tests/acceptance/Controllers/PiggyBankControllerTest.php new file mode 100644 index 0000000000..2ab8691f3d --- /dev/null +++ b/tests/acceptance/Controllers/PiggyBankControllerTest.php @@ -0,0 +1,182 @@ +be($this->user()); + $this->call('GET', '/piggy-banks/add/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::create + */ + public function testCreate() + { + $this->be($this->user()); + $this->call('GET', '/piggy-banks/create'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::delete + * @todo Implement testDelete(). + */ + public function testDelete() + { + $this->be($this->user()); + $this->call('GET', '/piggy-banks/delete/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::destroy + */ + public function testDestroy() + { + $this->be($this->user()); + $this->session(['piggy-banks.delete.url' => 'http://localhost']); + $this->call('POST', '/piggy-banks/destroy/2'); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::edit + */ + public function testEdit() + { + $this->be($this->user()); + $this->call('GET', '/piggy-banks/edit/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::index + */ + public function testIndex() + { + $this->be($this->user()); + $this->call('GET', '/piggy-banks'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::order + */ + public function testOrder() + { + $args = [ + 1 => 1, + 2 => 2, + ]; + + $this->be($this->user()); + $this->call('POST', '/piggy-banks/sort', $args); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::postAdd + * @todo Implement testPostAdd(). + */ + public function testPostAdd() + { + $args = [ + 'amount' => 100, + ]; + + $this->be($this->user()); + $this->call('POST', '/piggy-banks/add/1', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::postRemove + */ + public function testPostRemove() + { + $args = [ + 'amount' => 100, + ]; + + $this->be($this->user()); + $this->call('POST', '/piggy-banks/remove/1', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::remove + */ + public function testRemove() + { + $this->be($this->user()); + $this->call('GET', '/piggy-banks/remove/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::show + */ + public function testShow() + { + $this->be($this->user()); + $this->call('GET', '/piggy-banks/show/1'); + $this->assertResponseStatus(200); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::store + */ + public function testStore() + { + $this->be($this->user()); + $this->session(['piggy-banks.create.url' => 'http://localhost/']); + + $args = [ + 'name' => 'New', + 'targetamount' => 100, + 'account_id' => 2, + ]; + + $this->call('POST', '/piggy-banks/store', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } + + /** + * @covers FireflyIII\Http\Controllers\PiggyBankController::update + */ + public function testUpdate() + { + $this->be($this->user()); + $this->session(['piggy-banks.edit.url' => 'http://localhost/']); + + $args = [ + 'name' => 'Updated', + 'targetamount' => 100, + 'account_id' => 2, + ]; + + $this->call('POST', '/piggy-banks/update/1', $args); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + } +} diff --git a/tests/acceptance/Controllers/PreferencesControllerTest.php b/tests/acceptance/Controllers/PreferencesControllerTest.php new file mode 100644 index 0000000000..4fbf98a051 --- /dev/null +++ b/tests/acceptance/Controllers/PreferencesControllerTest.php @@ -0,0 +1,40 @@ +markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\PreferencesController::postIndex + * @todo Implement testPostIndex(). + */ + public function testPostIndex() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} diff --git a/tests/acceptance/Controllers/ProfileControllerTest.php b/tests/acceptance/Controllers/ProfileControllerTest.php new file mode 100644 index 0000000000..ffdf216572 --- /dev/null +++ b/tests/acceptance/Controllers/ProfileControllerTest.php @@ -0,0 +1,75 @@ +markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\ProfileController::deleteAccount + * @todo Implement testDeleteAccount(). + */ + public function testDeleteAccount() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\ProfileController::index + * @todo Implement testIndex(). + */ + public function testIndex() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\ProfileController::postChangePassword + * @todo Implement testPostChangePassword(). + */ + public function testPostChangePassword() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\ProfileController::postDeleteAccount + * @todo Implement testPostDeleteAccount(). + */ + public function testPostDeleteAccount() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} diff --git a/tests/acceptance/Controllers/ReportControllerTest.php b/tests/acceptance/Controllers/ReportControllerTest.php new file mode 100644 index 0000000000..641f7def38 --- /dev/null +++ b/tests/acceptance/Controllers/ReportControllerTest.php @@ -0,0 +1,75 @@ +markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\ReportController::defaultMultiYear + * @todo Implement testDefaultMultiYear(). + */ + public function testDefaultMultiYear() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\ReportController::defaultYear + * @todo Implement testDefaultYear(). + */ + public function testDefaultYear() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\ReportController::index + * @todo Implement testIndex(). + */ + public function testIndex() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\ReportController::report + * @todo Implement testReport(). + */ + public function testReport() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} diff --git a/tests/acceptance/Controllers/RuleControllerTest.php b/tests/acceptance/Controllers/RuleControllerTest.php new file mode 100644 index 0000000000..b33352c035 --- /dev/null +++ b/tests/acceptance/Controllers/RuleControllerTest.php @@ -0,0 +1,148 @@ +markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleController::delete + * @todo Implement testDelete(). + */ + public function testDelete() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleController::destroy + * @todo Implement testDestroy(). + */ + public function testDestroy() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleController::down + * @todo Implement testDown(). + */ + public function testDown() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleController::edit + * @todo Implement testEdit(). + */ + public function testEdit() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleController::index + * @todo Implement testIndex(). + */ + public function testIndex() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleController::reorderRuleActions + * @todo Implement testReorderRuleActions(). + */ + public function testReorderRuleActions() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleController::reorderRuleTriggers + * @todo Implement testReorderRuleTriggers(). + */ + public function testReorderRuleTriggers() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleController::store + * @todo Implement testStore(). + */ + public function testStore() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleController::up + * @todo Implement testUp(). + */ + public function testUp() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleController::update + * @todo Implement testUpdate(). + */ + public function testUpdate() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} diff --git a/tests/acceptance/Controllers/RuleGroupControllerTest.php b/tests/acceptance/Controllers/RuleGroupControllerTest.php new file mode 100644 index 0000000000..f23e52417c --- /dev/null +++ b/tests/acceptance/Controllers/RuleGroupControllerTest.php @@ -0,0 +1,112 @@ +markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleGroupController::delete + * @todo Implement testDelete(). + */ + public function testDelete() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleGroupController::destroy + * @todo Implement testDestroy(). + */ + public function testDestroy() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleGroupController::down + * @todo Implement testDown(). + */ + public function testDown() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleGroupController::edit + * @todo Implement testEdit(). + */ + public function testEdit() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleGroupController::store + * @todo Implement testStore(). + */ + public function testStore() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleGroupController::up + * @todo Implement testUp(). + */ + public function testUp() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\RuleGroupController::update + * @todo Implement testUpdate(). + */ + public function testUpdate() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} diff --git a/tests/acceptance/Controllers/SearchControllerTest.php b/tests/acceptance/Controllers/SearchControllerTest.php new file mode 100644 index 0000000000..70f44bc0bc --- /dev/null +++ b/tests/acceptance/Controllers/SearchControllerTest.php @@ -0,0 +1,27 @@ +markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} diff --git a/tests/acceptance/Controllers/TagControllerTest.php b/tests/acceptance/Controllers/TagControllerTest.php new file mode 100644 index 0000000000..8aa3cad951 --- /dev/null +++ b/tests/acceptance/Controllers/TagControllerTest.php @@ -0,0 +1,124 @@ +markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TagController::delete + * @todo Implement testDelete(). + */ + public function testDelete() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TagController::destroy + * @todo Implement testDestroy(). + */ + public function testDestroy() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TagController::edit + * @todo Implement testEdit(). + */ + public function testEdit() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TagController::hideTagHelp + * @todo Implement testHideTagHelp(). + */ + public function testHideTagHelp() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TagController::index + * @todo Implement testIndex(). + */ + public function testIndex() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TagController::show + * @todo Implement testShow(). + */ + public function testShow() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TagController::store + * @todo Implement testStore(). + */ + public function testStore() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TagController::update + * @todo Implement testUpdate(). + */ + public function testUpdate() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} diff --git a/tests/acceptance/Controllers/TransactionControllerTest.php b/tests/acceptance/Controllers/TransactionControllerTest.php new file mode 100644 index 0000000000..937acaccb8 --- /dev/null +++ b/tests/acceptance/Controllers/TransactionControllerTest.php @@ -0,0 +1,124 @@ +markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TransactionController::delete + * @todo Implement testDelete(). + */ + public function testDelete() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TransactionController::destroy + * @todo Implement testDestroy(). + */ + public function testDestroy() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TransactionController::edit + * @todo Implement testEdit(). + */ + public function testEdit() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TransactionController::index + * @todo Implement testIndex(). + */ + public function testIndex() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TransactionController::reorder + * @todo Implement testReorder(). + */ + public function testReorder() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TransactionController::show + * @todo Implement testShow(). + */ + public function testShow() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TransactionController::store + * @todo Implement testStore(). + */ + public function testStore() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * @covers FireflyIII\Http\Controllers\TransactionController::update + * @todo Implement testUpdate(). + */ + public function testUpdate() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} diff --git a/tests/acceptance/_bootstrap.php b/tests/acceptance/_bootstrap.php deleted file mode 100644 index 8a88555806..0000000000 --- a/tests/acceptance/_bootstrap.php +++ /dev/null @@ -1,2 +0,0 @@ -