diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000..07b13be62b --- /dev/null +++ b/.env.example @@ -0,0 +1,16 @@ +APP_ENV=local +APP_DEBUG=true +APP_KEY=SomeRandomString + +DB_CONNECTION=mysql +DB_HOST=localhost +DB_DATABASE=homestead +DB_USERNAME=homestead +DB_PASSWORD=secret + +CACHE_DRIVER=file +SESSION_DRIVER=file + +EMAIL_SMTP= +EMAIL_USERNAME= +EMAIL_PASSWORD= diff --git a/.env.testing b/.env.testing new file mode 100644 index 0000000000..887ffc6968 --- /dev/null +++ b/.env.testing @@ -0,0 +1,13 @@ +APP_ENV=testing +APP_DEBUG=true +APP_KEY=SomeRandomString + +DB_CONNECTION=sqlite +DB_HOST=localhost +DB_DATABASE=homestead +DB_USERNAME=homestead +DB_PASSWORD=secret + +CACHE_DRIVER=file +SESSION_DRIVER=file + diff --git a/.gitignore b/.gitignore index 90cd6c6a45..ddec920a30 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ /bootstrap/compiled.php /vendor composer.phar -.env.*.php -.env.php Thumbs.db .idea/ tests/_output/* @@ -25,3 +23,5 @@ tests/_data/dump.sql db.sqlite_snapshot c3.php db.sqlite-journal +tests/_output/* +.env diff --git a/.travis.yml b/.travis.yml index 102eb830b2..e96ea998f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,11 +11,13 @@ addons: install: - rm composer.lock - composer install + - php artisan env + - mv -v .env.testing .env script: - ./tests/_data/db.sh - php vendor/bin/codecept build - - php vendor/bin/codecept run --coverage --coverage-xml + - php vendor/bin/codecept run --coverage --coverage-xml --no-exit after_script: - cp -v tests/_output/coverage.xml build/logs/clover.xml diff --git a/README.md b/README.md index 5a0777ec10..1f72b826a5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Firefly III (v3.2.5) +Firefly III (v3.3) =========== [![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=develop)](https://travis-ci.org/JC5/firefly-iii) diff --git a/_sql/firefly-iii-reference-3.2.2.sql b/_sql/firefly-iii-reference-3.2.2.sql deleted file mode 100644 index 9305d9d8c5..0000000000 --- a/_sql/firefly-iii-reference-3.2.2.sql +++ /dev/null @@ -1,606 +0,0 @@ -# ************************************************************ -# Sequel Pro SQL dump -# Version 4096 -# -# http://www.sequelpro.com/ -# http://code.google.com/p/sequel-pro/ -# -# Host: 127.0.0.1 (MySQL 5.6.19-0ubuntu0.14.04.1) -# Database: homestead -# Generation Time: 2015-01-02 19:01:30 +0000 -# ************************************************************ - - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - - -# Dump of table account_meta -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `account_meta`; - -CREATE TABLE `account_meta` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `account_id` int(10) unsigned NOT NULL, - `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `data` text COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `account_meta_account_id_name_unique` (`account_id`,`name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table account_types -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `account_types`; - -CREATE TABLE `account_types` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `type` varchar(30) COLLATE utf8_unicode_ci NOT NULL, - `editable` tinyint(1) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `account_types_type_unique` (`type`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -LOCK TABLES `account_types` WRITE; -/*!40000 ALTER TABLE `account_types` DISABLE KEYS */; - -INSERT INTO `account_types` (`id`, `created_at`, `updated_at`, `type`, `editable`) -VALUES - (1,'2015-01-02 19:00:13','2015-01-02 19:00:13','Default account',1), - (2,'2015-01-02 19:00:13','2015-01-02 19:00:13','Cash account',0), - (3,'2015-01-02 19:00:13','2015-01-02 19:00:13','Asset account',1), - (4,'2015-01-02 19:00:13','2015-01-02 19:00:13','Expense account',1), - (5,'2015-01-02 19:00:13','2015-01-02 19:00:13','Revenue account',1), - (6,'2015-01-02 19:00:13','2015-01-02 19:00:13','Initial balance account',0), - (7,'2015-01-02 19:00:13','2015-01-02 19:00:13','Beneficiary account',1), - (8,'2015-01-02 19:00:13','2015-01-02 19:00:13','Import account',0); - -/*!40000 ALTER TABLE `account_types` ENABLE KEYS */; -UNLOCK TABLES; - - -# Dump of table accounts -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `accounts`; - -CREATE TABLE `accounts` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `user_id` int(10) unsigned NOT NULL, - `account_type_id` int(10) unsigned NOT NULL, - `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `active` tinyint(1) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `accounts_user_id_account_type_id_name_unique` (`user_id`,`account_type_id`,`name`), - KEY `accounts_account_type_id_foreign` (`account_type_id`), - CONSTRAINT `accounts_account_type_id_foreign` FOREIGN KEY (`account_type_id`) REFERENCES `account_types` (`id`) ON DELETE CASCADE, - CONSTRAINT `accounts_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table bills -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `bills`; - -CREATE TABLE `bills` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `user_id` int(10) unsigned NOT NULL, - `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL, - `match` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `amount_min` decimal(10,2) NOT NULL, - `amount_max` decimal(10,2) NOT NULL, - `date` date NOT NULL, - `active` tinyint(1) NOT NULL, - `automatch` tinyint(1) NOT NULL, - `repeat_freq` enum('daily','weekly','monthly','quarterly','half-year','yearly') COLLATE utf8_unicode_ci NOT NULL, - `skip` smallint(5) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `uid_name_unique` (`user_id`,`name`), - CONSTRAINT `bills_uid_for` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table budget_limits -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `budget_limits`; - -CREATE TABLE `budget_limits` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `budget_id` int(10) unsigned DEFAULT NULL, - `startdate` date NOT NULL, - `amount` decimal(10,2) NOT NULL, - `repeats` tinyint(1) NOT NULL, - `repeat_freq` enum('daily','weekly','monthly','quarterly','half-year','yearly') COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `unique_ci_combi` (`startdate`,`repeat_freq`), - UNIQUE KEY `unique_bl_combi` (`budget_id`,`startdate`,`repeat_freq`), - CONSTRAINT `bid_foreign` FOREIGN KEY (`budget_id`) REFERENCES `budgets` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table budget_transaction_journal -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `budget_transaction_journal`; - -CREATE TABLE `budget_transaction_journal` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `budget_id` int(10) unsigned NOT NULL, - `transaction_journal_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `budid_tjid_unique` (`budget_id`,`transaction_journal_id`), - KEY `budget_transaction_journal_transaction_journal_id_foreign` (`transaction_journal_id`), - CONSTRAINT `budget_transaction_journal_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE, - CONSTRAINT `budget_transaction_journal_budget_id_foreign` FOREIGN KEY (`budget_id`) REFERENCES `budgets` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table budgets -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `budgets`; - -CREATE TABLE `budgets` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL, - `user_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `budgets_user_id_name_unique` (`user_id`,`name`), - CONSTRAINT `budgets_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table categories -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `categories`; - -CREATE TABLE `categories` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL, - `user_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `categories_user_id_name_unique` (`user_id`,`name`), - CONSTRAINT `categories_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table category_transaction_journal -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `category_transaction_journal`; - -CREATE TABLE `category_transaction_journal` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `category_id` int(10) unsigned NOT NULL, - `transaction_journal_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `catid_tjid_unique` (`category_id`,`transaction_journal_id`), - KEY `category_transaction_journal_transaction_journal_id_foreign` (`transaction_journal_id`), - CONSTRAINT `category_transaction_journal_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE, - CONSTRAINT `category_transaction_journal_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table components -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `components`; - -CREATE TABLE `components` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL, - `user_id` int(10) unsigned NOT NULL, - `class` varchar(20) COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `components_user_id_class_name_unique` (`user_id`,`class`,`name`), - CONSTRAINT `components_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table limit_repetitions -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `limit_repetitions`; - -CREATE TABLE `limit_repetitions` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `budget_limit_id` int(10) unsigned NOT NULL, - `startdate` date NOT NULL, - `enddate` date NOT NULL, - `amount` decimal(10,2) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `limit_repetitions_limit_id_startdate_enddate_unique` (`budget_limit_id`,`startdate`,`enddate`), - CONSTRAINT `limit_repetitions_limit_id_foreign` FOREIGN KEY (`budget_limit_id`) REFERENCES `budget_limits` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table migrations -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `migrations`; - -CREATE TABLE `migrations` ( - `migration` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `batch` int(11) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -LOCK TABLES `migrations` WRITE; -/*!40000 ALTER TABLE `migrations` DISABLE KEYS */; - -INSERT INTO `migrations` (`migration`, `batch`) -VALUES - ('2014_06_27_163032_create_users_table',1), - ('2014_06_27_163145_create_account_types_table',1), - ('2014_06_27_163259_create_accounts_table',1), - ('2014_06_27_163817_create_components_table',1), - ('2014_06_27_163818_create_piggybanks_table',1), - ('2014_06_27_164042_create_transaction_currencies_table',1), - ('2014_06_27_164512_create_transaction_types_table',1), - ('2014_06_27_164619_create_recurring_transactions_table',1), - ('2014_06_27_164620_create_transaction_journals_table',1), - ('2014_06_27_164836_create_transactions_table',1), - ('2014_06_27_165344_create_component_transaction_table',1), - ('2014_07_05_171326_create_component_transaction_journal_table',1), - ('2014_07_06_123842_create_preferences_table',1), - ('2014_07_09_204843_create_session_table',1), - ('2014_07_17_183717_create_limits_table',1), - ('2014_07_19_055011_create_limit_repeat_table',1), - ('2014_08_06_044416_create_component_recurring_transaction_table',1), - ('2014_08_12_173919_create_piggybank_repetitions_table',1), - ('2014_08_18_100330_create_piggybank_events_table',1), - ('2014_08_23_113221_create_reminders_table',1), - ('2014_11_10_172053_create_account_meta_table',1), - ('2014_11_29_135749_create_transaction_groups_table',1), - ('2014_11_29_140217_create_transaction_group_transaction_journal_table',1), - ('2014_12_13_190730_changes_for_v321',1), - ('2014_12_24_191544_changes_for_v322',1); - -/*!40000 ALTER TABLE `migrations` ENABLE KEYS */; -UNLOCK TABLES; - - -# Dump of table piggy_bank_events -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `piggy_bank_events`; - -CREATE TABLE `piggy_bank_events` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `piggy_bank_id` int(10) unsigned NOT NULL, - `transaction_journal_id` int(10) unsigned DEFAULT NULL, - `date` date NOT NULL, - `amount` decimal(10,2) NOT NULL, - PRIMARY KEY (`id`), - KEY `piggybank_events_piggybank_id_foreign` (`piggy_bank_id`), - KEY `piggybank_events_transaction_journal_id_foreign` (`transaction_journal_id`), - CONSTRAINT `piggybank_events_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE SET NULL, - CONSTRAINT `piggybank_events_piggybank_id_foreign` FOREIGN KEY (`piggy_bank_id`) REFERENCES `piggy_banks` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table piggy_bank_repetitions -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `piggy_bank_repetitions`; - -CREATE TABLE `piggy_bank_repetitions` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `piggy_bank_id` int(10) unsigned NOT NULL, - `startdate` date DEFAULT NULL, - `targetdate` date DEFAULT NULL, - `currentamount` decimal(10,2) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `piggybank_repetitions_piggybank_id_startdate_targetdate_unique` (`piggy_bank_id`,`startdate`,`targetdate`), - CONSTRAINT `piggybank_repetitions_piggybank_id_foreign` FOREIGN KEY (`piggy_bank_id`) REFERENCES `piggy_banks` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table piggy_banks -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `piggy_banks`; - -CREATE TABLE `piggy_banks` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `account_id` int(10) unsigned NOT NULL, - `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `targetamount` decimal(10,2) NOT NULL, - `startdate` date DEFAULT NULL, - `targetdate` date DEFAULT NULL, - `repeats` tinyint(1) NOT NULL, - `rep_length` enum('day','week','quarter','month','year') COLLATE utf8_unicode_ci DEFAULT NULL, - `rep_every` smallint(5) unsigned NOT NULL, - `rep_times` smallint(5) unsigned DEFAULT NULL, - `reminder` enum('day','week','quarter','month','year') COLLATE utf8_unicode_ci DEFAULT NULL, - `reminder_skip` smallint(5) unsigned NOT NULL, - `remind_me` tinyint(1) NOT NULL, - `order` int(10) unsigned NOT NULL, - `deleted_at` timestamp NULL DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `piggybanks_account_id_name_unique` (`account_id`,`name`), - CONSTRAINT `piggybanks_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table preferences -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `preferences`; - -CREATE TABLE `preferences` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `user_id` int(10) unsigned NOT NULL, - `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `data` text COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `preferences_user_id_name_unique` (`user_id`,`name`), - CONSTRAINT `preferences_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table reminders -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `reminders`; - -CREATE TABLE `reminders` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `user_id` int(10) unsigned NOT NULL, - `startdate` date NOT NULL, - `enddate` date DEFAULT NULL, - `active` tinyint(1) NOT NULL, - `notnow` tinyint(1) NOT NULL DEFAULT '0', - `remindersable_id` int(10) unsigned DEFAULT NULL, - `remindersable_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `reminders_user_id_foreign` (`user_id`), - CONSTRAINT `reminders_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table sessions -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `sessions`; - -CREATE TABLE `sessions` ( - `id` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `payload` text COLLATE utf8_unicode_ci NOT NULL, - `last_activity` int(11) NOT NULL, - UNIQUE KEY `sessions_id_unique` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table transaction_currencies -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transaction_currencies`; - -CREATE TABLE `transaction_currencies` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `code` varchar(3) COLLATE utf8_unicode_ci NOT NULL, - `name` varchar(48) COLLATE utf8_unicode_ci DEFAULT NULL, - `symbol` varchar(8) COLLATE utf8_unicode_ci DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `transaction_currencies_code_unique` (`code`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -LOCK TABLES `transaction_currencies` WRITE; -/*!40000 ALTER TABLE `transaction_currencies` DISABLE KEYS */; - -INSERT INTO `transaction_currencies` (`id`, `created_at`, `updated_at`, `deleted_at`, `code`, `name`, `symbol`) -VALUES - (1,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'EUR','Euro','€'), - (2,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'USD','US Dollar','$'), - (3,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'HUF','Hungarian forint','Ft'); - -/*!40000 ALTER TABLE `transaction_currencies` ENABLE KEYS */; -UNLOCK TABLES; - - -# Dump of table transaction_group_transaction_journal -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transaction_group_transaction_journal`; - -CREATE TABLE `transaction_group_transaction_journal` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `transaction_group_id` int(10) unsigned NOT NULL, - `transaction_journal_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `tt_joined` (`transaction_group_id`,`transaction_journal_id`), - KEY `tr_trj_id` (`transaction_journal_id`), - CONSTRAINT `tr_trj_id` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE, - CONSTRAINT `tr_grp_id` FOREIGN KEY (`transaction_group_id`) REFERENCES `transaction_groups` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table transaction_groups -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transaction_groups`; - -CREATE TABLE `transaction_groups` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `user_id` int(10) unsigned NOT NULL, - `relation` enum('balance') COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - KEY `transaction_groups_user_id_foreign` (`user_id`), - CONSTRAINT `transaction_groups_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table transaction_journals -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transaction_journals`; - -CREATE TABLE `transaction_journals` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `user_id` int(10) unsigned NOT NULL, - `transaction_type_id` int(10) unsigned NOT NULL, - `bill_id` int(10) unsigned DEFAULT NULL, - `transaction_currency_id` int(10) unsigned NOT NULL, - `description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, - `completed` tinyint(1) NOT NULL, - `date` date NOT NULL, - PRIMARY KEY (`id`), - KEY `transaction_journals_user_id_foreign` (`user_id`), - KEY `transaction_journals_transaction_type_id_foreign` (`transaction_type_id`), - KEY `transaction_journals_transaction_currency_id_foreign` (`transaction_currency_id`), - KEY `bill_id_foreign` (`bill_id`), - CONSTRAINT `bill_id_foreign` FOREIGN KEY (`bill_id`) REFERENCES `bills` (`id`) ON DELETE SET NULL, - CONSTRAINT `transaction_journals_transaction_currency_id_foreign` FOREIGN KEY (`transaction_currency_id`) REFERENCES `transaction_currencies` (`id`) ON DELETE CASCADE, - CONSTRAINT `transaction_journals_transaction_type_id_foreign` FOREIGN KEY (`transaction_type_id`) REFERENCES `transaction_types` (`id`) ON DELETE CASCADE, - CONSTRAINT `transaction_journals_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table transaction_types -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transaction_types`; - -CREATE TABLE `transaction_types` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `type` varchar(50) COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `transaction_types_type_unique` (`type`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -LOCK TABLES `transaction_types` WRITE; -/*!40000 ALTER TABLE `transaction_types` DISABLE KEYS */; - -INSERT INTO `transaction_types` (`id`, `created_at`, `updated_at`, `deleted_at`, `type`) -VALUES - (1,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Withdrawal'), - (2,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Deposit'), - (3,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Transfer'), - (4,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Opening balance'); - -/*!40000 ALTER TABLE `transaction_types` ENABLE KEYS */; -UNLOCK TABLES; - - -# Dump of table transactions -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transactions`; - -CREATE TABLE `transactions` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `account_id` int(10) unsigned NOT NULL, - `transaction_journal_id` int(10) unsigned NOT NULL, - `description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, - `amount` decimal(10,2) NOT NULL, - PRIMARY KEY (`id`), - KEY `transactions_account_id_foreign` (`account_id`), - KEY `transactions_transaction_journal_id_foreign` (`transaction_journal_id`), - CONSTRAINT `transactions_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE, - CONSTRAINT `transactions_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table users -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `users`; - -CREATE TABLE `users` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `password` varchar(60) COLLATE utf8_unicode_ci NOT NULL, - `reset` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, - `remember_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `users_email_unique` (`email`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - - -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/_sql/firefly-iii-reference-3.2.5.sql b/_sql/firefly-iii-reference-3.2.5.sql deleted file mode 100644 index b2ad69f707..0000000000 --- a/_sql/firefly-iii-reference-3.2.5.sql +++ /dev/null @@ -1,607 +0,0 @@ -# ************************************************************ -# Sequel Pro SQL dump -# Version 4096 -# -# http://www.sequelpro.com/ -# http://code.google.com/p/sequel-pro/ -# -# Host: 127.0.0.1 (MySQL 5.6.19-0ubuntu0.14.04.1) -# Database: homestead -# Generation Time: 2015-01-31 05:33:30 +0000 -# ************************************************************ - - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - - -# Dump of table account_meta -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `account_meta`; - -CREATE TABLE `account_meta` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `account_id` int(10) unsigned NOT NULL, - `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `data` text COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `account_meta_account_id_name_unique` (`account_id`,`name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table account_types -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `account_types`; - -CREATE TABLE `account_types` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `type` varchar(30) COLLATE utf8_unicode_ci NOT NULL, - `editable` tinyint(1) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `account_types_type_unique` (`type`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -LOCK TABLES `account_types` WRITE; -/*!40000 ALTER TABLE `account_types` DISABLE KEYS */; - -INSERT INTO `account_types` (`id`, `created_at`, `updated_at`, `type`, `editable`) -VALUES - (1,'2015-01-31 05:33:21','2015-01-31 05:33:21','Default account',1), - (2,'2015-01-31 05:33:21','2015-01-31 05:33:21','Cash account',0), - (3,'2015-01-31 05:33:21','2015-01-31 05:33:21','Asset account',1), - (4,'2015-01-31 05:33:21','2015-01-31 05:33:21','Expense account',1), - (5,'2015-01-31 05:33:21','2015-01-31 05:33:21','Revenue account',1), - (6,'2015-01-31 05:33:21','2015-01-31 05:33:21','Initial balance account',0), - (7,'2015-01-31 05:33:21','2015-01-31 05:33:21','Beneficiary account',1), - (8,'2015-01-31 05:33:21','2015-01-31 05:33:21','Import account',0); - -/*!40000 ALTER TABLE `account_types` ENABLE KEYS */; -UNLOCK TABLES; - - -# Dump of table accounts -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `accounts`; - -CREATE TABLE `accounts` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `user_id` int(10) unsigned NOT NULL, - `account_type_id` int(10) unsigned NOT NULL, - `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `active` tinyint(1) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `accounts_user_id_account_type_id_name_unique` (`user_id`,`account_type_id`,`name`), - KEY `accounts_account_type_id_foreign` (`account_type_id`), - CONSTRAINT `accounts_account_type_id_foreign` FOREIGN KEY (`account_type_id`) REFERENCES `account_types` (`id`) ON DELETE CASCADE, - CONSTRAINT `accounts_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table bills -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `bills`; - -CREATE TABLE `bills` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `user_id` int(10) unsigned NOT NULL, - `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL, - `match` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `amount_min` decimal(10,2) NOT NULL, - `amount_max` decimal(10,2) NOT NULL, - `date` date NOT NULL, - `active` tinyint(1) NOT NULL, - `automatch` tinyint(1) NOT NULL, - `repeat_freq` enum('daily','weekly','monthly','quarterly','half-year','yearly') COLLATE utf8_unicode_ci NOT NULL, - `skip` smallint(5) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `uid_name_unique` (`user_id`,`name`), - CONSTRAINT `bills_uid_for` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table budget_limits -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `budget_limits`; - -CREATE TABLE `budget_limits` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `budget_id` int(10) unsigned DEFAULT NULL, - `startdate` date NOT NULL, - `amount` decimal(10,2) NOT NULL, - `repeats` tinyint(1) NOT NULL, - `repeat_freq` enum('daily','weekly','monthly','quarterly','half-year','yearly') COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `unique_bl_combi` (`budget_id`,`startdate`,`repeat_freq`), - CONSTRAINT `bid_foreign` FOREIGN KEY (`budget_id`) REFERENCES `budgets` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table budget_transaction_journal -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `budget_transaction_journal`; - -CREATE TABLE `budget_transaction_journal` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `budget_id` int(10) unsigned NOT NULL, - `transaction_journal_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `budid_tjid_unique` (`budget_id`,`transaction_journal_id`), - KEY `budget_transaction_journal_transaction_journal_id_foreign` (`transaction_journal_id`), - CONSTRAINT `budget_transaction_journal_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE, - CONSTRAINT `budget_transaction_journal_budget_id_foreign` FOREIGN KEY (`budget_id`) REFERENCES `budgets` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table budgets -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `budgets`; - -CREATE TABLE `budgets` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL, - `user_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `budgets_user_id_name_unique` (`user_id`,`name`), - CONSTRAINT `budgets_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table categories -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `categories`; - -CREATE TABLE `categories` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL, - `user_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `categories_user_id_name_unique` (`user_id`,`name`), - CONSTRAINT `categories_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table category_transaction_journal -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `category_transaction_journal`; - -CREATE TABLE `category_transaction_journal` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `category_id` int(10) unsigned NOT NULL, - `transaction_journal_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `catid_tjid_unique` (`category_id`,`transaction_journal_id`), - KEY `category_transaction_journal_transaction_journal_id_foreign` (`transaction_journal_id`), - CONSTRAINT `category_transaction_journal_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE, - CONSTRAINT `category_transaction_journal_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table components -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `components`; - -CREATE TABLE `components` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL, - `user_id` int(10) unsigned NOT NULL, - `class` varchar(20) COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `components_user_id_class_name_unique` (`user_id`,`class`,`name`), - CONSTRAINT `components_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table limit_repetitions -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `limit_repetitions`; - -CREATE TABLE `limit_repetitions` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `budget_limit_id` int(10) unsigned NOT NULL, - `startdate` date NOT NULL, - `enddate` date NOT NULL, - `amount` decimal(10,2) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `limit_repetitions_limit_id_startdate_enddate_unique` (`budget_limit_id`,`startdate`,`enddate`), - CONSTRAINT `limit_repetitions_limit_id_foreign` FOREIGN KEY (`budget_limit_id`) REFERENCES `budget_limits` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table migrations -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `migrations`; - -CREATE TABLE `migrations` ( - `migration` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `batch` int(11) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -LOCK TABLES `migrations` WRITE; -/*!40000 ALTER TABLE `migrations` DISABLE KEYS */; - -INSERT INTO `migrations` (`migration`, `batch`) -VALUES - ('2014_06_27_163032_create_users_table',1), - ('2014_06_27_163145_create_account_types_table',1), - ('2014_06_27_163259_create_accounts_table',1), - ('2014_06_27_163817_create_components_table',1), - ('2014_06_27_163818_create_piggybanks_table',1), - ('2014_06_27_164042_create_transaction_currencies_table',1), - ('2014_06_27_164512_create_transaction_types_table',1), - ('2014_06_27_164619_create_recurring_transactions_table',1), - ('2014_06_27_164620_create_transaction_journals_table',1), - ('2014_06_27_164836_create_transactions_table',1), - ('2014_06_27_165344_create_component_transaction_table',1), - ('2014_07_05_171326_create_component_transaction_journal_table',1), - ('2014_07_06_123842_create_preferences_table',1), - ('2014_07_09_204843_create_session_table',1), - ('2014_07_17_183717_create_limits_table',1), - ('2014_07_19_055011_create_limit_repeat_table',1), - ('2014_08_06_044416_create_component_recurring_transaction_table',1), - ('2014_08_12_173919_create_piggybank_repetitions_table',1), - ('2014_08_18_100330_create_piggybank_events_table',1), - ('2014_08_23_113221_create_reminders_table',1), - ('2014_11_10_172053_create_account_meta_table',1), - ('2014_11_29_135749_create_transaction_groups_table',1), - ('2014_11_29_140217_create_transaction_group_transaction_journal_table',1), - ('2014_12_13_190730_changes_for_v321',1), - ('2014_12_24_191544_changes_for_v322',1), - ('2015_01_18_082406_changes_for_v325',1); - -/*!40000 ALTER TABLE `migrations` ENABLE KEYS */; -UNLOCK TABLES; - - -# Dump of table piggy_bank_events -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `piggy_bank_events`; - -CREATE TABLE `piggy_bank_events` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `piggy_bank_id` int(10) unsigned NOT NULL, - `transaction_journal_id` int(10) unsigned DEFAULT NULL, - `date` date NOT NULL, - `amount` decimal(10,2) NOT NULL, - PRIMARY KEY (`id`), - KEY `piggybank_events_piggybank_id_foreign` (`piggy_bank_id`), - KEY `piggybank_events_transaction_journal_id_foreign` (`transaction_journal_id`), - CONSTRAINT `piggybank_events_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE SET NULL, - CONSTRAINT `piggybank_events_piggybank_id_foreign` FOREIGN KEY (`piggy_bank_id`) REFERENCES `piggy_banks` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table piggy_bank_repetitions -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `piggy_bank_repetitions`; - -CREATE TABLE `piggy_bank_repetitions` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `piggy_bank_id` int(10) unsigned NOT NULL, - `startdate` date DEFAULT NULL, - `targetdate` date DEFAULT NULL, - `currentamount` decimal(10,2) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `piggybank_repetitions_piggybank_id_startdate_targetdate_unique` (`piggy_bank_id`,`startdate`,`targetdate`), - CONSTRAINT `piggybank_repetitions_piggybank_id_foreign` FOREIGN KEY (`piggy_bank_id`) REFERENCES `piggy_banks` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table piggy_banks -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `piggy_banks`; - -CREATE TABLE `piggy_banks` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `account_id` int(10) unsigned NOT NULL, - `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `targetamount` decimal(10,2) NOT NULL, - `startdate` date DEFAULT NULL, - `targetdate` date DEFAULT NULL, - `repeats` tinyint(1) NOT NULL, - `rep_length` enum('day','week','quarter','month','year') COLLATE utf8_unicode_ci DEFAULT NULL, - `rep_every` smallint(5) unsigned NOT NULL, - `rep_times` smallint(5) unsigned DEFAULT NULL, - `reminder` enum('day','week','quarter','month','year') COLLATE utf8_unicode_ci DEFAULT NULL, - `reminder_skip` smallint(5) unsigned NOT NULL, - `remind_me` tinyint(1) NOT NULL, - `order` int(10) unsigned NOT NULL, - `deleted_at` timestamp NULL DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `piggybanks_account_id_name_unique` (`account_id`,`name`), - CONSTRAINT `piggybanks_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table preferences -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `preferences`; - -CREATE TABLE `preferences` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `user_id` int(10) unsigned NOT NULL, - `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `data` text COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `preferences_user_id_name_unique` (`user_id`,`name`), - CONSTRAINT `preferences_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table reminders -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `reminders`; - -CREATE TABLE `reminders` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `user_id` int(10) unsigned NOT NULL, - `startdate` date NOT NULL, - `enddate` date DEFAULT NULL, - `active` tinyint(1) NOT NULL, - `notnow` tinyint(1) NOT NULL DEFAULT '0', - `remindersable_id` int(10) unsigned DEFAULT NULL, - `remindersable_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `reminders_user_id_foreign` (`user_id`), - CONSTRAINT `reminders_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table sessions -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `sessions`; - -CREATE TABLE `sessions` ( - `id` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `payload` text COLLATE utf8_unicode_ci NOT NULL, - `last_activity` int(11) NOT NULL, - UNIQUE KEY `sessions_id_unique` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table transaction_currencies -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transaction_currencies`; - -CREATE TABLE `transaction_currencies` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `code` varchar(3) COLLATE utf8_unicode_ci NOT NULL, - `name` varchar(48) COLLATE utf8_unicode_ci DEFAULT NULL, - `symbol` varchar(8) COLLATE utf8_unicode_ci DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `transaction_currencies_code_unique` (`code`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -LOCK TABLES `transaction_currencies` WRITE; -/*!40000 ALTER TABLE `transaction_currencies` DISABLE KEYS */; - -INSERT INTO `transaction_currencies` (`id`, `created_at`, `updated_at`, `deleted_at`, `code`, `name`, `symbol`) -VALUES - (1,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'EUR','Euro','€'), - (2,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'USD','US Dollar','$'), - (3,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'HUF','Hungarian forint','Ft'); - -/*!40000 ALTER TABLE `transaction_currencies` ENABLE KEYS */; -UNLOCK TABLES; - - -# Dump of table transaction_group_transaction_journal -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transaction_group_transaction_journal`; - -CREATE TABLE `transaction_group_transaction_journal` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `transaction_group_id` int(10) unsigned NOT NULL, - `transaction_journal_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `tt_joined` (`transaction_group_id`,`transaction_journal_id`), - KEY `tr_trj_id` (`transaction_journal_id`), - CONSTRAINT `tr_trj_id` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE, - CONSTRAINT `tr_grp_id` FOREIGN KEY (`transaction_group_id`) REFERENCES `transaction_groups` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table transaction_groups -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transaction_groups`; - -CREATE TABLE `transaction_groups` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `user_id` int(10) unsigned NOT NULL, - `relation` enum('balance') COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - KEY `transaction_groups_user_id_foreign` (`user_id`), - CONSTRAINT `transaction_groups_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table transaction_journals -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transaction_journals`; - -CREATE TABLE `transaction_journals` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `user_id` int(10) unsigned NOT NULL, - `transaction_type_id` int(10) unsigned NOT NULL, - `bill_id` int(10) unsigned DEFAULT NULL, - `transaction_currency_id` int(10) unsigned NOT NULL, - `description` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL, - `completed` tinyint(1) NOT NULL, - `date` date NOT NULL, - `encrypted` tinyint(1) NOT NULL DEFAULT '0', - PRIMARY KEY (`id`), - KEY `transaction_journals_user_id_foreign` (`user_id`), - KEY `transaction_journals_transaction_type_id_foreign` (`transaction_type_id`), - KEY `transaction_journals_transaction_currency_id_foreign` (`transaction_currency_id`), - KEY `bill_id_foreign` (`bill_id`), - CONSTRAINT `bill_id_foreign` FOREIGN KEY (`bill_id`) REFERENCES `bills` (`id`) ON DELETE SET NULL, - CONSTRAINT `transaction_journals_transaction_currency_id_foreign` FOREIGN KEY (`transaction_currency_id`) REFERENCES `transaction_currencies` (`id`) ON DELETE CASCADE, - CONSTRAINT `transaction_journals_transaction_type_id_foreign` FOREIGN KEY (`transaction_type_id`) REFERENCES `transaction_types` (`id`) ON DELETE CASCADE, - CONSTRAINT `transaction_journals_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table transaction_types -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transaction_types`; - -CREATE TABLE `transaction_types` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `type` varchar(50) COLLATE utf8_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `transaction_types_type_unique` (`type`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -LOCK TABLES `transaction_types` WRITE; -/*!40000 ALTER TABLE `transaction_types` DISABLE KEYS */; - -INSERT INTO `transaction_types` (`id`, `created_at`, `updated_at`, `deleted_at`, `type`) -VALUES - (1,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'Withdrawal'), - (2,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'Deposit'), - (3,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'Transfer'), - (4,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'Opening balance'); - -/*!40000 ALTER TABLE `transaction_types` ENABLE KEYS */; -UNLOCK TABLES; - - -# Dump of table transactions -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `transactions`; - -CREATE TABLE `transactions` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `deleted_at` timestamp NULL DEFAULT NULL, - `account_id` int(10) unsigned NOT NULL, - `transaction_journal_id` int(10) unsigned NOT NULL, - `description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, - `amount` decimal(10,2) NOT NULL, - PRIMARY KEY (`id`), - KEY `transactions_account_id_foreign` (`account_id`), - KEY `transactions_transaction_journal_id_foreign` (`transaction_journal_id`), - CONSTRAINT `transactions_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE, - CONSTRAINT `transactions_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - -# Dump of table users -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `users`; - -CREATE TABLE `users` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', - `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `password` varchar(60) COLLATE utf8_unicode_ci NOT NULL, - `reset` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, - `remember_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `users_email_unique` (`email`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - - - - -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/app/Commands/Command.php b/app/Commands/Command.php new file mode 100644 index 0000000000..095393f3fa --- /dev/null +++ b/app/Commands/Command.php @@ -0,0 +1,11 @@ +comment(PHP_EOL . Inspiring::quote() . PHP_EOL); + } + +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php new file mode 100644 index 0000000000..f740d7abbc --- /dev/null +++ b/app/Console/Kernel.php @@ -0,0 +1,37 @@ +command('inspire') + ->hourly(); + } + +} diff --git a/app/Events/Event.php b/app/Events/Event.php new file mode 100644 index 0000000000..3d82e4d1dd --- /dev/null +++ b/app/Events/Event.php @@ -0,0 +1,13 @@ +isHttpException($e)) { + return $this->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. + * + * @param \Exception $e + * + * @return void + */ + public function report(Exception $e) + { + /** @noinspection PhpInconsistentReturnPointsInspection */ + return parent::report($e); + } + +} diff --git a/app/lib/FireflyIII/Exception/NotImplementedException.php b/app/Exceptions/NotImplementedException.php similarity index 61% rename from app/lib/FireflyIII/Exception/NotImplementedException.php rename to app/Exceptions/NotImplementedException.php index 718e394f3e..614a9b7f97 100644 --- a/app/lib/FireflyIII/Exception/NotImplementedException.php +++ b/app/Exceptions/NotImplementedException.php @@ -1,11 +1,11 @@ _queries->journalsByExpenseAccount($start, $end); + $array = $this->_helper->makeArray($result); + $limited = $this->_helper->limitArray($array, $limit); + + return $limited; + + } + + /** + * @return Carbon + */ + public function firstDate() + { + $journal = Auth::user()->transactionjournals()->orderBy('date', 'ASC')->first(); + if ($journal) { + return $journal->date; + } + + return Carbon::now(); + } + + /** + * This method gets some kind of list for a monthly overview. + * + * @param Carbon $date + * + * @return Collection + */ + public function getBudgetsForMonth(Carbon $date) + { + $start = clone $date; + $start->startOfMonth(); + $end = clone $date; + $end->endOfMonth(); + // all budgets + $set = \Auth::user()->budgets() + ->leftJoin( + 'budget_limits', function (JoinClause $join) use ($date) { + $join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d')); + } + ) + ->get(['budgets.*', 'budget_limits.amount as amount']); + + + $budgets = $this->_helper->makeArray($set); + $amountSet = $this->_queries->journalsByBudget($start, $end); + $amounts = $this->_helper->makeArray($amountSet); + $combined = $this->_helper->mergeArrays($budgets, $amounts); + $combined[0]['spent'] = isset($combined[0]['spent']) ? $combined[0]['spent'] : 0.0; + $combined[0]['amount'] = isset($combined[0]['amount']) ? $combined[0]['amount'] : 0.0; + $combined[0]['name'] = 'No budget'; + + // find transactions to shared expense accounts, which are without a budget by default: + $transfers = $this->_queries->sharedExpenses($start, $end); + foreach ($transfers as $transfer) { + $combined[0]['spent'] += floatval($transfer->amount) * -1; + } + + return $combined; + } + + /** + * @param Carbon $date + * + * @return array + */ + public function listOfMonths(Carbon $date) + { + $start = clone $date; + $end = Carbon::now(); + $months = []; + while ($start <= $end) { + $months[] = [ + 'formatted' => $start->format('F Y'), + 'month' => intval($start->format('m')), + 'year' => intval($start->format('Y')), + ]; + $start->addMonth(); + } + + return $months; + } + + /** + * @param Carbon $date + * + * @return array + */ + public function listOfYears(Carbon $date) + { + $start = clone $date; + $end = Carbon::now(); + $years = []; + while ($start <= $end) { + $years[] = $start->format('Y'); + $start->addYear(); + } + + return $years; + } + + /** + * @param Carbon $date + * + * @return array + */ + public function yearBalanceReport(Carbon $date) + { + $start = clone $date; + $end = clone $date; + $sharedAccounts = []; + $sharedCollection = \Auth::user()->accounts() + ->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id') + ->where('account_meta.name', '=', 'accountRole') + ->where('account_meta.data', '=', json_encode('sharedExpense')) + ->get(['accounts.id']); + + foreach ($sharedCollection as $account) { + $sharedAccounts[] = $account->id; + } + + $accounts = \Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])->filter( + function (Account $account) use ($sharedAccounts) { + if (!in_array($account->id, $sharedAccounts)) { + return $account; + } + + return null; + } + ); + $report = []; + $start->startOfYear()->subDay(); + $end->endOfYear(); + + foreach ($accounts as $account) { + $report[] = [ + 'start' => \Steam::balance($account, $start), + 'end' => \Steam::balance($account, $end), + 'account' => $account, + 'shared' => $account->accountRole == 'sharedExpense' + ]; + } + + return $report; + } +} \ No newline at end of file diff --git a/app/Helpers/Report/ReportHelperInterface.php b/app/Helpers/Report/ReportHelperInterface.php new file mode 100644 index 0000000000..99fbad8742 --- /dev/null +++ b/app/Helpers/Report/ReportHelperInterface.php @@ -0,0 +1,62 @@ +accounts() + ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') + ->leftJoin( + 'account_meta', function (JoinClause $join) { + $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', "accountRole"); + } + ) + ->whereIn('account_types.type', ['Default account', 'Cash account', 'Asset account']) + ->where('active', 1) + ->where( + function (Builder $query) { + $query->where('account_meta.data', '!=', '"sharedExpense"'); + $query->orWhereNull('account_meta.data'); + } + ) + ->get(['accounts.*']); + } + + /** + * This method will get a list of all expenses in a certain time period that have no budget + * and are balanced by a transfer to make up for it. + * + * @param Account $account + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function balancedTransactionsList(Account $account, Carbon $start, Carbon $end) + { + + $set = TransactionJournal:: + leftJoin('transaction_group_transaction_journal', 'transaction_group_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') + ->leftJoin( + 'transaction_group_transaction_journal as otherFromGroup', function (JoinClause $join) { + $join->on('otherFromGroup.transaction_group_id', '=', 'transaction_group_transaction_journal.transaction_group_id') + ->on('otherFromGroup.transaction_journal_id', '!=', 'transaction_journals.id'); + } + ) + ->leftJoin('transaction_journals as otherJournals', 'otherJournals.id', '=', 'otherFromGroup.transaction_journal_id') + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'otherJournals.transaction_type_id') + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0); + } + ) + ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'otherJournals.id') + ->before($end)->after($start) + ->where('transaction_types.type', 'Withdrawal') + ->where('transaction_journals.user_id', \Auth::user()->id) + ->whereNull('budget_transaction_journal.budget_id')->whereNull('transaction_journals.deleted_at') + ->whereNull('otherJournals.deleted_at') + ->where('transactions.account_id', $account->id) + ->whereNotNull('transaction_group_transaction_journal.transaction_group_id') + ->first( + [ + DB::Raw('SUM(`transactions`.`amount`) as `amount`') + ] + ); + $sum = 0; + if (!is_null($set)) { + $sum = floatval($set->amount); + } + + return $sum; + } + + /** + * Get a users accounts combined with various meta-data related to the start and end date. + * + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getAllAccounts(Carbon $start, Carbon $end) + { + $set = Auth::user()->accounts()->orderBy('accounts.name', 'ASC') + ->accountTypeIn(['Default account', 'Asset account', 'Cash account']) + ->leftJoin( + 'account_meta', function (JoinClause $join) { + $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); + } + ) + ->where( + function (Builder $query) { + $query->where('account_meta.data', '!=', '"sharedExpense"'); + $query->orWhereNull('account_meta.data'); + } + ) + ->get(['accounts.*']); + $set->each( + function (Account $account) use ($start, $end) { + /** @noinspection PhpParamsInspection */ + $account->startBalance = Steam::balance($account, $start); + $account->endBalance = Steam::balance($account, $end); + } + ); + + return $set; + } + + /** + * Grabs a summary of all expenses grouped by budget, related to the account. + * + * @param Account $account + * @param Carbon $start + * @param Carbon $end + * + * @return mixed + */ + public function getBudgetSummary(Account $account, Carbon $start, Carbon $end) + { + $set = TransactionJournal:: + leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') + ->leftJoin('budgets', 'budgets.id', '=', 'budget_transaction_journal.budget_id') + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); + } + ) + ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') + ->before($end) + ->after($start) + ->where('accounts.id', $account->id) + ->where('transaction_journals.user_id', Auth::user()->id) + ->where('transaction_types.type', 'Withdrawal') + ->groupBy('budgets.id') + ->orderBy('budgets.name', 'ASC') + ->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) as `amount`')]); + + return $set; + + + } + + /** + * This method returns all "income" journals in a certain period, which are both transfers from a shared account + * and "ordinary" deposits. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does + * not group and returns different fields. + * + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function incomeByPeriod(Carbon $start, Carbon $end) + { + return TransactionJournal:: + leftJoin( + 'transactions as t_from', function (JoinClause $join) { + $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); + } + ) + ->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id') + ->leftJoin( + 'account_meta as acm_from', function (JoinClause $join) { + $join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole'); + } + ) + ->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 as ac_to', 't_to.account_id', '=', 'ac_to.id') + ->leftJoin( + 'account_meta as acm_to', function (JoinClause $join) { + $join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole'); + } + ) + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->where( + function ($query) { + $query->where( + function ($q) { + $q->where('transaction_types.type', 'Deposit'); + $q->where('acm_to.data', '!=', '"sharedExpense"'); + } + ); + $query->orWhere( + function ($q) { + $q->where('transaction_types.type', 'Transfer'); + $q->where('acm_from.data', '=', '"sharedExpense"'); + } + ); + } + ) + ->before($end)->after($start) + ->where('transaction_journals.user_id', Auth::user()->id) + ->groupBy('t_from.account_id')->orderBy('transaction_journals.date') + ->get( + ['transaction_journals.id', + 'transaction_journals.description', + 'transaction_journals.encrypted', + 'transaction_types.type', + 't_to.amount', 'transaction_journals.date', 't_from.account_id as account_id', + 'ac_from.name as name'] + ); + } + + /** + * Gets a list of expenses grouped by the budget they were filed under. + * + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function journalsByBudget(Carbon $start, Carbon $end) + { + return Auth::user()->transactionjournals() + ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') + ->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id') + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0); + } + ) + ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') + ->leftJoin( + 'account_meta', function (JoinClause $join) { + $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); + } + ) + ->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->where('account_meta.data', '!=', '"sharedExpense"') + ->where('transaction_types.type', 'Withdrawal') + ->groupBy('budgets.id') + ->orderBy('budgets.name', 'ASC') + ->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) AS `spent`')]); + } + + /** + * Gets a list of categories and the expenses therein, grouped by the relevant category. + * This result excludes transfers to shared accounts which are expenses, technically. + * + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function journalsByCategory(Carbon $start, Carbon $end) + { + return Auth::user()->transactionjournals() + ->leftJoin( + 'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id' + ) + ->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id') + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0); + } + ) + ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') + ->leftJoin( + 'account_meta', function (JoinClause $join) { + $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); + } + ) + ->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->where('account_meta.data', '!=', '"sharedExpense"') + ->where('transaction_types.type', 'Withdrawal') + ->groupBy('categories.id') + ->orderBy('amount') + ->get(['categories.id', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `amount`')]); + + } + + /** + * Gets a list of expense accounts and the expenses therein, grouped by that expense account. + * This result excludes transfers to shared accounts which are expenses, technically. + * + * So now it will include them! + * + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function journalsByExpenseAccount(Carbon $start, Carbon $end) + { + return TransactionJournal:: + leftJoin( + 'transactions as t_from', function (JoinClause $join) { + $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); + } + ) + ->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id') + ->leftJoin( + 'account_meta as acm_from', function (JoinClause $join) { + $join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole'); + } + ) + ->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 as ac_to', 't_to.account_id', '=', 'ac_to.id') + ->leftJoin( + 'account_meta as acm_to', function (JoinClause $join) { + $join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole'); + } + ) + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->where( + function ($query) { + $query->where( + function ($q) { + $q->where('transaction_types.type', 'Withdrawal'); + $q->where('acm_from.data', '!=', '"sharedExpense"'); + } + ); + $query->orWhere( + function ($q) { + $q->where('transaction_types.type', 'Transfer'); + $q->where('acm_to.data', '=', '"sharedExpense"'); + } + ); + } + ) + ->before($end) + ->after($start) + ->where('transaction_journals.user_id', Auth::user()->id) + ->groupBy('t_to.account_id') + ->orderBy('amount', 'DESC') + ->get(['t_to.account_id as id', 'ac_to.name as name', DB::Raw('SUM(t_to.amount) as `amount`')]); + } + + /** + * This method returns all deposits into asset accounts, grouped by the revenue account, + * + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function journalsByRevenueAccount(Carbon $start, Carbon $end) + { + return TransactionJournal:: + leftJoin( + 'transactions as t_from', function (JoinClause $join) { + $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); + } + ) + ->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id') + ->leftJoin( + 'account_meta as acm_from', function (JoinClause $join) { + $join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole'); + } + ) + ->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 as ac_to', 't_to.account_id', '=', 'ac_to.id') + ->leftJoin( + 'account_meta as acm_to', function (JoinClause $join) { + $join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole'); + } + ) + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->where( + function ($query) { + $query->where( + function ($q) { + $q->where('transaction_types.type', 'Deposit'); + $q->where('acm_to.data', '!=', '"sharedExpense"'); + } + ); + $query->orWhere( + function ($q) { + $q->where('transaction_types.type', 'Transfer'); + $q->where('acm_from.data', '=', '"sharedExpense"'); + } + ); + } + ) + ->before($end)->after($start) + ->where('transaction_journals.user_id', Auth::user()->id) + ->groupBy('t_from.account_id')->orderBy('amount') + ->get(['t_from.account_id as account_id', 'ac_from.name as name', DB::Raw('SUM(t_from.amount) as `amount`')]); + } + + /** + * With an equally misleading name, this query returns are transfers to shared accounts. These are considered + * expenses. + * + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function sharedExpenses(Carbon $start, Carbon $end) + { + return TransactionJournal:: + leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where( + 'transactions.amount', '>', 0 + ); + } + ) + ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') + ->leftJoin( + 'account_meta', function (JoinClause $join) { + $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); + } + ) + ->where('account_meta.data', '"sharedExpense"') + ->after($start) + ->before($end) + ->where('transaction_types.type', 'Transfer') + ->where('transaction_journals.user_id', Auth::user()->id) + ->get( + ['transaction_journals.id', 'transaction_journals.description', 'transactions.account_id', 'accounts.name', + 'transactions.amount'] + ); + + } + + /** + * With a slightly misleading name, this query returns all transfers to shared accounts + * which are technically expenses, since it won't be just your money that gets spend. + * + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function sharedExpensesByCategory(Carbon $start, Carbon $end) + { + return TransactionJournal:: + leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where( + 'transactions.amount', '>', 0 + ); + } + ) + ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') + ->leftJoin( + 'account_meta', function (JoinClause $join) { + $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); + } + ) + ->leftJoin( + 'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id' + ) + ->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id') + ->where('account_meta.data', '"sharedExpense"') + ->after($start) + ->before($end) + ->where('transaction_types.type', 'Transfer') + ->where('transaction_journals.user_id', Auth::user()->id) + ->groupBy('categories.name') + ->get( + [ + 'categories.id', + 'categories.name as name', + DB::Raw('SUM(`transactions`.`amount`) * -1 AS `amount`') + ] + ); + } + +} \ No newline at end of file diff --git a/app/lib/FireflyIII/Report/ReportQueryInterface.php b/app/Helpers/Report/ReportQueryInterface.php similarity index 74% rename from app/lib/FireflyIII/Report/ReportQueryInterface.php rename to app/Helpers/Report/ReportQueryInterface.php index 046835b843..1bce968341 100644 --- a/app/lib/FireflyIII/Report/ReportQueryInterface.php +++ b/app/Helpers/Report/ReportQueryInterface.php @@ -1,15 +1,15 @@ accountType->type)) . ' "' . e($account->name) . '"'; + + return view('accounts.delete', compact('account', 'subTitle')); + } + + /** + * @param Account $account + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(Account $account, AccountRepositoryInterface $repository) + { + + $type = $account->accountType->type; + $typeName = Config::get('firefly.shortNamesByFullName.' . $type); + $name = $account->name; + + $repository->destroy($account); + + Session::flash('success', 'The ' . e($typeName) . ' account "' . e($name) . '" was deleted.'); + + return Redirect::route('accounts.index', $typeName); + } + + public function edit(Account $account, AccountRepositoryInterface $repository) + { + $what = Config::get('firefly.shortNamesByFullName')[$account->accountType->type]; + $subTitle = 'Edit ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"'; + $subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what); + $openingBalance = $repository->openingBalanceTransaction($account); + + // pre fill some useful values. + + // the opening balance is tricky: + $openingBalanceAmount = null; + if ($openingBalance) { + $transaction = $openingBalance->transactions()->where('account_id', $account->id)->first(); + $openingBalanceAmount = $transaction->amount; + } + + $preFilled = [ + 'accountRole' => $account->getMeta('accountRole'), + 'openingBalanceDate' => $openingBalance ? $openingBalance->date->format('Y-m-d') : null, + 'openingBalance' => $openingBalanceAmount + ]; + Session::flash('preFilled', $preFilled); + + return view('accounts.edit', compact('account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what')); + } + + /** + * @param string $what + * + * @return View + */ + public function index($what = 'default') + { + $subTitle = Config::get('firefly.subTitlesByIdentifier.' . $what); + $subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what); + $types = Config::get('firefly.accountTypesByIdentifier.' . $what); + $accounts = Auth::user()->accounts()->accountTypeIn($types)->get(['accounts.*']); + + return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts')); + } + + /** + * @param Account $account + * @param string $range + * @param AccountRepositoryInterface $repository + * + * @return \Illuminate\View\View + */ + public function show(Account $account, $range = 'session') + { + /** @var \FireflyIII\Repositories\Account\AccountRepositoryInterface $repository */ + $repository = App::make('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page')); + $subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $account->accountType->type); + $what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type); + $journals = $repository->getJournals($account, $page, $range); + $subTitle = 'Details for ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"'; + + return view('accounts.show', compact('account', 'what', 'range', 'subTitleIcon', 'journals', 'subTitle')); + } + + /** + * @param AccountFormRequest $request + * @param AccountRepositoryInterface $repository + * + * @return \Illuminate\Http\RedirectResponse + */ + public function store(AccountFormRequest $request, AccountRepositoryInterface $repository) + { + $accountData = [ + 'name' => $request->input('name'), + 'accountType' => $request->input('what'), + 'active' => true, + 'user' => Auth::user()->id, + 'accountRole' => $request->input('accountRole'), + 'openingBalance' => floatval($request->input('openingBalance')), + 'openingBalanceDate' => new Carbon($request->input('openingBalanceDate')), + 'openingBalanceCurrency' => intval($request->input('balance_currency_id')), + + ]; + $account = $repository->store($accountData); + + Session::flash('success', 'New account "' . $account->name . '" stored!'); + + return Redirect::route('accounts.index', $request->input('what')); + + } + + /** + * @param Account $account + * @param AccountFormRequest $request + * @param AccountRepositoryInterface $repository + * + * @return \Illuminate\Http\RedirectResponse + */ + public function update(Account $account, AccountFormRequest $request, AccountRepositoryInterface $repository) + { + $what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type); + $accountData = [ + 'name' => $request->input('name'), + 'active' => $request->input('active'), + 'user' => Auth::user()->id, + 'accountRole' => $request->input('accountRole'), + 'openingBalance' => floatval($request->input('openingBalance')), + 'openingBalanceDate' => new Carbon($request->input('openingBalanceDate')), + 'openingBalanceCurrency' => intval($request->input('balance_currency_id')), + ]; + + $repository->update($account, $accountData); + + Session::flash('success', 'Account "' . $account->name . '" updated.'); + + return Redirect::route('accounts.index', $what); + + } + +} diff --git a/app/Http/Controllers/Auth/AuthController.php b/app/Http/Controllers/Auth/AuthController.php new file mode 100644 index 0000000000..d79cc2c56e --- /dev/null +++ b/app/Http/Controllers/Auth/AuthController.php @@ -0,0 +1,46 @@ +auth = $auth; + $this->registrar = $registrar; + + $this->middleware('guest', ['except' => 'getLogout']); + } + +} diff --git a/app/Http/Controllers/Auth/PasswordController.php b/app/Http/Controllers/Auth/PasswordController.php new file mode 100644 index 0000000000..2d9ebced35 --- /dev/null +++ b/app/Http/Controllers/Auth/PasswordController.php @@ -0,0 +1,48 @@ +auth = $auth; + $this->passwords = $passwords; + + + $this->middleware('guest'); + } + +} diff --git a/app/Http/Controllers/BillController.php b/app/Http/Controllers/BillController.php new file mode 100644 index 0000000000..139fb63887 --- /dev/null +++ b/app/Http/Controllers/BillController.php @@ -0,0 +1,240 @@ +with('periods', $periods)->with('subTitle', 'Create new'); + } + + /** + * @param Bill $bill + * + * @return $this + */ + public function delete(Bill $bill) + { + return view('bills.delete')->with('bill', $bill)->with('subTitle', 'Delete "' . e($bill->name) . '"'); + } + + /** + * @param Bill $bill + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(Bill $bill) + { + $bill->delete(); + Session::flash('success', 'The bill was deleted.'); + + return Redirect::route('bills.index'); + + } + + /** + * @param Bill $bill + * + * @return $this + */ + public function edit(Bill $bill) + { + $periods = \Config::get('firefly.periods_to_text'); + + return view('bills.edit')->with('periods', $periods)->with('bill', $bill)->with('subTitle', 'Edit "' . e($bill->name) . '"'); + } + + /** + * @param BillRepositoryInterface $repository + * + * @return \Illuminate\View\View + */ + public function index(BillRepositoryInterface $repository) + { + $bills = Auth::user()->bills()->get(); + $bills->each( + function (Bill $bill) use ($repository) { + $bill->nextExpectedMatch = $repository->nextExpectedMatch($bill); + $last = $bill->transactionjournals()->orderBy('date', 'DESC')->first(); + $bill->lastFoundMatch = null; + if ($last) { + $bill->lastFoundMatch = $last->date; + } + } + ); + + return view('bills.index', compact('bills')); + } + + /** + * @param Bill $bill + * + * @return mixed + */ + public function rescan(Bill $bill, BillRepositoryInterface $repository) + { + if (intval($bill->active) == 0) { + Session::flash('warning', 'Inactive bills cannot be scanned.'); + + return Redirect::intended('/'); + } + + $set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)->get(['transaction_journal_id']); + $ids = []; + + /** @var Transaction $entry */ + foreach ($set as $entry) { + $ids[] = intval($entry->transaction_journal_id); + } + if (count($ids) > 0) { + $journals = Auth::user()->transactionjournals()->whereIn('id',$ids)->get(); + /** @var TransactionJournal $journal */ + foreach ($journals as $journal) { + $repository->scan($bill, $journal); + } + } + + Session::flash('success', 'Rescanned everything.'); + + return Redirect::to(URL::previous()); + } + + /** + * @param Bill $bill + * + * @return mixed + */ + public function show(Bill $bill, BillRepositoryInterface $repository) + { + $journals = $bill->transactionjournals()->withRelevantData()->orderBy('date', 'DESC')->get(); + $bill->nextExpectedMatch = $repository->nextExpectedMatch($bill); + $hideBill = true; + + + return view('bills.show', compact('journals', 'hideBill', 'bill'))->with('subTitle', e($bill->name)); + } + + /** + * @return $this + */ + public function store(BillFormRequest $request, BillRepositoryInterface $repository) + { + + var_dump($request->all()); + + $billData = [ + 'name' => $request->get('name'), + 'match' => $request->get('match'), + 'amount_min' => floatval($request->get('amount_min')), + 'amount_currency_id' => floatval($request->get('amount_currency_id')), + 'amount_max' => floatval($request->get('amount_max')), + 'date' => new Carbon($request->get('date')), + 'user' => Auth::user()->id, + 'repeat_freq' => $request->get('repeat_freq'), + 'skip' => intval($request->get('skip')), + 'automatch' => intval($request->get('automatch')) === 1, + 'active' => intval($request->get('active')) === 1, + ]; + + $bill = $repository->store($billData); + Session::flash('success', 'Bill "' . e($bill->name) . '" stored.'); + + return Redirect::route('bills.index'); + + } + + /** + * @param Bill $bill + * + * @return $this + */ + public function update(Bill $bill, BillFormRequest $request, BillRepositoryInterface $repository) + { + $billData = [ + 'name' => $request->get('name'), + 'match' => $request->get('match'), + 'amount_min' => floatval($request->get('amount_min')), + 'amount_currency_id' => floatval($request->get('amount_currency_id')), + 'amount_max' => floatval($request->get('amount_max')), + 'date' => new Carbon($request->get('date')), + 'user' => Auth::user()->id, + 'repeat_freq' => $request->get('repeat_freq'), + 'skip' => intval($request->get('skip')), + 'automatch' => intval($request->get('automatch')) === 1, + 'active' => intval($request->get('active')) === 1, + ]; + + $bill = $repository->update($bill, $billData); + + Session::flash('success', 'Bill "' . e($bill->name) . '" updated.'); + + return Redirect::route('bills.index'); + + + // $data = Input::except('_token'); + // $data['active'] = intval(Input::get('active')); + // $data['automatch'] = intval(Input::get('automatch')); + // $data['user_id'] = Auth::user()->id; + // + // // always validate: + // $messages = $this->_repository->validate($data); + // + // // flash messages: + // Session::flash('warnings', $messages['warnings']); + // Session::flash('successes', $messages['successes']); + // Session::flash('errors', $messages['errors']); + // if ($messages['errors']->count() > 0) { + // Session::flash('error', 'Could not update bill: ' . $messages['errors']->first()); + // + // return Redirect::route('bills.edit', $bill->id)->withInput(); + // } + // + // // return to update screen: + // if ($data['post_submit_action'] == 'validate_only') { + // return Redirect::route('bills.edit', $bill->id)->withInput(); + // } + // + // // update + // $this->_repository->update($bill, $data); + // Session::flash('success', 'Bill "' . e($data['name']) . '" updated.'); + // + // // go back to list + // if ($data['post_submit_action'] == 'update') { + // return Redirect::route('bills.index'); + // } + // + // // go back to update screen. + // return Redirect::route('bills.edit', $bill->id)->withInput(['post_submit_action' => 'return_to_edit']); + + } + +} diff --git a/app/Http/Controllers/BudgetController.php b/app/Http/Controllers/BudgetController.php new file mode 100644 index 0000000000..93afee239e --- /dev/null +++ b/app/Http/Controllers/BudgetController.php @@ -0,0 +1,222 @@ +startOfMonth()); + $limitRepetition = $repository->updateLimitAmount($budget, $date, $amount); + + return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0]); + + } + + /** + * @return $this + */ + public function create() + { + return view('budgets.create')->with('subTitle', 'Create a new budget'); + } + + /** + * @param Budget $budget + * + * @return \Illuminate\View\View + */ + public function delete(Budget $budget) + { + $subTitle = 'Delete budget' . e($budget->name) . '"'; + + return view('budgets.delete', compact('budget', 'subTitle')); + } + + /** + * @param Budget $budget + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(Budget $budget, BudgetRepositoryInterface $repository) + { + + $name = $budget->name; + $repository->destroy($budget); + + Session::flash('success', 'The budget "' . e($name) . '" was deleted.'); + + return Redirect::route('budgets.index'); + } + + /** + * @param Budget $budget + * + * @return $this + */ + public function edit(Budget $budget) + { + $subTitle = 'Edit budget "' . e($budget->name) . '"'; + + return view('budgets.edit', compact('budget', 'subTitle')); + + } + + /** + * @return mixed + */ + public function index(BudgetRepositoryInterface $repository) + { + $budgets = Auth::user()->budgets()->get(); + + // loop the budgets: + $budgets->each( + function (Budget $budget) use ($repository) { + $date = Session::get('start', Carbon::now()->startOfMonth()); + $budget->spent = $repository->spentInMonth($budget, $date); + $budget->currentRep = $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']); + } + ); + + $date = Session::get('start', Carbon::now()->startOfMonth())->format('FY'); + $spent = $budgets->sum('spent'); + $amount = Preferences::get('budgetIncomeTotal' . $date, 1000)->data; + $overspent = $spent > $amount; + $spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100); + $budgetMax = Preferences::get('budgetMaximum', 1000); + $budgetMaximum = $budgetMax->data; + + return view('budgets.index', compact('budgetMaximum', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount')); + } + + /** + * @return \Illuminate\View\View + */ + public function noBudget() + { + $start = \Session::get('start', Carbon::now()->startOfMonth()); + $end = \Session::get('end', Carbon::now()->startOfMonth()); + $list = Auth::user() + ->transactionjournals() + ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') + ->whereNull('budget_transaction_journal.id') + ->before($end) + ->after($start) + ->orderBy('transaction_journals.date') + ->get(['transaction_journals.*']); + $subTitle = 'Transactions without a budget in ' . $start->format('F Y'); + + return view('budgets.noBudget', compact('list', 'subTitle')); + } + + /** + * @return mixed + */ + public function postUpdateIncome() + { + + $date = Session::get('start', Carbon::now()->startOfMonth())->format('FY'); + Preferences::set('budgetIncomeTotal' . $date, intval(Input::get('amount'))); + + return Redirect::route('budgets.index'); + } + + public function store(BudgetFormRequest $request, BudgetRepositoryInterface $repository) + { + $budgetData = [ + 'name' => $request->input('name'), + 'user' => Auth::user()->id, + ]; + $budget = $repository->store($budgetData); + + Session::flash('success', 'New budget "' . $budget->name . '" stored!'); + + return Redirect::route('budgets.index'); + + } + + /** + * + * @param Budget $budget + * @param LimitRepetition $repetition + * + * @return \Illuminate\View\View + */ + public function show(Budget $budget, LimitRepetition $repetition = null, BudgetRepositoryInterface $repository) + { + if (!is_null($repetition->id) && $repetition->budgetLimit->budget->id != $budget->id) { + return view('error')->with('message', 'Invalid selection.'); + } + + $hideBudget = true; // used in transaction list. + $journals = $repository->getJournals($budget, $repetition); + $limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $budget->budgetLimits()->orderBy('startdate', 'DESC')->get(); + $subTitle = !is_null($repetition->id) ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name); + + return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle', 'hideBudget')); + } + + /** + * @param Budget $budget + * @param BudgetFormRequest $request + * @param BudgetRepositoryInterface $repository + * + * @return \Illuminate\Http\RedirectResponse + */ + public function update(Budget $budget, BudgetFormRequest $request, BudgetRepositoryInterface $repository) + { + $budgetData = [ + 'name' => $request->input('name'), + ]; + + $repository->update($budget, $budgetData); + + Session::flash('success', 'Budget "' . $budget->name . '" updated.'); + + return Redirect::route('budgets.index'); + + } + + /** + * @return $this + */ + public function updateIncome() + { + $date = Session::get('start', Carbon::now()->startOfMonth())->format('FY'); + $budgetAmount = Preferences::get('budgetIncomeTotal' . $date, 1000); + + return view('budgets.income')->with('amount', $budgetAmount); + } + +} diff --git a/app/Http/Controllers/CategoryController.php b/app/Http/Controllers/CategoryController.php new file mode 100644 index 0000000000..8bc05e7bc8 --- /dev/null +++ b/app/Http/Controllers/CategoryController.php @@ -0,0 +1,172 @@ +with('subTitle', 'Create a new category'); + } + + /** + * @param Category $category + * + * @return $this + */ + public function show(Category $category, CategoryRepositoryInterface $repository) + { + $hideCategory = true; // used in list. + $page = intval(Input::get('page')); + $offset = $page > 0 ? $page * 50 : 0; + $set = $category->transactionJournals()->withRelevantData()->take(50)->offset($offset)->orderBy('date', 'DESC')->get(['transaction_journals.*']); + $count = $category->transactionJournals()->count(); + + $journals = new LengthAwarePaginator($set, $count, 50, $page); + + return view('categories.show', compact('category', 'journals', 'hideCategory')); + } + + /** + * @return \Illuminate\View\View + */ + public function noCategory() + { + $start = Session::get('start', Carbon::now()->startOfMonth()); + $end = Session::get('end', Carbon::now()->startOfMonth()); + $list = 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') + ->get(['transaction_journals.*']); + $subTitle = 'Transactions without a category in ' . $start->format('F Y'); + + return view('categories.noCategory', compact('list', 'subTitle')); + } + + /** + * @param Category $category + * + * @return \Illuminate\View\View + */ + public function delete(Category $category) + { + $subTitle = 'Delete category' . e($category->name) . '"'; + + return view('categories.delete', compact('category', 'subTitle')); + } + + /** + * @param Category $category + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(Category $category, CategoryRepositoryInterface $repository) + { + + $name = $category->name; + $repository->destroy($category); + + Session::flash('success', 'The category "' . e($name) . '" was deleted.'); + + return Redirect::route('categories.index'); + } + + /** + * @param Category $category + * + * @return $this + */ + public function edit(Category $category) + { + $subTitle = 'Edit category "' . e($category->name) . '"'; + + return view('categories.edit', compact('category', 'subTitle')); + + } + + /** + * @return $this + */ + public function index() + { + $categories = Auth::user()->categories()->get(); + + return view('categories.index', compact('categories')); + } + + /** + * @param CategoryFormRequest $request + * @param CategoryRepositoryInterface $repository + * + * @return mixed + */ + public function store(CategoryFormRequest $request, CategoryRepositoryInterface $repository) + { + $categoryData = [ + 'name' => $request->input('name'), + 'user' => Auth::user()->id, + ]; + $category = $repository->store($categoryData); + + Session::flash('success', 'New category "' . $category->name . '" stored!'); + + return Redirect::route('categories.index'); + + } + + + /** + * @param Category $category + * @param CategoryFormRequest $request + * @param CategoryRepositoryInterface $repository + * + * @return \Illuminate\Http\RedirectResponse + */ + public function update(Category $category, CategoryFormRequest $request, CategoryRepositoryInterface $repository) + { + $categoryData = [ + 'name' => $request->input('name'), + ]; + + $repository->update($category, $categoryData); + + Session::flash('success', 'Category "' . $category->name . '" updated.'); + + return Redirect::route('categories.index'); + + } + +} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php new file mode 100644 index 0000000000..fb7b363590 --- /dev/null +++ b/app/Http/Controllers/Controller.php @@ -0,0 +1,17 @@ +data = $currency->code; + $currencyPreference->save(); + + Session::flash('success', $currency->name . ' is now the default currency.'); + Cache::forget('FFCURRENCYSYMBOL'); + Cache::forget('FFCURRENCYCODE'); + + return Redirect::route('currency.index'); + + } + + /** + * @param TransactionCurrency $currency + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View + */ + public function delete(TransactionCurrency $currency) + { + if ($currency->transactionJournals()->count() > 0) { + Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.'); + + return Redirect::route('currency.index'); + } + + + return view('currency.delete', compact('currency')); + } + + /** + * @param TransactionCurrency $currency + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(TransactionCurrency $currency) + { + if ($currency->transactionJournals()->count() > 0) { + Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.'); + + return Redirect::route('currency.index'); + } + + Session::flash('success', 'Currency "' . e($currency->name) . '" deleted'); + + $currency->delete(); + + return Redirect::route('currency.index'); + } + + /** + * @param TransactionCurrency $currency + * + * @return \Illuminate\View\View + */ + public function edit(TransactionCurrency $currency) + { + $subTitleIcon = 'fa-pencil'; + $subTitle = 'Edit currency "' . e($currency->name) . '"'; + $currency->symbol = htmlentities($currency->symbol); + + return view('currency.edit', compact('currency', 'subTitle', 'subTitleIcon')); + + } + + /** + * @return \Illuminate\View\View + */ + public function index() + { + $currencies = TransactionCurrency::get(); + $currencyPreference = Preferences::get('currencyPreference', 'EUR'); + $defaultCurrency = TransactionCurrency::whereCode($currencyPreference->data)->first(); + + + return view('currency.index', compact('currencies', 'defaultCurrency')); + } + + /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * + * @return $this|\Illuminate\Http\RedirectResponse + */ + public function store(CurrencyFormRequest $request) + { + + + // no repository, because the currency controller is relatively simple. + $currency = TransactionCurrency::create( + [ + 'name' => $request->get('name'), + 'code' => $request->get('code'), + 'symbol' => $request->get('symbol'), + ] + ); + + Session::flash('success', 'Currency "' . $currency->name . '" created'); + + return Redirect::route('currency.index'); + + + } + + /** + * @param TransactionCurrency $currency + * + * @return $this|\Illuminate\Http\RedirectResponse + */ + public function update(TransactionCurrency $currency, CurrencyFormRequest $request) + { + + $currency->code = $request->get('code'); + $currency->symbol = $request->get('symbol'); + $currency->name = $request->get('name'); + $currency->save(); + + Session::flash('success', 'Currency "' . e($currency->namename) . '" updated.'); + + return Redirect::route('currency.index'); + + } + +} diff --git a/app/Http/Controllers/GoogleChartController.php b/app/Http/Controllers/GoogleChartController.php new file mode 100644 index 0000000000..55e90b4979 --- /dev/null +++ b/app/Http/Controllers/GoogleChartController.php @@ -0,0 +1,635 @@ +addColumn('Day of month', 'date'); + $chart->addColumn('Balance for ' . $account->name, 'number'); + $chart->addCertainty(1); + + $start = Session::get('start', Carbon::now()->startOfMonth()); + $end = Session::get('end', Carbon::now()->endOfMonth()); + $count = $account->transactions()->count(); + + if ($view == 'all' && $count > 0) { + $first = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy( + 'date', 'ASC' + )->first(['transaction_journals.date']); + $last = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy( + 'date', 'DESC' + )->first(['transaction_journals.date']); + $start = new Carbon($first->date); + $end = new Carbon($last->date); + } + + $current = clone $start; + + while ($end >= $current) { + $chart->addRow(clone $current, Steam::balance($account, $current), false); + $current->addDay(); + } + + + $chart->generate(); + + return Response::json($chart->getData()); + } + + /** + * @param GChart $chart + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function allAccountsBalanceChart(GChart $chart) + { + $chart->addColumn('Day of the month', 'date'); + + $frontPage = Preferences::get('frontPageAccounts', []); + $start = Session::get('start', Carbon::now()->startOfMonth()); + $end = Session::get('end', Carbon::now()->endOfMonth()); + + if ($frontPage->data == []) { + $accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']); + } else { + $accounts = Auth::user()->accounts()->whereIn('id', $frontPage->data)->get(['accounts.*']); + } + $index = 1; + /** @var Account $account */ + foreach ($accounts as $account) { + $chart->addColumn('Balance for ' . $account->name, 'number'); + $chart->addCertainty($index); + $index++; + } + $current = clone $start; + $current->subDay(); + $today = Carbon::now(); + while ($end >= $current) { + $row = [clone $current]; + $certain = $current < $today; + foreach ($accounts as $account) { + $row[] = Steam::balance($account, $current); + $row[] = $certain; + } + $chart->addRowArray($row); + $current->addDay(); + } + $chart->generate(); + + return Response::json($chart->getData()); + + } + + /** + * @param int $year + * + * @return $this|\Illuminate\Http\JsonResponse + */ + public function allBudgetsAndSpending($year, GChart $chart, BudgetRepositoryInterface $repository) + { + try { + new Carbon('01-01-' . $year); + } catch (Exception $e) { + return view('error')->with('message', 'Invalid year.'); + } + $budgets = Auth::user()->budgets()->get(); + $budgets->sortBy('name'); + $chart->addColumn('Month', 'date'); + foreach ($budgets as $budget) { + $chart->addColumn($budget->name, 'number'); + } + $start = Carbon::createFromDate(intval($year), 1, 1); + $end = clone $start; + $end->endOfYear(); + + + while ($start <= $end) { + $row = [clone $start]; + foreach ($budgets as $budget) { + $spent = $repository->spentInMonth($budget, $start); + $row[] = $spent; + } + $chart->addRowArray($row); + $start->addMonth(); + } + + + $chart->generate(); + + return Response::json($chart->getData()); + + } + + /** + * @param GChart $chart + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function allBudgetsHomeChart(GChart $chart) + { + $chart->addColumn('Budget', 'string'); + $chart->addColumn('Budgeted', 'number'); + $chart->addColumn('Spent', 'number'); + + $budgets = Auth::user()->budgets()->orderBy('name', 'DESC')->get(); + $start = Session::get('start', Carbon::now()->startOfMonth()); + $end = Session::get('end', Carbon::now()->endOfMonth()); + + /** @var Budget $budget */ + foreach ($budgets as $budget) { + + /** @var \LimitRepetition $repetition */ + $repetition = LimitRepetition:: + leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') + ->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00')) + ->where('budget_limits.budget_id', $budget->id) + ->first(['limit_repetitions.*']); + if (is_null($repetition)) { // use the session start and end for our search query + $searchStart = $start; + $searchEnd = $end; + $limit = 0; // the limit is zero: + } else { + // use the limit's start and end for our search query + $searchStart = $repetition->startdate; + $searchEnd = $repetition->enddate; + $limit = floatval($repetition->amount); // the limit is the repetitions limit: + } + + $expenses = floatval($budget->transactionjournals()->before($searchEnd)->after($searchStart)->lessThan(0)->sum('amount')) * -1; + if ($expenses > 0) { + $chart->addRow($budget->name, $limit, $expenses); + } + } + + $noBudgetSet = Auth::user() + ->transactionjournals() + ->whereNotIn( + 'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) { + $query + ->select('transaction_journals.id') + ->from('transaction_journals') + ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00')); + } + ) + ->before($end) + ->after($start) + ->lessThan(0) + ->transactionTypes(['Withdrawal']) + ->get(); + $sum = $noBudgetSet->sum('amount') * -1; + $chart->addRow('No budget', 0, $sum); + $chart->generate(); + + return Response::json($chart->getData()); + } + + /** + * @param GChart $chart + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function allCategoriesHomeChart(GChart $chart) + { + $chart->addColumn('Category', 'string'); + $chart->addColumn('Spent', 'number'); + + // query! + $start = Session::get('start', Carbon::now()->startOfMonth()); + $end = Session::get('end', Carbon::now()->endOfMonth()); + $set = TransactionJournal::leftJoin( + 'transactions', + function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0); + } + ) + ->leftJoin( + 'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id' + ) + ->leftJoin('categories', 'categories.id', '=', 'category_transaction_journal.category_id') + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->before($end) + ->after($start) + ->where('transaction_types.type', 'Withdrawal') + ->groupBy('categories.id') + ->orderBy('sum', 'DESC') + ->get(['categories.id', 'categories.name', \DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]); + + foreach ($set as $entry) { + $entry->name = strlen($entry->name) == 0 ? '(no category)' : $entry->name; + $chart->addRow($entry->name, floatval($entry->sum)); + } + + $chart->generate(); + + return Response::json($chart->getData()); + + } + + /** + * @param Bill $bill + * + * @return \Illuminate\Http\JsonResponse + */ + public function billOverview(Bill $bill, GChart $chart) + { + + $chart->addColumn('Date', 'date'); + $chart->addColumn('Max amount', 'number'); + $chart->addColumn('Min amount', 'number'); + $chart->addColumn('Current entry', 'number'); + + // get first transaction or today for start: + $first = $bill->transactionjournals()->orderBy('date', 'ASC')->first(); + if ($first) { + $start = $first->date; + } else { + $start = new Carbon; + } + $end = new Carbon; + while ($start <= $end) { + $result = $bill->transactionjournals()->before($end)->after($start)->first(); + if ($result) { + /** @var Transaction $tr */ + foreach ($result->transactions()->get() as $tr) { + if (floatval($tr->amount) > 0) { + $amount = floatval($tr->amount); + } + } + } else { + $amount = 0; + } + unset($result); + $chart->addRow(clone $start, $bill->amount_max, $bill->amount_min, $amount); + $start = Navigation::addPeriod($start, $bill->repeat_freq, 0); + } + + $chart->generate(); + + return Response::json($chart->getData()); + + } + + /** + * @param GChart $chart + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function billsOverview(GChart $chart) + { + $paid = ['items' => [], 'amount' => 0]; + $unpaid = ['items' => [], 'amount' => 0]; + $start = Session::get('start', Carbon::now()->startOfMonth()); + $end = Session::get('end', Carbon::now()->endOfMonth()); + + $chart->addColumn('Name', 'string'); + $chart->addColumn('Amount', 'number'); + + $set = Bill:: + leftJoin( + 'transaction_journals', function (JoinClause $join) use ($start, $end) { + $join->on('bills.id', '=', 'transaction_journals.bill_id') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')); + } + ) + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '>', 0); + } + ) + ->where('active', 1) + ->groupBy('bills.id') + ->get( + ['bills.id', 'bills.name', 'transaction_journals.description', + 'transaction_journals.encrypted', + 'transaction_journals.id as journalId', + \DB::Raw('SUM(`bills`.`amount_min` + `bills`.`amount_max`) / 2 as `averageAmount`'), + 'transactions.amount AS actualAmount'] + ); + + foreach ($set as $entry) { + if (intval($entry->journalId) == 0) { + $unpaid['items'][] = $entry->name; + $unpaid['amount'] += floatval($entry->averageAmount); + } else { + $description = intval($entry->encrypted) == 1 ? Crypt::decrypt($entry->description) : $entry->description; + $paid['items'][] = $description; + $paid['amount'] += floatval($entry->actualAmount); + } + } + $chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']); + $chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']); + $chart->generate(); + + return Response::json($chart->getData()); + } + + /** + * + * @param Budget $budget + * @param LimitRepetition $repetition + * + * @return \Illuminate\Http\JsonResponse + */ + public function budgetLimitSpending(Budget $budget, LimitRepetition $repetition, GChart $chart) + { + $start = clone $repetition->startdate; + $end = $repetition->enddate; + + $chart->addColumn('Day', 'date'); + $chart->addColumn('Left', 'number'); + + + $amount = $repetition->amount; + + while ($start <= $end) { + /* + * Sum of expenses on this day: + */ + $sum = floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($start)->sum('amount')); + $amount += $sum; + $chart->addRow(clone $start, $amount); + $start->addDay(); + } + $chart->generate(); + + return Response::json($chart->getData()); + + } + + /** + * + * @param Budget $budget + * + * @param int $year + * + * @return \Illuminate\Http\JsonResponse + */ + public function budgetsAndSpending(Budget $budget, $year = 0) + { + + $chart = App::make('Grumpydictator\Gchart\GChart'); + $repository = App::make('FireflyIII\Repositories\Budget\BudgetRepository'); + $chart->addColumn('Month', 'date'); + $chart->addColumn('Budgeted', 'number'); + $chart->addColumn('Spent', 'number'); + if ($year == 0) { + // grab the first budgetlimit ever: + $firstLimit = $budget->budgetlimits()->orderBy('startdate', 'ASC')->first(); + if ($firstLimit) { + $start = new Carbon($firstLimit->startdate); + } else { + $start = Carbon::now()->startOfYear(); + } + + // grab the last budget limit ever: + $lastLimit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first(); + if ($lastLimit) { + $end = new Carbon($lastLimit->startdate); + } else { + $end = Carbon::now()->endOfYear(); + } + } else { + $start = Carbon::createFromDate(intval($year), 1, 1); + $end = clone $start; + $end->endOfYear(); + } + + while ($start <= $end) { + $spent = $repository->spentInMonth($budget, $start); + $repetition = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') + ->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00')) + ->where('budget_limits.budget_id', $budget->id) + ->first(['limit_repetitions.*']); + + if ($repetition) { + $budgeted = floatval($repetition->amount); + \Log::debug('Found a repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name . '!'); + } else { + \Log::debug('No repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name); + $budgeted = null; + } + $chart->addRow(clone $start, $budgeted, $spent); + $start->addMonth(); + } + + $chart->generate(); + + return Response::json($chart->getData()); + + + } + + /** + * + * @param Category $category + * @param $year + * + * @return \Illuminate\Http\JsonResponse + */ + public function categoriesAndSpending(Category $category, $year, GChart $chart) + { + try { + new Carbon('01-01-' . $year); + } catch (Exception $e) { + return view('error')->with('message', 'Invalid year.'); + } + + $chart->addColumn('Month', 'date'); + $chart->addColumn('Budgeted', 'number'); + $chart->addColumn('Spent', 'number'); + + $start = new Carbon('01-01-' . $year); + $end = clone $start; + $end->endOfYear(); + while ($start <= $end) { + + $currentEnd = clone $start; + $currentEnd->endOfMonth(); + $spent = floatval($category->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1; + $budgeted = null; + + $chart->addRow(clone $start, $budgeted, $spent); + + $start->addMonth(); + } + + + $chart->generate(); + + return Response::json($chart->getData()); + + + } + + /** + * @param PiggyBank $piggyBank + * + * @return \Illuminate\Http\JsonResponse + */ + public function piggyBankHistory(PiggyBank $piggyBank, GChart $chart) + { + $chart->addColumn('Date', 'date'); + $chart->addColumn('Balance', 'number'); + + $set = \DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]); + + foreach ($set as $entry) { + $chart->addRow(new Carbon($entry->date), floatval($entry->sum)); + } + + $chart->generate(); + + return Response::json($chart->getData()); + + } + + /** + * + * @param $year + * + * @return \Illuminate\Http\JsonResponse + */ + public function yearInExp($year, GChart $chart, ReportQueryInterface $query) + { + try { + $start = new Carbon('01-01-' . $year); + } catch (Exception $e) { + return view('error')->with('message', 'Invalid year.'); + } + $chart->addColumn('Month', 'date'); + $chart->addColumn('Income', 'number'); + $chart->addColumn('Expenses', 'number'); + + // get report query interface. + + $end = clone $start; + $end->endOfYear(); + while ($start < $end) { + $currentEnd = clone $start; + $currentEnd->endOfMonth(); + // total income: + $income = $query->incomeByPeriod($start, $currentEnd); + $incomeSum = 0; + foreach ($income as $entry) { + $incomeSum += floatval($entry->amount); + } + + // total expenses: + $expense = $query->journalsByExpenseAccount($start, $currentEnd); + $expenseSum = 0; + foreach ($expense as $entry) { + $expenseSum += floatval($entry->amount); + } + + $chart->addRow(clone $start, $incomeSum, $expenseSum); + $start->addMonth(); + } + + + $chart->generate(); + + return Response::json($chart->getData()); + + } + + /** + * + * @param $year + * + * @return \Illuminate\Http\JsonResponse + */ + public function yearInExpSum($year, GChart $chart, ReportQueryInterface $query) + { + try { + $start = new Carbon('01-01-' . $year); + } catch (Exception $e) { + return view('error')->with('message', 'Invalid year.'); + } + $chart->addColumn('Summary', 'string'); + $chart->addColumn('Income', 'number'); + $chart->addColumn('Expenses', 'number'); + + $income = 0; + $expense = 0; + $count = 0; + + $end = clone $start; + $end->endOfYear(); + while ($start < $end) { + $currentEnd = clone $start; + $currentEnd->endOfMonth(); + // total income: + $incomeResult = $query->incomeByPeriod($start, $currentEnd); + $incomeSum = 0; + foreach ($incomeResult as $entry) { + $incomeSum += floatval($entry->amount); + } + + // total expenses: + $expenseResult = $query->journalsByExpenseAccount($start, $currentEnd); + $expenseSum = 0; + foreach ($expenseResult as $entry) { + $expenseSum += floatval($entry->amount); + } + + $income += $incomeSum; + $expense += $expenseSum; + $count++; + $start->addMonth(); + } + + + $chart->addRow('Sum', $income, $expense); + $count = $count > 0 ? $count : 1; + $chart->addRow('Average', ($income / $count), ($expense / $count)); + + $chart->generate(); + + return Response::json($chart->getData()); + + } + + +} diff --git a/app/controllers/HelpController.php b/app/Http/Controllers/HelpController.php similarity index 80% rename from app/controllers/HelpController.php rename to app/Http/Controllers/HelpController.php index dbb9f7a2aa..19457e4786 100644 --- a/app/controllers/HelpController.php +++ b/app/Http/Controllers/HelpController.php @@ -1,13 +1,22 @@ -There is no help for this route.

'; } - $content['text'] = \Michelf\Markdown::defaultTransform($content['text']); + $converter = new CommonMarkConverter(); + $content['text'] = $converter->convertToHtml($content['text']); return $content; } -} +} diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php new file mode 100644 index 0000000000..0d6056761f --- /dev/null +++ b/app/Http/Controllers/HomeController.php @@ -0,0 +1,124 @@ +accounts()->accountTypeIn(['Asset account', 'Default account'])->count(); + $title = 'Firefly'; + $subTitle = 'What\'s playing?'; + $mainTitleIcon = 'fa-fire'; + $transactions = []; + $frontPage = Preferences::get('frontPageAccounts', []); + $start = Session::get('start', Carbon::now()->startOfMonth()); + $end = Session::get('end', Carbon::now()->endOfMonth()); + + if ($frontPage->data == []) { + $accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']); + } else { + $accounts = Auth::user()->accounts()->whereIn('id', $frontPage->data)->get(['accounts.*']); + } + + foreach ($accounts as $account) { + $set = Auth::user() + ->transactionjournals() + ->with(['transactions', 'transactioncurrency', 'transactiontype']) + ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id) + ->where('date', '>=', $start->format('Y-m-d')) + ->where('date', '<=', $end->format('Y-m-d')) + ->orderBy('transaction_journals.date', 'DESC') + ->orderBy('transaction_journals.id', 'DESC') + ->take(10) + ->get(['transaction_journals.*']); + if (count($set) > 0) { + $transactions[] = [$set, $account]; + } + } + + // var_dump($transactions); + + return view('index', compact('count', 'title', 'subTitle', 'mainTitleIcon', 'transactions')); + } + + /** + * @param string $range + * + * @return mixed + */ + public function rangeJump($range) + { + + $valid = ['1D', '1W', '1M', '3M', '6M', '1Y',]; + + if (in_array($range, $valid)) { + Preferences::set('viewRange', $range); + Session::forget('range'); + } + + return Redirect::to(URL::previous()); + } + + /** + * @return \Illuminate\Http\RedirectResponse + */ + public function sessionNext() + { + $range = Session::get('range'); + $start = Session::get('start'); + + Session::put('start', Navigation::jumpToNext($range, clone $start)); + + return Redirect::to(URL::previous()); + + } + + /** + * @return \Illuminate\Http\RedirectResponse + */ + public function sessionPrev() + { + $range = Session::get('range'); + $start = Session::get('start'); + + Session::put('start', Navigation::jumpToPrevious($range, clone $start)); + + return Redirect::to(URL::previous()); + } + +} diff --git a/app/controllers/JsonController.php b/app/Http/Controllers/JsonController.php similarity index 57% rename from app/controllers/JsonController.php rename to app/Http/Controllers/JsonController.php index a0e6f08262..f4583a826f 100644 --- a/app/controllers/JsonController.php +++ b/app/Http/Controllers/JsonController.php @@ -1,11 +1,19 @@ -get(); + $list = Auth::user()->categories()->orderBy('name','ASC')->get(); $return = []; foreach ($list as $entry) { $return[] = $entry->name; @@ -34,9 +40,7 @@ class JsonController extends BaseController */ public function expenseAccounts() { - /** @var \FireflyIII\Database\Account\Account $accounts */ - $accounts = App::make('FireflyIII\Database\Account\Account'); - $list = $accounts->getAccountsByType(['Expense account', 'Beneficiary account']); + $list = Auth::user()->accounts()->accountTypeIn(['Expense account', 'Beneficiary account'])->get(); $return = []; foreach ($list as $entry) { $return[] = $entry->name; @@ -51,9 +55,7 @@ class JsonController extends BaseController */ public function revenueAccounts() { - /** @var \FireflyIII\Database\Account\Account $accounts */ - $accounts = App::make('FireflyIII\Database\Account\Account'); - $list = $accounts->getAccountsByType(['Revenue account']); + $list = Auth::user()->accounts()->accountTypeIn(['Revenue account'])->get(); $return = []; foreach ($list as $entry) { $return[] = $entry->name; @@ -62,4 +64,5 @@ class JsonController extends BaseController return Response::json($return); } + } diff --git a/app/controllers/PiggybankController.php b/app/Http/Controllers/PiggyBankController.php similarity index 54% rename from app/controllers/PiggybankController.php rename to app/Http/Controllers/PiggyBankController.php index 5b9851eb84..9e2a7ef9f5 100644 --- a/app/controllers/PiggybankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -1,30 +1,36 @@ -_repository = $repository; View::share('title', 'Piggy banks'); View::share('mainTitleIcon', 'fa-sort-amount-asc'); } @@ -36,9 +42,9 @@ class PiggyBankController extends BaseController * * @return $this */ - public function add(PiggyBank $piggyBank) + public function add(PiggyBank $piggyBank, AccountRepositoryInterface $repository) { - $leftOnAccount = $this->_repository->leftOnAccount($piggyBank->account); + $leftOnAccount = $repository->leftOnAccount($piggyBank->account); $savedSoFar = $piggyBank->currentRelevantRep()->currentamount; $leftToSave = $piggyBank->targetamount - $savedSoFar; $maxAmount = min($leftOnAccount, $leftToSave); @@ -46,7 +52,7 @@ class PiggyBankController extends BaseController \Log::debug('Now going to view for piggy bank #' . $piggyBank->id . ' (' . $piggyBank->name . ')'); - return View::make('piggy_banks.add', compact('piggyBank', 'maxAmount')); + return view('piggy-banks.add', compact('piggyBank', 'maxAmount')); } /** @@ -55,15 +61,12 @@ class PiggyBankController extends BaseController public function create() { - /** @var \FireflyIII\Database\Account\Account $acct */ - $acct = App::make('FireflyIII\Database\Account\Account'); - $periods = Config::get('firefly.piggy_bank_periods'); - $accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account'])); + $accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])); $subTitle = 'Create new piggy bank'; $subTitleIcon = 'fa-plus'; - return View::make('piggy_banks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon')); + return view('piggy-banks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon')); } /** @@ -75,7 +78,7 @@ class PiggyBankController extends BaseController { $subTitle = 'Delete "' . e($piggyBank->name) . '"'; - return View::make('piggy_banks.delete', compact('piggyBank', 'subTitle')); + return view('piggy_banks.delete', compact('piggyBank', 'subTitle')); } /** @@ -102,11 +105,8 @@ class PiggyBankController extends BaseController public function edit(PiggyBank $piggyBank) { - /** @var \FireflyIII\Database\Account\Account $acct */ - $acct = App::make('FireflyIII\Database\Account\Account'); - $periods = Config::get('firefly.piggy_bank_periods'); - $accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account'])); + $accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])); $subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"'; $subTitleIcon = 'fa-pencil'; @@ -128,16 +128,17 @@ class PiggyBankController extends BaseController ]; Session::flash('preFilled', $preFilled); - return View::make('piggy_banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'accounts', 'periods', 'preFilled')); + return view('piggy-banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'accounts', 'periods', 'preFilled')); } + /** * @return $this */ - public function index() + public function index(AccountRepositoryInterface $repository) { /** @var Collection $piggyBanks */ - $piggyBanks = $this->_repository->get(); + $piggyBanks = Auth::user()->piggyBanks()->where('repeats', 0)->get(); $accounts = []; /** @var PiggyBank $piggyBank */ @@ -154,7 +155,7 @@ class PiggyBankController extends BaseController $accounts[$account->id] = [ 'name' => $account->name, 'balance' => Steam::balance($account), - 'leftForPiggyBanks' => $this->_repository->leftOnAccount($account), + 'leftForPiggyBanks' => $repository->leftOnAccount($account), 'sumOfSaved' => $piggyBank->savedSoFar, 'sumOfTargets' => floatval($piggyBank->targetamount), 'leftToSave' => $piggyBank->leftToSave @@ -166,9 +167,10 @@ class PiggyBankController extends BaseController } } - return View::make('piggy_banks.index', compact('piggyBanks', 'accounts')); + return view('piggy-banks.index', compact('piggyBanks', 'accounts')); } + /** * POST add money to piggy bank * @@ -176,14 +178,10 @@ class PiggyBankController extends BaseController * * @return \Illuminate\Http\RedirectResponse */ - public function postAdd(PiggyBank $piggyBank) + public function postAdd(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository, AccountRepositoryInterface $accounts) { - $amount = round(floatval(Input::get('amount')), 2); - - /** @var \FireflyIII\Database\PiggyBank\PiggyBank $acct */ - $piggyRepository = App::make('FireflyIII\Database\PiggyBank\PiggyBank'); - - $leftOnAccount = $piggyRepository->leftOnAccount($piggyBank->account); + $amount = round(floatval(Input::get('amount')), 2); + $leftOnAccount = $accounts->leftOnAccount($piggyBank->account); $savedSoFar = $piggyBank->currentRelevantRep()->currentamount; $leftToSave = $piggyBank->targetamount - $savedSoFar; $maxAmount = round(min($leftOnAccount, $leftToSave), 2); @@ -196,14 +194,14 @@ class PiggyBankController extends BaseController /* * Create event! */ - Event::fire('piggy_bank.addMoney', [$piggyBank, $amount]); // new and used. + //Event::fire('piggy_bank.addMoney', [$piggyBank, $amount]); // new and used. Session::flash('success', 'Added ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".'); } else { Session::flash('error', 'Could not add ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".'); } - return Redirect::route('piggy_banks.index'); + return Redirect::route('piggy-banks.index'); } /** @@ -225,14 +223,14 @@ class PiggyBankController extends BaseController /* * Create event! */ - Event::fire('piggy_bank.removeMoney', [$piggyBank, $amount]); // new and used. + //Event::fire('piggy_bank.removeMoney', [$piggyBank, $amount]); // new and used. Session::flash('success', 'Removed ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".'); } else { Session::flash('error', 'Could not remove ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".'); } - return Redirect::route('piggy_banks.index'); + return Redirect::route('piggy-banks.index'); } /** @@ -244,7 +242,7 @@ class PiggyBankController extends BaseController */ public function remove(PiggyBank $piggyBank) { - return View::make('piggy_banks.remove', compact('piggyBank')); + return view('piggy-banks.remove', compact('piggyBank')); } /** @@ -263,51 +261,30 @@ class PiggyBankController extends BaseController $subTitle = e($piggyBank->name); - return View::make('piggy_banks.show', compact('piggyBank', 'events', 'subTitle')); + return view('piggy-banks.show', compact('piggyBank', 'events', 'subTitle')); } /** * */ - public function store() + public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository) { - $data = Input::all(); - $data['repeats'] = 0; - $data['user_id'] = Auth::user()->id; - $data['rep_every'] = 0; - $data['reminder_skip'] = 0; - $data['remind_me'] = intval(Input::get('remind_me')); - $data['order'] = 0; + $piggyBankData = [ + 'repeats' => false, + 'name' => $request->get('name'), + 'startdate' => new Carbon, + 'account_id' => intval($request->get('account_id')), + 'targetamount' => floatval($request->get('targetamount')), + 'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null, + 'reminder' => $request->get('reminder'), + ]; + $piggyBank = $repository->store($piggyBankData); - // always validate: - $messages = $this->_repository->validate($data); + Session::flash('success', 'Stored piggy bank "' . e($piggyBank->name) . '".'); - // flash messages: - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not store piggy bank: ' . $messages['errors']->first()); - return Redirect::route('piggy_banks.create')->withInput(); - } - - - // return to create screen: - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('piggy_banks.create')->withInput(); - } - - // store - $piggyBank = $this->_repository->store($data); - Event::fire('piggy_bank.store', [$piggyBank]); // new and used. - Session::flash('success', 'Piggy bank "' . e($data['name']) . '" stored.'); - if ($data['post_submit_action'] == 'store') { - return Redirect::route('piggy_banks.index'); - } - - return Redirect::route('piggy_banks.create')->withInput(); + return Redirect::route('piggy-banks.index'); } /** @@ -316,45 +293,27 @@ class PiggyBankController extends BaseController * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. * * @return $this - * @throws FireflyException */ - public function update(PiggyBank $piggyBank) + public function update(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository, PiggyBankFormRequest $request) { + $piggyBankData = [ + 'repeats' => false, + 'name' => $request->get('name'), + 'account_id' => intval($request->get('account_id')), + 'targetamount' => floatval($request->get('targetamount')), + 'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null, + 'reminder' => $request->get('reminder'), + ]; - $data = Input::except('_token'); - $data['rep_every'] = 0; - $data['reminder_skip'] = 0; - $data['order'] = 0; - $data['remind_me'] = isset($data['remind_me']) ? 1 : 0; - $data['user_id'] = Auth::user()->id; - $data['repeats'] = 0; + $piggyBank = $repository->update($piggyBank, $piggyBankData); - $messages = $this->_repository->validate($data); + Session::flash('success', 'Updated piggy bank "' . e($piggyBank->name) . '".'); - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not update piggy bank: ' . $messages['errors']->first()); - return Redirect::route('piggy_banks.edit', $piggyBank->id)->withInput(); - } + return Redirect::route('piggy-banks.index'); - // return to update screen: - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('piggy_banks.edit', $piggyBank->id)->withInput(); - } - - // update - $this->_repository->update($piggyBank, $data); - Session::flash('success', 'Piggy bank "' . e($data['name']) . '" updated.'); - - // go back to list - if ($data['post_submit_action'] == 'update') { - return Redirect::route('piggy_banks.index'); - } - - // go back to update screen. - return Redirect::route('piggy_banks.edit', $piggyBank->id)->withInput(['post_submit_action' => 'return_to_edit']); } + + + } diff --git a/app/Http/Controllers/PreferencesController.php b/app/Http/Controllers/PreferencesController.php new file mode 100644 index 0000000000..c8c1379149 --- /dev/null +++ b/app/Http/Controllers/PreferencesController.php @@ -0,0 +1,76 @@ +accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']); + $viewRange = Preferences::get('viewRange', '1M'); + $viewRangeValue = $viewRange->data; + $frontPage = Preferences::get('frontPageAccounts', []); + $budgetMax = Preferences::get('budgetMaximum', 1000); + $budgetMaximum = $budgetMax->data; + + return view('preferences.index', compact('budgetMaximum'))->with('accounts', $accounts)->with('frontPageAccounts', $frontPage)->with( + 'viewRange', $viewRangeValue + ); + } + + /** + * @return \Illuminate\Http\RedirectResponse + */ + public function postIndex() + { + // front page accounts + $frontPageAccounts = []; + foreach (Input::get('frontPageAccounts') as $id) { + $frontPageAccounts[] = intval($id); + } + Preferences::set('frontPageAccounts', $frontPageAccounts); + + // view range: + Preferences::set('viewRange', Input::get('viewRange')); + // forget session values: + Session::forget('start'); + Session::forget('end'); + Session::forget('range'); + + // budget maximum: + $budgetMaximum = intval(Input::get('budgetMaximum')); + Preferences::set('budgetMaximum', $budgetMaximum); + + + Session::flash('success', 'Preferences saved!'); + + return Redirect::route('preferences'); + } + +} diff --git a/app/controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php similarity index 56% rename from app/controllers/ProfileController.php rename to app/Http/Controllers/ProfileController.php index 8ac759f571..e9e6daadef 100644 --- a/app/controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -1,10 +1,18 @@ -with('title', Auth::user()->email)->with('subTitle', 'Change your password')->with( + return view('profile.change-password')->with('title', Auth::user()->email)->with('subTitle', 'Change your password')->with( 'mainTitleIcon', 'fa-user' ); } @@ -23,32 +31,30 @@ class ProfileController extends BaseController */ public function index() { - return View::make('profile.index')->with('title', 'Profile')->with('subTitle', Auth::user()->email)->with('mainTitleIcon', 'fa-user'); + return view('profile.index')->with('title', 'Profile')->with('subTitle', Auth::user()->email)->with('mainTitleIcon', 'fa-user'); } /** * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View */ - public function postChangePassword() + public function postChangePassword(ProfileFormRequest $request) { - // old, new1, new2 - if (!Hash::check(Input::get('old'), Auth::user()->password)) { + if (!Hash::check($request->get('current_password'), Auth::user()->password)) { Session::flash('error', 'Invalid current password!'); - return View::make('profile.change-password'); + return Redirect::route('change-password'); } - $result = $this->_validatePassword(Input::get('old'), Input::get('new1'), Input::get('new2')); + $result = $this->_validatePassword($request->get('current_password'), $request->get('new_password'), $request->get('new_password_confirmation')); if (!($result === true)) { Session::flash('error', $result); - return View::make('profile.change-password'); + return Redirect::route('change-password'); } // update the user with the new password. - /** @var \FireflyIII\Database\User\User $repository */ - $repository = \App::make('FireflyIII\Database\User\User'); - $repository->updatePassword(Auth::user(), Input::get('new1')); + Auth::user()->password = $request->get('new_password'); + Auth::user()->save(); Session::flash('success', 'Password changed!'); @@ -81,5 +87,4 @@ class ProfileController extends BaseController return true; } - -} +} diff --git a/app/controllers/RelatedController.php b/app/Http/Controllers/RelatedController.php similarity index 72% rename from app/controllers/RelatedController.php rename to app/Http/Controllers/RelatedController.php index fb77ee320c..9ea88a1352 100644 --- a/app/controllers/RelatedController.php +++ b/app/Http/Controllers/RelatedController.php @@ -1,28 +1,25 @@ -_repository = $repository; - - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. * * @param TransactionJournal $journal * @@ -43,10 +40,16 @@ class RelatedController extends BaseController $unique = array_unique($ids); if (count($unique) > 0) { - $set = $this->_repository->getJournalsByIds($unique); + $set = Auth::user()->transactionjournals()->whereIn('id', $unique)->get(); $set->each( function (TransactionJournal $journal) { - $journal->amount = Amount::format($journal->getAmount()); + /** @var Transaction $t */ + foreach ($journal->transactions()->get() as $t) { + if ($t->amount > 0) { + $journal->amount = $t->amount; + } + } + } ); @@ -66,7 +69,7 @@ class RelatedController extends BaseController { $group = new TransactionGroup; $group->relation = 'balance'; - $group->user_id = $this->_repository->getUser()->id; + $group->user_id = Auth::user()->id; $group->save(); $group->transactionjournals()->save($parentJournal); $group->transactionjournals()->save($childJournal); @@ -94,7 +97,7 @@ class RelatedController extends BaseController } } - return View::make('related.relate', compact('journal', 'members')); + return view('related.relate', compact('journal', 'members')); } /** @@ -130,15 +133,20 @@ class RelatedController extends BaseController * * @return \Illuminate\Http\JsonResponse */ - public function search(TransactionJournal $journal) + public function search(TransactionJournal $journal, JournalRepositoryInterface $repository) { $search = e(trim(Input::get('searchValue'))); - $result = $this->_repository->search($search, $journal); + $result = $repository->searchRelated($search, $journal); $result->each( - function (TransactionJournal $j) { - $j->amount = Amount::format($j->getAmount()); + function (TransactionJournal $journal) { + /** @var Transaction $t */ + foreach ($journal->transactions()->get() as $t) { + if ($t->amount > 0) { + $journal->amount = $t->amount; + } + } } ); diff --git a/app/Http/Controllers/RepeatedExpenseController.php b/app/Http/Controllers/RepeatedExpenseController.php new file mode 100644 index 0000000000..8569b067a9 --- /dev/null +++ b/app/Http/Controllers/RepeatedExpenseController.php @@ -0,0 +1,199 @@ +accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])); + + return view('repeatedExpense.create', compact('accounts', 'periods'))->with('subTitle', 'Create new repeated expense')->with( + 'subTitleIcon', 'fa-plus' + ); + } + + /** + * @param PiggyBank $repeatedExpense + * + * @return $this + */ + public function delete(PiggyBank $repeatedExpense) + { + $subTitle = 'Delete "' . e($repeatedExpense->name) . '"'; + + return view('repeatedExpense.delete', compact('repeatedExpense', 'subTitle')); + } + + /** + * @param PiggyBank $repeatedExpense + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(PiggyBank $repeatedExpense) + { + + Session::flash('success', 'Repeated expense "' . e($repeatedExpense->name) . '" deleted.'); + + $repeatedExpense->delete(); + + return Redirect::route('repeated.index'); + } + + /** + * @param PiggyBank $repeatedExpense + * + * @return $this + */ + public function edit(PiggyBank $repeatedExpense) + { + + $periods = Config::get('firefly.piggy_bank_periods'); + $accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])); + $subTitle = 'Edit repeated expense "' . e($repeatedExpense->name) . '"'; + $subTitleIcon = 'fa-pencil'; + + /* + * Flash some data to fill the form. + */ + $preFilled = ['name' => $repeatedExpense->name, + 'account_id' => $repeatedExpense->account_id, + 'targetamount' => $repeatedExpense->targetamount, + 'reminder_skip' => $repeatedExpense->reminder_skip, + 'rep_every' => $repeatedExpense->rep_every, + 'rep_times' => $repeatedExpense->rep_times, + 'targetdate' => $repeatedExpense->targetdate->format('Y-m-d'), + 'reminder' => $repeatedExpense->reminder, + 'remind_me' => intval($repeatedExpense->remind_me) == 1 || !is_null($repeatedExpense->reminder) ? true : false + ]; + Session::flash('preFilled', $preFilled); + + return view('repeatedExpense.edit', compact('subTitle', 'subTitleIcon', 'repeatedExpense', 'accounts', 'periods', 'preFilled')); + } + + /** + * @return \Illuminate\View\View + */ + public function index() + { + + $subTitle = 'Overview'; + + $expenses = Auth::user()->piggyBanks()->where('repeats', 1)->get(); + $expenses->each( + function (PiggyBank $piggyBank) { + $piggyBank->currentRelevantRep(); + } + ); + + return view('repeatedExpense.index', compact('expenses', 'subTitle')); + } + + /** + * @param PiggyBank $repeatedExpense + * + * @return \Illuminate\View\View + */ + public function show(PiggyBank $repeatedExpense, PiggyBankRepositoryInterface $repository) + { + $subTitle = $repeatedExpense->name; + $today = Carbon::now(); + $repetitions = $repeatedExpense->piggyBankRepetitions()->get(); + + $repetitions->each( + function (PiggyBankRepetition $repetition) use ($repository) { + $repetition->bars = $repository->calculateParts($repetition); + } + ); + + return view('repeatedExpense.show', compact('repetitions', 'repeatedExpense', 'today', 'subTitle')); + } + + /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + */ + public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository) + { + + $piggyBankData = [ + 'repeats' => true, + 'name' => $request->get('name'), + 'startdate' => new Carbon, + 'account_id' => intval($request->get('account_id')), + 'targetamount' => floatval($request->get('targetamount')), + 'targetdate' => new Carbon($request->get('targetdate')), + 'reminder' => $request->get('reminder'), + 'skip' => intval($request->get('skip')), + 'rep_every' => intval($request->get('rep_every')), + 'rep_times' => intval($request->get('rep_times')), + ]; + + $piggyBank = $repository->store($piggyBankData); + + Session::flash('success', 'Stored repeated expense "' . e($piggyBank->name) . '".'); + + return Redirect::route('repeated.index'); + } + + /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * + * @param PiggyBank $repeatedExpense + * + * @return $this + */ + public function update(PiggyBank $repeatedExpense, PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository) + { + $piggyBankData = [ + 'repeats' => false, + 'name' => $request->get('name'), + 'account_id' => intval($request->get('account_id')), + 'targetamount' => floatval($request->get('targetamount')), + 'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null, + 'rep_length' => $request->get('rep_length'), + 'rep_every' => intval($request->get('rep_every')), + 'rep_times' => intval($request->get('rep_times')), + 'remind_me' => intval($request->get('remind_me')) == 1 ? true : false , + 'reminder' => $request->get('reminder'), + ]; + + + $piggyBank = $repository->update($repeatedExpense, $piggyBankData); + + Session::flash('success', 'Updated repeated expense "' . e($piggyBank->name) . '".'); + + return Redirect::route('repeated.index'); + + } + +} diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php new file mode 100644 index 0000000000..5349059c90 --- /dev/null +++ b/app/Http/Controllers/ReportController.php @@ -0,0 +1,284 @@ +with('message', 'Invalid date'); + } + $date = new Carbon($year . '-' . $month . '-01'); + $start = clone $date; + $start->startOfMonth(); + $end = clone $date; + $end->endOfMonth(); + $start->subDay(); + + $dayEarly = clone $date; + $subTitle = 'Budget report for ' . $date->format('F Y'); + $subTitleIcon = 'fa-calendar'; + $dayEarly = $dayEarly->subDay(); + $accounts = $query->getAllAccounts($start, $end); + $start->addDay(); + + $accounts->each( + function (Account $account) use ($start, $end, $query) { + $budgets = $query->getBudgetSummary($account, $start, $end); + $balancedAmount = $query->balancedTransactionsList($account, $start, $end); + $array = []; + foreach ($budgets as $budget) { + $id = intval($budget->id); + $data = $budget->toArray(); + $array[$id] = $data; + } + + $account->budgetInformation = $array; + $account->balancedAmount = $balancedAmount; + + } + ); + + $start = clone $date; + $start->startOfMonth(); + + /** + * Start getBudgetsForMonth DONE + */ + $set = Auth::user()->budgets()->orderBy('budgets.name', 'ASC') + ->leftJoin( + 'budget_limits', function (JoinClause $join) use ($date) { + $join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d')); + } + ) + ->get(['budgets.*', 'budget_limits.amount as amount']); + $budgets = Steam::makeArray($set); + $amountSet = $query->journalsByBudget($start, $end); + $amounts = Steam::makeArray($amountSet); + $budgets = Steam::mergeArrays($budgets, $amounts); + $budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0; + $budgets[0]['amount'] = isset($budgets[0]['amount']) ? $budgets[0]['amount'] : 0.0; + $budgets[0]['name'] = 'No budget'; + + // find transactions to shared expense accounts, which are without a budget by default: + $transfers = $query->sharedExpenses($start, $end); + foreach ($transfers as $transfer) { + $budgets[0]['spent'] += floatval($transfer->amount) * -1; + } + + /** + * End getBudgetsForMonth DONE + */ + + return view('reports.budget', compact('subTitle', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly')); + + } + + /** + * @param ReportHelperInterface $helper + * + * @return View + */ + public function index(ReportHelperInterface $helper) + { + $start = $helper->firstDate(); + $months = $helper->listOfMonths($start); + $years = $helper->listOfYears($start); + $title = 'Reports'; + $mainTitleIcon = 'fa-line-chart'; + + return view('reports.index', compact('years', 'months', 'title', 'mainTitleIcon')); + } + + /** + * @param string $year + * @param string $month + * + * @return \Illuminate\View\View + */ + public function month($year = '2014', $month = '1', ReportQueryInterface $query) + { + try { + new Carbon($year . '-' . $month . '-01'); + } catch (Exception $e) { + return view('error')->with('message', 'Invalid date.'); + } + $date = new Carbon($year . '-' . $month . '-01'); + $subTitle = 'Report for ' . $date->format('F Y'); + $subTitleIcon = 'fa-calendar'; + $displaySum = true; // to show sums in report. + + + /** + * + * get income for month (date) + * + */ + + $start = clone $date; + $start->startOfMonth(); + $end = clone $date; + $end->endOfMonth(); + + /** + * Start getIncomeForMonth DONE + */ + $income = $query->incomeByPeriod($start, $end); + /** + * End getIncomeForMonth DONE + */ + /** + * Start getExpenseGroupedForMonth DONE + */ + $set = $query->journalsByExpenseAccount($start, $end); + $expenses = Steam::makeArray($set); + $expenses = Steam::sortArray($expenses); + $expenses = Steam::limitArray($expenses, 10); + /** + * End getExpenseGroupedForMonth DONE + */ + /** + * Start getBudgetsForMonth DONE + */ + $set = Auth::user()->budgets() + ->leftJoin( + 'budget_limits', function (JoinClause $join) use ($date) { + $join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d')); + } + ) + ->get(['budgets.*', 'budget_limits.amount as amount']); + $budgets = Steam::makeArray($set); + $amountSet = $query->journalsByBudget($start, $end); + $amounts = Steam::makeArray($amountSet); + $budgets = Steam::mergeArrays($budgets, $amounts); + $budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0; + $budgets[0]['amount'] = isset($budgets[0]['amount']) ? $budgets[0]['amount'] : 0.0; + $budgets[0]['name'] = 'No budget'; + + // find transactions to shared expense accounts, which are without a budget by default: + $transfers = $query->sharedExpenses($start, $end); + foreach ($transfers as $transfer) { + $budgets[0]['spent'] += floatval($transfer->amount) * -1; + } + + /** + * End getBudgetsForMonth DONE + */ + /** + * Start getCategoriesForMonth DONE + */ + // all categories. + $result = $query->journalsByCategory($start, $end); + $categories = Steam::makeArray($result); + + // all transfers + $result = $query->sharedExpensesByCategory($start, $end); + $transfers = Steam::makeArray($result); + $merged = Steam::mergeArrays($categories, $transfers); + + // sort. + $sorted = Steam::sortNegativeArray($merged); + + // limit to $limit: + $categories = Steam::limitArray($sorted, 10); + /** + * End getCategoriesForMonth DONE + */ + /** + * Start getAccountsForMonth + */ + $list = $query->accountList(); + $accounts = []; + /** @var Account $account */ + foreach ($list as $account) { + $id = intval($account->id); + /** @noinspection PhpParamsInspection */ + $accounts[$id] = [ + 'name' => $account->name, + 'startBalance' => Steam::balance($account, $start), + 'endBalance' => Steam::balance($account, $end) + ]; + + $accounts[$id]['difference'] = $accounts[$id]['endBalance'] - $accounts[$id]['startBalance']; + } + + /** + * End getAccountsForMonth + */ + + + return view( + 'reports.month', + compact( + 'income', 'expenses', 'budgets', 'accounts', 'categories', + 'date', 'subTitle', 'displaySum', 'subTitleIcon' + ) + ); + } + + /** + * @param $year + * + * @return $this + */ + public function year($year, ReportHelperInterface $helper, ReportQueryInterface $query) + { + try { + new Carbon('01-01-' . $year); + } catch (Exception $e) { + return view('error')->with('message', 'Invalid date.'); + } + $date = new Carbon('01-01-' . $year); + $end = clone $date; + $end->endOfYear(); + $title = 'Reports'; + $subTitle = $year; + $subTitleIcon = 'fa-bar-chart'; + $mainTitleIcon = 'fa-line-chart'; + $balances = $helper->yearBalanceReport($date); + $groupedIncomes = $query->journalsByRevenueAccount($date, $end); + $groupedExpenses = $query->journalsByExpenseAccount($date, $end); + + //$groupedExpenses = $helper-> expensesGroupedByAccount($date, $end, 15); + + return view( + 'reports.year', compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon') + ); + } + + +} diff --git a/app/controllers/SearchController.php b/app/Http/Controllers/SearchController.php similarity index 70% rename from app/controllers/SearchController.php rename to app/Http/Controllers/SearchController.php index 6bcbb73d35..aa56c5e993 100644 --- a/app/controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -1,19 +1,24 @@ -with('title', 'Search')->with('subTitle', $subTitle)->with( + return view('search.index')->with('title', 'Search')->with('subTitle', $subTitle)->with( 'mainTitleIcon', 'fa-search' )->with('query', $rawQuery)->with('result', $result); } + } diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php new file mode 100644 index 0000000000..88a8e0f17f --- /dev/null +++ b/app/Http/Controllers/TransactionController.php @@ -0,0 +1,307 @@ +accounts()->accountTypeIn(['Default account', 'Asset account'])->where('active', 1)->orderBy('name', 'DESC')->get(['accounts.*']) + ); + $budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get()); + $budgets[0] = '(no budget)'; + $piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get()); + $piggies[0] = '(no piggy bank)'; + $preFilled = Session::has('preFilled') ? Session::get('preFilled') : []; + $respondTo = ['account_id', 'account_from_id']; + $subTitle = 'Add a new ' . e($what); + + foreach ($respondTo as $r) { + if (!is_null(Input::get($r))) { + $preFilled[$r] = Input::get($r); + } + } + Session::put('preFilled', $preFilled); + + asort($piggies); + + + return view('transactions.create', compact('accounts', 'budgets', 'what', 'piggies', 'subTitle')); + } + + /** + * Shows the form that allows a user to delete a transaction journal. + * + * @param TransactionJournal $journal + * + * @return $this + */ + public function delete(TransactionJournal $journal) + { + $type = strtolower($journal->transactionType->type); + $subTitle = 'Delete ' . e($type) . ' "' . e($journal->description) . '"'; + + return View::make('transactions.delete', compact('journal', 'subTitle')); + + + } + + /** + * @param TransactionJournal $transactionJournal + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(TransactionJournal $transactionJournal) + { + $type = $transactionJournal->transactionType->type; + $return = 'withdrawal'; + + Session::flash('success', 'Transaction "' . e($transactionJournal->description) . '" destroyed.'); + + $transactionJournal->delete(); + + switch ($type) { + case 'Deposit': + $return = 'deposit'; + break; + case 'Transfer': + $return = 'transfers'; + break; + } + + return Redirect::route('transactions.index', $return); + } + + /** + * Shows the view to edit a transaction. + * + * @param TransactionJournal $journal + * + * @return $this + */ + public function edit(TransactionJournal $journal, JournalRepositoryInterface $repository) + { + $what = strtolower($journal->transactiontype->type); + $accounts = ExpandedForm::makeSelectList( + Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->where('active', 1)->orderBy('name', 'DESC')->get(['accounts.*']) + ); + $budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get()); + $budgets[0] = '(no budget)'; + $transactions = $journal->transactions()->orderBy('amount', 'DESC')->get(); + $piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get()); + $piggies[0] = '(no piggy bank)'; + $preFilled = [ + 'date' => $journal->date->format('Y-m-d'), + 'category' => '', + 'budget_id' => 0, + 'piggy_bank_id' => 0 + ]; + + $category = $journal->categories()->first(); + if (!is_null($category)) { + $preFilled['category'] = $category->name; + } + + $budget = $journal->budgets()->first(); + if (!is_null($budget)) { + $preFilled['budget_id'] = $budget->id; + } + + if ($journal->piggyBankEvents()->count() > 0) { + $preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->first()->piggy_bank_id; + } + + $preFilled['amount'] = 0; + /** @var Transaction $t */ + foreach ($transactions as $t) { + if (floatval($t->amount) > 0) { + $preFilled['amount'] = floatval($t->amount); + } + } + $preFilled['account_id'] = $repository->getAssetAccount($journal); + $preFilled['expense_account'] = $transactions[0]->account->name; + $preFilled['revenue_account'] = $transactions[1]->account->name; + $preFilled['account_from_id'] = $transactions[1]->account->id; + $preFilled['account_to_id'] = $transactions[0]->account->id; + + + return View::make('transactions.edit', compact('journal', 'accounts', 'what', 'budgets', 'piggies', 'subTitle'))->with('data', $preFilled); + } + + /** + * @param $what + * + * @return $this + */ + public function index($what) + { + switch ($what) { + case 'expenses': + case 'withdrawal': + $subTitleIcon = 'fa-long-arrow-left'; + $subTitle = 'Expenses'; + //$journals = $this->_repository->getWithdrawalsPaginated(50); + $types = ['Withdrawal']; + break; + case 'revenue': + case 'deposit': + $subTitleIcon = 'fa-long-arrow-right'; + $subTitle = 'Revenue, income and deposits'; + // $journals = $this->_repository->getDepositsPaginated(50); + $types = ['Deposit']; + break; + case 'transfer': + case 'transfers': + $subTitleIcon = 'fa-arrows-h'; + $subTitle = 'Transfers'; + //$journals = $this->_repository->getTransfersPaginated(50); + $types = ['Transfer']; + break; + } + + $page = intval(\Input::get('page')); + $offset = $page > 0 ? ($page - 1) * 50 : 0; + + $set = Auth::user()->transactionJournals()->transactionTypes($types)->withRelevantData()->take(50)->offset($offset)->orderBy('date', 'DESC')->get( + ['transaction_journals.*'] + ); + $count = Auth::user()->transactionJournals()->transactionTypes($types)->count(); + $journals = new LengthAwarePaginator($set, $count, 50, $page); + $journals->setPath('transactions/' . $what); + + return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals')); + + } + + /** + * @param TransactionJournal $journal + * + * @return $this + */ + public function show(TransactionJournal $journal) + { + $journal->transactions->each( + function (Transaction $t) use ($journal) { + $t->before = floatval( + $t->account->transactions()->leftJoin( + 'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id' + )->where('transaction_journals.date', '<=', $journal->date->format('Y-m-d'))->where( + 'transaction_journals.created_at', '<=', $journal->created_at->format('Y-m-d H:i:s') + )->where('transaction_journals.id', '!=', $journal->id)->sum('transactions.amount') + ); + $t->after = $t->before + $t->amount; + } + ); + $members = new Collection; + /** @var TransactionGroup $group */ + foreach ($journal->transactiongroups()->get() as $group) { + /** @var TransactionJournal $loopJournal */ + foreach ($group->transactionjournals()->get() as $loopJournal) { + if ($loopJournal->id != $journal->id) { + $members->push($loopJournal); + } + } + } + + return view('transactions.show', compact('journal', 'members'))->with( + 'subTitle', e($journal->transactiontype->type) . ' "' . e($journal->description) . '"' + ); + } + + public function store(JournalFormRequest $request, JournalRepositoryInterface $repository) + { + + $journalData = [ + 'what' => $request->get('what'), + 'description' => $request->get('description'), + 'account_id' => intval($request->get('account_id')), + 'account_from_id' => intval($request->get('account_from_id')), + 'account_to_id' => intval($request->get('account_to_id')), + 'expense_account' => $request->get('expense_account'), + 'revenue_account' => $request->get('revenue_account'), + 'amount' => floatval($request->get('amount')), + 'user' => Auth::user()->id, + 'amount_currency_id' => intval($request->get('amount_currency_id')), + 'date' => new Carbon($request->get('date')), + 'budget_id' => intval($request->get('budget_id')), + 'category' => $request->get('category'), + ]; + + $journal = $repository->store($journalData); + + Session::flash('success', 'New transaction "' . $journal->description . '" stored!'); + + return Redirect::route('transactions.index', $request->input('what')); + + } + + /** + * @param TransactionJournal $journal + * + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * + * @return $this + * @throws FireflyException + */ + public function update(TransactionJournal $journal, JournalFormRequest $request, JournalRepositoryInterface $repository) + { + + $journalData = [ + 'what' => $request->get('what'), + 'description' => $request->get('description'), + 'account_id' => intval($request->get('account_id')), + 'account_from_id' => intval($request->get('account_from_id')), + 'account_to_id' => intval($request->get('account_to_id')), + 'expense_account' => $request->get('expense_account'), + 'revenue_account' => $request->get('revenue_account'), + 'amount' => floatval($request->get('amount')), + 'user' => Auth::user()->id, + 'amount_currency_id' => intval($request->get('amount_currency_id')), + 'date' => new Carbon($request->get('date')), + 'budget_id' => intval($request->get('budget_id')), + 'category' => $request->get('category'), + ]; + + $repository->update($journal, $journalData); + Session::flash('success', 'Transaction "' . e($journalData['description']) . '" updated.'); + + return Redirect::route('transactions.index', $journalData['what']); + + } + +} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php new file mode 100644 index 0000000000..67ce5757e4 --- /dev/null +++ b/app/Http/Kernel.php @@ -0,0 +1,41 @@ + 'FireflyIII\Http\Middleware\Authenticate', + 'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth', + 'guest' => 'FireflyIII\Http\Middleware\RedirectIfAuthenticated', + 'range' => 'FireflyIII\Http\Middleware\Range', + ]; + +} diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php new file mode 100644 index 0000000000..f014b3c53a --- /dev/null +++ b/app/Http/Middleware/Authenticate.php @@ -0,0 +1,53 @@ +auth = $auth; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * + * @return mixed + */ + public function handle($request, Closure $next) + { + if ($this->auth->guest()) { + if ($request->ajax()) { + return response('Unauthorized.', 401); + } else { + return redirect()->guest('auth/login'); + } + } + + return $next($request); + } + +} diff --git a/app/Http/Middleware/Range.php b/app/Http/Middleware/Range.php new file mode 100644 index 0000000000..49c3708b93 --- /dev/null +++ b/app/Http/Middleware/Range.php @@ -0,0 +1,75 @@ +auth = $auth; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $theNext + * + * @return mixed + */ + public function handle($request, Closure $theNext) + { + if ($this->auth->check()) { + // user's view range comes from preferences, gets set in session: + /** @var \FireflyIII\Models\Preference $viewRange */ + $viewRange = Preferences::get('viewRange', '1M'); + + + // the start and end date are checked and stored: + $start = Session::has('start') ? Session::get('start') : new Carbon; + $start = Navigation::updateStartDate($viewRange->data, $start); + $end = Navigation::updateEndDate($viewRange->data, $start); + $period = Navigation::periodName($viewRange->data, $start); + $prev = Navigation::jumpToPrevious($viewRange->data, clone $start); + $next = Navigation::jumpToNext($viewRange->data, clone $start); + + Session::put('range', $viewRange->data); + Session::put('start', $start); + Session::put('end', $end); + Session::put('period', $period); + Session::put('prev', Navigation::periodName($viewRange->data, $prev)); + Session::put('next', Navigation::periodName($viewRange->data, $next)); + + } + + return $theNext($request); + + } + +} \ No newline at end of file diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php new file mode 100644 index 0000000000..5033c35130 --- /dev/null +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -0,0 +1,50 @@ +auth = $auth; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * + * @return mixed + */ + public function handle($request, Closure $next) + { + if ($this->auth->check()) { + return new RedirectResponse(url('/')); + } + + return $next($request); + } + +} diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php new file mode 100644 index 0000000000..0cb1548af8 --- /dev/null +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -0,0 +1,27 @@ + $nameRule, + 'openingBalance' => 'numeric', + 'openingBalanceDate' => 'date', + 'accountRole' => 'in:' . $accountRoles, + 'active' => 'boolean', + 'balance_currency_id' => 'exists:transaction_currencies,id', + 'what' => 'in:' . $types + ]; + } +} \ No newline at end of file diff --git a/app/Http/Requests/BillFormRequest.php b/app/Http/Requests/BillFormRequest.php new file mode 100644 index 0000000000..2c9452cccb --- /dev/null +++ b/app/Http/Requests/BillFormRequest.php @@ -0,0 +1,55 @@ + 0) { + $nameRule .= ','.intval(Input::get('id')); + } + + $rules = [ + 'name' => $nameRule, + 'match' => 'required|between:1,255', + 'amount_min' => 'required|numeric|min:0.01', + 'amount_max' => 'required|numeric|min:0.01', + 'amount_currency_id' => 'required|exists:transaction_currencies,id', + 'date' => 'required|date', + 'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly', + 'skip' => 'required|between:0,31', + 'automatch' => 'in:1', + 'active' => 'in:1', + ]; + + return $rules; + } +} \ No newline at end of file diff --git a/app/Http/Requests/BudgetFormRequest.php b/app/Http/Requests/BudgetFormRequest.php new file mode 100644 index 0000000000..591926a969 --- /dev/null +++ b/app/Http/Requests/BudgetFormRequest.php @@ -0,0 +1,40 @@ + $nameRule, + ]; + } +} \ No newline at end of file diff --git a/app/Http/Requests/CategoryFormRequest.php b/app/Http/Requests/CategoryFormRequest.php new file mode 100644 index 0000000000..30376b4cd8 --- /dev/null +++ b/app/Http/Requests/CategoryFormRequest.php @@ -0,0 +1,40 @@ + $nameRule, + ]; + } +} \ No newline at end of file diff --git a/app/Http/Requests/CurrencyFormRequest.php b/app/Http/Requests/CurrencyFormRequest.php new file mode 100644 index 0000000000..75e0f7dd6f --- /dev/null +++ b/app/Http/Requests/CurrencyFormRequest.php @@ -0,0 +1,51 @@ + 'required|min:3|max:3|unique:transaction_currencies,code', + 'name' => 'required|max:48|min:1|unique:transaction_currencies,name', + 'symbol' => 'required|min:1|max:8|unique:transaction_currencies,symbol', + ]; + if (intval(Input::get('id')) > 0) { + $rules = [ + 'code' => 'required|min:3|max:3', + 'name' => 'required|max:48|min:1', + 'symbol' => 'required|min:1|max:8', + ]; + } + + return $rules; + } +} \ No newline at end of file diff --git a/app/Http/Requests/JournalFormRequest.php b/app/Http/Requests/JournalFormRequest.php new file mode 100644 index 0000000000..aefaefb972 --- /dev/null +++ b/app/Http/Requests/JournalFormRequest.php @@ -0,0 +1,72 @@ + 'required|min:1,max:255', + 'what' => 'required|in:withdrawal,deposit,transfer|exists:transaction_types,type', + 'amount' => 'numeric|required|min:0.01', + 'date' => 'required|date', + 'amount_currency_id' => 'required|exists:transaction_currencies,id', + + ]; + + switch ($what) { + case 'withdrawal': + $rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts'; + $rules['expense_account'] = 'between:1,255'; + $rules['category'] = 'between:1,255'; + if (intval(Input::get('budget_id')) != 0) { + $rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets'; + } + + + break; + case 'deposit': + $rules['category'] = 'between:1,255'; + $rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts'; + $rules['revenue_account'] = 'between:1,255'; + break; + case 'transfer': + $rules['account_from_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_to_id'; + $rules['account_to_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_from_id'; + $rules['category'] = 'between:1,255'; + break; + default: + die('Cannot handle ' . $what); + break; + } + + return $rules; + + + } +} \ No newline at end of file diff --git a/app/Http/Requests/PiggyBankFormRequest.php b/app/Http/Requests/PiggyBankFormRequest.php new file mode 100644 index 0000000000..74fc66efdb --- /dev/null +++ b/app/Http/Requests/PiggyBankFormRequest.php @@ -0,0 +1,61 @@ + 'required|boolean', + 'name' => $nameRule, + 'account_id' => 'required|belongsToUser:accounts', + 'targetamount' => 'required|min:0.01', + 'amount_currency_id' => 'exists:transaction_currencies,id', + 'startdate' => 'date', + 'targetdate' => $targetDateRule, + 'rep_length' => 'in:day,week,quarter,month,year', + 'rep_every' => 'integer|min:0|max:31', + 'rep_times' => 'integer|min:0|max:99', + 'reminder' => 'in:day,week,quarter,month,year', + 'reminder_skip' => 'integer|min:0|max:99', + 'remind_me' => 'boolean', + 'order' => 'integer|min:1', + + ]; + + return $rules; + } +} \ No newline at end of file diff --git a/app/Http/Requests/ProfileFormRequest.php b/app/Http/Requests/ProfileFormRequest.php new file mode 100644 index 0000000000..2b337a1037 --- /dev/null +++ b/app/Http/Requests/ProfileFormRequest.php @@ -0,0 +1,35 @@ + 'required', + 'new_password' => 'required|confirmed', + 'new_password_confirmation' => 'required', + ]; + } +} \ No newline at end of file diff --git a/app/Http/Requests/Request.php b/app/Http/Requests/Request.php new file mode 100644 index 0000000000..a5c9945e32 --- /dev/null +++ b/app/Http/Requests/Request.php @@ -0,0 +1,15 @@ +accountType->type) { default: throw new FireflyException('Cannot handle account type "' . e($account->accountType->type) . '"'); @@ -47,14 +54,14 @@ Breadcrumbs::register( } ); Breadcrumbs::register( - 'accounts.delete', function (Generator $breadcrumbs, \Account $account) { + 'accounts.delete', function (Generator $breadcrumbs, Account $account) { $breadcrumbs->parent('accounts.show', $account); $breadcrumbs->push('Delete ' . e($account->name), route('accounts.delete', $account->id)); } ); Breadcrumbs::register( - 'accounts.edit', function (Generator $breadcrumbs, \Account $account) { + 'accounts.edit', function (Generator $breadcrumbs, Account $account) { $breadcrumbs->parent('accounts.show', $account); $breadcrumbs->push('Edit ' . e($account->name), route('accounts.edit', $account->id)); } @@ -91,9 +98,9 @@ Breadcrumbs::register( 'budgets.show', function (Generator $breadcrumbs, Budget $budget, LimitRepetition $repetition = null) { $breadcrumbs->parent('budgets.index'); $breadcrumbs->push(e($budget->name), route('budgets.show', $budget->id)); - if (!is_null($repetition)) { + if (!is_null($repetition) && !is_null($repetition->id)) { $breadcrumbs->push( - DateKit::periodShow($repetition->startdate, $repetition->budgetlimit->repeat_freq), route('budgets.show', $budget->id, $repetition->id) + Navigation::periodShow($repetition->startdate, $repetition->budgetlimit->repeat_freq), route('budgets.show', $budget->id, $repetition->id) ); } } @@ -137,35 +144,35 @@ Breadcrumbs::register( // piggy banks Breadcrumbs::register( - 'piggyBanks.index', function (Generator $breadcrumbs) { + 'piggy-banks.index', function (Generator $breadcrumbs) { $breadcrumbs->parent('home'); - $breadcrumbs->push('Piggy banks', route('piggyBanks.index')); + $breadcrumbs->push('Piggy banks', route('piggy-banks.index')); } ); Breadcrumbs::register( - 'piggyBanks.create', function (Generator $breadcrumbs) { - $breadcrumbs->parent('piggyBanks.index'); - $breadcrumbs->push('Create new piggy bank', route('piggyBanks.create')); + 'piggy-banks.create', function (Generator $breadcrumbs) { + $breadcrumbs->parent('piggy-banks.index'); + $breadcrumbs->push('Create new piggy bank', route('piggy-banks.create')); } ); Breadcrumbs::register( - 'piggyBanks.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) { - $breadcrumbs->parent('piggyBanks.show', $piggyBank); - $breadcrumbs->push('Edit ' . e($piggyBank->name), route('piggyBanks.edit', $piggyBank->id)); + 'piggy-banks.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) { + $breadcrumbs->parent('piggy-banks.show', $piggyBank); + $breadcrumbs->push('Edit ' . e($piggyBank->name), route('piggy-banks.edit', $piggyBank->id)); } ); Breadcrumbs::register( - 'piggyBanks.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) { - $breadcrumbs->parent('piggyBanks.show', $piggyBank); - $breadcrumbs->push('Delete ' . e($piggyBank->name), route('piggyBanks.delete', $piggyBank->id)); + 'piggy-banks.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) { + $breadcrumbs->parent('piggy-banks.show', $piggyBank); + $breadcrumbs->push('Delete ' . e($piggyBank->name), route('piggy-banks.delete', $piggyBank->id)); } ); Breadcrumbs::register( - 'piggyBanks.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) { - $breadcrumbs->parent('piggyBanks.index'); - $breadcrumbs->push(e($piggyBank->name), route('piggyBanks.show', $piggyBank->id)); + 'piggy-banks.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) { + $breadcrumbs->parent('piggy-banks.index'); + $breadcrumbs->push(e($piggyBank->name), route('piggy-banks.show', $piggyBank->id)); } ); @@ -342,7 +349,7 @@ Breadcrumbs::register( Breadcrumbs::register( 'transactions.create', function (Generator $breadcrumbs, $what) { $breadcrumbs->parent('transactions.index', $what); - $breadcrumbs->push('Create new ' .e($what), route('transactions.create', $what)); + $breadcrumbs->push('Create new ' . e($what), route('transactions.create', $what)); } ); diff --git a/app/routes.php b/app/Http/routes.php similarity index 62% rename from app/routes.php rename to app/Http/routes.php index 1f534f5811..84ee9dd19c 100644 --- a/app/routes.php +++ b/app/Http/routes.php @@ -1,12 +1,20 @@ where('account_types.editable', 1) ->where('accounts.id', $value) ->where('user_id', Auth::user()->id) @@ -20,34 +28,13 @@ Route::bind( ); Route::bind( - 'accountname', function ($value, $route) { + 'repeatedExpense', function ($value, $route) { if (Auth::check()) { - return Account:: - leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')->where('account_types.editable', 1)->where('name', $value)->where( - 'user_id', Auth::user()->id - )->first(); - } - - return null; -} -); - - -Route::bind( - 'bill', function ($value, $route) { - if (Auth::check()) { - return Bill:: - where('id', $value)->where('user_id', Auth::user()->id)->first(); - } - - return null; -} -); -Route::bind( - 'budget', function ($value, $route) { - if (Auth::check()) { - return Budget:: - where('id', $value)->where('user_id', Auth::user()->id)->first(); + return PiggyBank:: + where('piggy_banks.id', $value) + ->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') + ->where('accounts.user_id', Auth::user()->id) + ->where('repeats', 1)->first(['piggy_banks.*']); } return null; @@ -55,31 +42,9 @@ Route::bind( ); Route::bind( - 'component', function ($value, $route) { + 'tjSecond', function ($value, $route) { if (Auth::check()) { - return Component:: - where('id', $value)->where('user_id', Auth::user()->id)->first(); - } - - return null; -} -); - -Route::bind( - 'reminder', function ($value, $route) { - if (Auth::check()) { - return Reminder:: - where('id', $value)->where('user_id', Auth::user()->id)->first(); - } - - return null; -} -); - -Route::bind( - 'category', function ($value, $route) { - if (Auth::check()) { - return Category:: + return TransactionJournal:: where('id', $value)->where('user_id', Auth::user()->id)->first(); } @@ -97,11 +62,17 @@ Route::bind( return null; } ); + Route::bind( - 'tjSecond', function ($value, $route) { + 'currency', function ($value, $route) { + return TransactionCurrency::find($value); +} +); + +Route::bind( + 'bill', function ($value, $route) { if (Auth::check()) { - return TransactionJournal:: - where('id', $value)->where('user_id', Auth::user()->id)->first(); + return Bill::where('id', $value)->where('user_id', Auth::user()->id)->first(); } return null; @@ -109,8 +80,12 @@ Route::bind( ); Route::bind( - 'currency', function ($value, $route) { - return TransactionCurrency::find($value); + 'budget', function ($value, $route) { + if (Auth::check()) { + return Budget::where('id', $value)->where('user_id', Auth::user()->id)->first(); + } + + return null; } ); @@ -143,132 +118,56 @@ Route::bind( ); Route::bind( - 'repeatedExpense', function ($value, $route) { + 'category', function ($value, $route) { if (Auth::check()) { - return PiggyBank:: - where('piggy_banks.id', $value) - ->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') - ->where('accounts.user_id', Auth::user()->id) - ->where('repeats', 1)->first(['piggy_banks.*']); + return Category::where('id', $value)->where('user_id', Auth::user()->id)->first(); } return null; } ); -Route::bind( - 'repeated', function ($value, $route) { - if (Auth::check()) { - return PiggyBank:: - where('piggy_banks.id', $value) - ->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') - ->where('accounts.user_id', Auth::user()->id) - ->where('repeats', 1)->first(['piggy_banks.*']); - } - return null; -} +/** + * Auth\AuthController + */ +Route::get('/register', ['uses' => 'Auth\AuthController@getRegister', 'as' => 'register']); + +Route::controllers( + [ + 'auth' => 'Auth\AuthController', + 'password' => 'Auth\PasswordController', + ] ); -// protected routes: + +/** + * Home Controller + */ Route::group( - ['before' => 'auth'], function () { - - - // some date routes used for (well duh) date-based navigation. + ['middleware' => ['auth', 'range']], function () { + Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']); + Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']); Route::get('/prev', ['uses' => 'HomeController@sessionPrev', 'as' => 'sessionPrev']); Route::get('/next', ['uses' => 'HomeController@sessionNext', 'as' => 'sessionNext']); Route::get('/jump/{range}', ['uses' => 'HomeController@rangeJump', 'as' => 'rangeJump']); - - - // account controller: + Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']); + /** + * Account Controller + */ Route::get('/accounts/{what}', ['uses' => 'AccountController@index', 'as' => 'accounts.index'])->where('what', 'revenue|asset|expense'); Route::get('/accounts/create/{what}', ['uses' => 'AccountController@create', 'as' => 'accounts.create'])->where('what', 'revenue|asset|expense'); Route::get('/accounts/edit/{account}', ['uses' => 'AccountController@edit', 'as' => 'accounts.edit']); Route::get('/accounts/delete/{account}', ['uses' => 'AccountController@delete', 'as' => 'accounts.delete']); Route::get('/accounts/show/{account}/{view?}', ['uses' => 'AccountController@show', 'as' => 'accounts.show']); + Route::post('/accounts/store', ['uses' => 'AccountController@store', 'as' => 'accounts.store']); + Route::post('/accounts/update/{account}', ['uses' => 'AccountController@update', 'as' => 'accounts.update']); + Route::post('/accounts/destroy/{account}', ['uses' => 'AccountController@destroy', 'as' => 'accounts.destroy']); - // budget controller: - Route::get('/budgets', ['uses' => 'BudgetController@index', 'as' => 'budgets.index']); - Route::get('/budgets/income', ['uses' => 'BudgetController@updateIncome', 'as' => 'budgets.income']); # extra. - Route::get('/budgets/create', ['uses' => 'BudgetController@create', 'as' => 'budgets.create']); - Route::get('/budgets/edit/{budget}', ['uses' => 'BudgetController@edit', 'as' => 'budgets.edit']); - Route::get('/budgets/delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'budgets.delete']); - Route::get('/budgets/show/{budget}/{limitrepetition?}', ['uses' => 'BudgetController@show', 'as' => 'budgets.show']); - Route::get('/budgets/list/noBudget', ['uses' => 'BudgetController@noBudget', 'as' => 'budgets.noBudget']); - - // category controller: - Route::get('/categories', ['uses' => 'CategoryController@index', 'as' => 'categories.index']); - Route::get('/categories/create', ['uses' => 'CategoryController@create', 'as' => 'categories.create']); - Route::get('/categories/edit/{category}', ['uses' => 'CategoryController@edit', 'as' => 'categories.edit']); - Route::get('/categories/delete/{category}', ['uses' => 'CategoryController@delete', 'as' => 'categories.delete']); - Route::get('/categories/show/{category}', ['uses' => 'CategoryController@show', 'as' => 'categories.show']); - Route::get('/categories/list/noCategory', ['uses' => 'CategoryController@noCategory', 'as' => 'categories.noCategory']); - - // currency controller - Route::get('/currency', ['uses' => 'CurrencyController@index', 'as' => 'currency.index']); - Route::get('/currency/create', ['uses' => 'CurrencyController@create', 'as' => 'currency.create']); - Route::get('/currency/edit/{currency}', ['uses' => 'CurrencyController@edit', 'as' => 'currency.edit']); - Route::get('/currency/delete/{currency}', ['uses' => 'CurrencyController@delete', 'as' => 'currency.delete']); - Route::get('/currency/default/{currency}', ['uses' => 'CurrencyController@defaultCurrency', 'as' => 'currency.default']); - - // google chart controller - Route::get('/chart/home/account', ['uses' => 'GoogleChartController@allAccountsBalanceChart']); - Route::get('/chart/home/budgets', ['uses' => 'GoogleChartController@allBudgetsHomeChart']); - Route::get('/chart/home/categories', ['uses' => 'GoogleChartController@allCategoriesHomeChart']); - Route::get('/chart/home/bills', ['uses' => 'GoogleChartController@billsOverview']); - Route::get('/chart/account/{account}/{view?}', ['uses' => 'GoogleChartController@accountBalanceChart']); - Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']); - Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']); - Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']); - - Route::get('/chart/piggy_history/{piggyBank}', ['uses' => 'GoogleChartController@piggyBankHistory']); - - // google chart for components (categories + budgets combined) - Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']); - Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending']); - Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']); - Route::get('/chart/category/{category}/spending/{year}', ['uses' => 'GoogleChartController@categoriesAndSpending']); - - // help controller - Route::get('/help/{route}', ['uses' => 'HelpController@show', 'as' => 'help.show']); - - // home controller - Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']); - Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']); # even though nothing is cached. - - // JSON controller - Route::get('/json/expense-accounts', ['uses' => 'JsonController@expenseAccounts', 'as' => 'json.expense-accounts']); - Route::get('/json/revenue-accounts', ['uses' => 'JsonController@revenueAccounts', 'as' => 'json.revenue-accounts']); - Route::get('/json/categories', ['uses' => 'JsonController@categories', 'as' => 'json.categories']); - - - // piggy bank controller - Route::get('/piggy_banks', ['uses' => 'PiggyBankController@index', 'as' => 'piggy_banks.index']); - Route::get('/piggy_banks/add/{piggyBank}', ['uses' => 'PiggyBankController@add']); # add money - Route::get('/piggy_banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove']); #remove money - - Route::get('/piggy_banks/create', ['uses' => 'PiggyBankController@create', 'as' => 'piggy_banks.create']); - Route::get('/piggy_banks/edit/{piggyBank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy_banks.edit']); - Route::get('/piggy_banks/delete/{piggyBank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy_banks.delete']); - Route::get('/piggy_banks/show/{piggyBank}', ['uses' => 'PiggyBankController@show', 'as' => 'piggy_banks.show']); - - // preferences controller - Route::get('/preferences', ['uses' => 'PreferencesController@index', 'as' => 'preferences']); - - //profile controller - Route::get('/profile', ['uses' => 'ProfileController@index', 'as' => 'profile']); - Route::get('/profile/change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']); - - // related controller: - Route::get('/related/alreadyRelated/{tj}', ['uses' => 'RelatedController@alreadyRelated', 'as' => 'related.alreadyRelated']); - Route::post('/related/relate/{tj}/{tjSecond}', ['uses' => 'RelatedController@relate', 'as' => 'related.relate']); - Route::get('/related/removeRelation/{tj}/{tjSecond}', ['uses' => 'RelatedController@removeRelation', 'as' => 'related.removeRelation']); - Route::get('/related/related/{tj}', ['uses' => 'RelatedController@related', 'as' => 'related.related']); - Route::post('/related/search/{tj}', ['uses' => 'RelatedController@search', 'as' => 'related.search']); - - // bills controller + /** + * Bills Controller + */ Route::get('/bills', ['uses' => 'BillController@index', 'as' => 'bills.index']); Route::get('/bills/rescan/{bill}', ['uses' => 'BillController@rescan', 'as' => 'bills.rescan']); # rescan for matching. Route::get('/bills/create', ['uses' => 'BillController@create', 'as' => 'bills.create']); @@ -276,29 +175,148 @@ Route::group( Route::get('/bills/delete/{bill}', ['uses' => 'BillController@delete', 'as' => 'bills.delete']); Route::get('/bills/show/{bill}', ['uses' => 'BillController@show', 'as' => 'bills.show']); - // repeated expenses controller: - Route::get('/repeatedexpenses', ['uses' => 'RepeatedExpenseController@index', 'as' => 'repeated.index']); - Route::get('/repeatedexpenses/create', ['uses' => 'RepeatedExpenseController@create', 'as' => 'repeated.create']); - Route::get('/repeatedexpenses/edit/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@edit', 'as' => 'repeated.edit']); - Route::get('/repeatedexpenses/delete/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@delete', 'as' => 'repeated.delete']); - Route::get('/repeatedexpenses/show/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@show', 'as' => 'repeated.show']); + Route::post('/bills/store', ['uses' => 'BillController@store', 'as' => 'bills.store']); + Route::post('/bills/update/{bill}', ['uses' => 'BillController@update', 'as' => 'bills.update']); + Route::post('/bills/destroy/{bill}', ['uses' => 'BillController@destroy', 'as' => 'bills.destroy']); - // report controller: + /** + * Budget Controller + */ + Route::get('/budgets', ['uses' => 'BudgetController@index', 'as' => 'budgets.index']); + Route::get('/budgets/income', ['uses' => 'BudgetController@updateIncome', 'as' => 'budgets.income']); # extra. + Route::get('/budgets/create', ['uses' => 'BudgetController@create', 'as' => 'budgets.create']); + Route::get('/budgets/edit/{budget}', ['uses' => 'BudgetController@edit', 'as' => 'budgets.edit']); + Route::get('/budgets/delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'budgets.delete']); + Route::get('/budgets/show/{budget}/{limitrepetition?}', ['uses' => 'BudgetController@show', 'as' => 'budgets.show']); + Route::get('/budgets/list/noBudget', ['uses' => 'BudgetController@noBudget', 'as' => 'budgets.noBudget']); + Route::post('/budgets/income', ['uses' => 'BudgetController@postUpdateIncome', 'as' => 'budgets.postIncome']); + Route::post('/budgets/store', ['uses' => 'BudgetController@store', 'as' => 'budgets.store']); + Route::post('/budgets/update/{budget}', ['uses' => 'BudgetController@update', 'as' => 'budgets.update']); + Route::post('/budgets/destroy/{budget}', ['uses' => 'BudgetController@destroy', 'as' => 'budgets.destroy']); + Route::post('budgets/amount/{budget}', ['uses' => 'BudgetController@amount']); + + /** + * Category Controller + */ + Route::get('/categories', ['uses' => 'CategoryController@index', 'as' => 'categories.index']); + Route::get('/categories/create', ['uses' => 'CategoryController@create', 'as' => 'categories.create']); + Route::get('/categories/edit/{category}', ['uses' => 'CategoryController@edit', 'as' => 'categories.edit']); + Route::get('/categories/delete/{category}', ['uses' => 'CategoryController@delete', 'as' => 'categories.delete']); + Route::get('/categories/show/{category}', ['uses' => 'CategoryController@show', 'as' => 'categories.show']); + Route::get('/categories/list/noCategory', ['uses' => 'CategoryController@noCategory', 'as' => 'categories.noCategory']); + Route::post('/categories/store', ['uses' => 'CategoryController@store', 'as' => 'categories.store']); + Route::post('/categories/update/{category}', ['uses' => 'CategoryController@update', 'as' => 'categories.update']); + Route::post('/categories/destroy/{category}', ['uses' => 'CategoryController@destroy', 'as' => 'categories.destroy']); + + /** + * Currency Controller + */ + Route::get('/currency', ['uses' => 'CurrencyController@index', 'as' => 'currency.index']); + Route::get('/currency/create', ['uses' => 'CurrencyController@create', 'as' => 'currency.create']); + Route::get('/currency/edit/{currency}', ['uses' => 'CurrencyController@edit', 'as' => 'currency.edit']); + Route::get('/currency/delete/{currency}', ['uses' => 'CurrencyController@delete', 'as' => 'currency.delete']); + Route::get('/currency/default/{currency}', ['uses' => 'CurrencyController@defaultCurrency', 'as' => 'currency.default']); + Route::post('/currency/store', ['uses' => 'CurrencyController@store', 'as' => 'currency.store']); + Route::post('/currency/update/{currency}', ['uses' => 'CurrencyController@update', 'as' => 'currency.update']); + Route::post('/currency/destroy/{currency}', ['uses' => 'CurrencyController@destroy', 'as' => 'currency.destroy']); + + + /** + * Google Chart Controller + */ + Route::get('/chart/home/account', ['uses' => 'GoogleChartController@allAccountsBalanceChart']); + Route::get('/chart/home/budgets', ['uses' => 'GoogleChartController@allBudgetsHomeChart']); + Route::get('/chart/home/categories', ['uses' => 'GoogleChartController@allCategoriesHomeChart']); + Route::get('/chart/home/bills', ['uses' => 'GoogleChartController@billsOverview']); + Route::get('/chart/account/{account}/{view?}', ['uses' => 'GoogleChartController@accountBalanceChart']); + Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']); + Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending']); + Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']); + Route::get('/chart/category/{category}/spending/{year}', ['uses' => 'GoogleChartController@categoriesAndSpending']); + Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']); + Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']); + Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']); + Route::get('/chart/piggy-history/{piggyBank}', ['uses' => 'GoogleChartController@piggyBankHistory']); + + /** + * Help Controller + */ + Route::get('/help/{route}', ['uses' => 'HelpController@show', 'as' => 'help.show']); + + /** + * JSON Controller + */ + Route::get('/json/expense-accounts', ['uses' => 'JsonController@expenseAccounts', 'as' => 'json.expense-accounts']); + Route::get('/json/revenue-accounts', ['uses' => 'JsonController@revenueAccounts', 'as' => 'json.revenue-accounts']); + Route::get('/json/categories', ['uses' => 'JsonController@categories', 'as' => 'json.categories']); + + + /** + * Piggy Bank Controller + */ + Route::get('/piggy-banks', ['uses' => 'PiggyBankController@index', 'as' => 'piggy-banks.index']); + Route::get('/piggy-banks/add/{piggyBank}', ['uses' => 'PiggyBankController@add']); # add money + Route::get('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove']); #remove money + Route::get('/piggy-banks/create', ['uses' => 'PiggyBankController@create', 'as' => 'piggy-banks.create']); + Route::get('/piggy-banks/edit/{piggyBank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy-banks.edit']); + Route::get('/piggy-banks/delete/{piggyBank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy-banks.delete']); + Route::get('/piggy-banks/show/{piggyBank}', ['uses' => 'PiggyBankController@show', 'as' => 'piggy-banks.show']); + Route::post('/piggy-banks/store', ['uses' => 'PiggyBankController@store', 'as' => 'piggy-banks.store']); + Route::post('/piggy-banks/update/{piggyBank}', ['uses' => 'PiggyBankController@update', 'as' => 'piggy-banks.update']); + Route::post('/piggy-banks/destroy/{piggyBank}', ['uses' => 'PiggyBankController@destroy', 'as' => 'piggy-banks.destroy']); + Route::post('/piggy-banks/add/{piggyBank}', ['uses' => 'PiggyBankController@postAdd', 'as' => 'piggy-banks.add']); # add money + Route::post('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@postRemove', 'as' => 'piggy-banks.remove']); # remove money. + + /** + * Preferences Controller + */ + Route::get('/preferences', ['uses' => 'PreferencesController@index', 'as' => 'preferences']); + Route::post('/preferences', ['uses' => 'PreferencesController@postIndex']); + + /** + * Profile Controller + */ + Route::get('/profile', ['uses' => 'ProfileController@index', 'as' => 'profile']); + Route::get('/profile/change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']); + Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword','as' => 'change-password-post']); + + /** + * Related transactions controller + */ + Route::get('/related/alreadyRelated/{tj}', ['uses' => 'RelatedController@alreadyRelated', 'as' => 'related.alreadyRelated']); + Route::post('/related/relate/{tj}/{tjSecond}', ['uses' => 'RelatedController@relate', 'as' => 'related.relate']); + Route::post('/related/removeRelation/{tj}/{tjSecond}', ['uses' => 'RelatedController@removeRelation', 'as' => 'related.removeRelation']); + Route::get('/related/related/{tj}', ['uses' => 'RelatedController@related', 'as' => 'related.related']); + Route::post('/related/search/{tj}', ['uses' => 'RelatedController@search', 'as' => 'related.search']); + + /** + * Repeated Expenses Controller + */ + Route::get('/repeated-expenses', ['uses' => 'RepeatedExpenseController@index', 'as' => 'repeated.index']); + Route::get('/repeated-expenses/create', ['uses' => 'RepeatedExpenseController@create', 'as' => 'repeated.create']); + Route::get('/repeated-expenses/edit/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@edit', 'as' => 'repeated.edit']); + Route::get('/repeated-expenses/delete/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@delete', 'as' => 'repeated.delete']); + Route::get('/repeated-expenses/show/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@show', 'as' => 'repeated.show']); + Route::post('/repeated-expense/store', ['uses' => 'RepeatedExpenseController@store', 'as' => 'repeated.store']); + Route::post('/repeated-expense/update/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@update', 'as' => 'repeated.update']); + Route::post('/repeated-expense/destroy/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@destroy', 'as' => 'repeated.destroy']); + + /** + * Report Controller + */ Route::get('/reports', ['uses' => 'ReportController@index', 'as' => 'reports.index']); Route::get('/reports/{year}', ['uses' => 'ReportController@year', 'as' => 'reports.year']); Route::get('/reports/{year}/{month}', ['uses' => 'ReportController@month', 'as' => 'reports.month']); Route::get('/reports/budget/{year}/{month}', ['uses' => 'ReportController@budget', 'as' => 'reports.budget']); - // reminder controller - Route::get('/reminders/{reminder}', ['uses' => 'ReminderController@show', 'as' => 'reminders.show']); - Route::get('/reminders/{reminder}/dismiss', ['uses' => 'ReminderController@dismiss', 'as' => 'reminders.dismiss']); - Route::get('/reminders/{reminder}/notNow', ['uses' => 'ReminderController@notNow', 'as' => 'reminders.notNow']); - Route::get('/reminders/{reminder}/act', ['uses' => 'ReminderController@act', 'as' => 'reminders.act']); - - // search controller: + /** + * Search Controller + */ Route::get('/search', ['uses' => 'SearchController@index', 'as' => 'search']); - // transaction controller: + /** + * Transaction Controller + */ Route::get('/transactions/{what}', ['uses' => 'TransactionController@index', 'as' => 'transactions.index'])->where( ['what' => 'expenses|revenue|withdrawal|deposit|transfer|transfers'] ); @@ -308,68 +326,6 @@ Route::group( Route::get('/transaction/edit/{tj}', ['uses' => 'TransactionController@edit', 'as' => 'transactions.edit']); Route::get('/transaction/delete/{tj}', ['uses' => 'TransactionController@delete', 'as' => 'transactions.delete']); Route::get('/transaction/show/{tj}', ['uses' => 'TransactionController@show', 'as' => 'transactions.show']); - Route::get('/transaction/relate/{tj}', ['uses' => 'TransactionController@relate', 'as' => 'transactions.relate']); - Route::post('/transactions/relatedSearch/{tj}', ['uses' => 'TransactionController@relatedSearch', 'as' => 'transactions.relatedSearch']); - Route::post('/transactions/alreadyRelated/{tj}', ['uses' => 'TransactionController@alreadyRelated', 'as' => 'transactions.alreadyRelated']); - Route::post('/transactions/doRelate', ['uses' => 'TransactionController@doRelate', 'as' => 'transactions.doRelate']); - Route::any('/transactions/unrelate/{tj}', ['uses' => 'TransactionController@unrelate', 'as' => 'transactions.unrelate']); - - // user controller - Route::get('/logout', ['uses' => 'UserController@logout', 'as' => 'logout']); - - Route::post('budgets/amount/{budget}', ['uses' => 'BudgetController@amount']); - - -} -); - -// protected + csrf routes (POST) -Route::group( - ['before' => 'csrf|auth'], function () { - // account controller: - Route::post('/accounts/store', ['uses' => 'AccountController@store', 'as' => 'accounts.store']); - Route::post('/accounts/update/{account}', ['uses' => 'AccountController@update', 'as' => 'accounts.update']); - Route::post('/accounts/destroy/{account}', ['uses' => 'AccountController@destroy', 'as' => 'accounts.destroy']); - - // budget controller: - Route::post('/budgets/income', ['uses' => 'BudgetController@postUpdateIncome', 'as' => 'budgets.postIncome']); - Route::post('/budgets/store', ['uses' => 'BudgetController@store', 'as' => 'budgets.store']); - Route::post('/budgets/update/{budget}', ['uses' => 'BudgetController@update', 'as' => 'budgets.update']); - Route::post('/budgets/destroy/{budget}', ['uses' => 'BudgetController@destroy', 'as' => 'budgets.destroy']); - - // category controller - Route::post('/categories/store', ['uses' => 'CategoryController@store', 'as' => 'categories.store']); - Route::post('/categories/update/{category}', ['uses' => 'CategoryController@update', 'as' => 'categories.update']); - Route::post('/categories/destroy/{category}', ['uses' => 'CategoryController@destroy', 'as' => 'categories.destroy']); - - // currency controller - Route::post('/currency/store', ['uses' => 'CurrencyController@store', 'as' => 'currency.store']); - Route::post('/currency/update/{currency}', ['uses' => 'CurrencyController@update', 'as' => 'currency.update']); - Route::post('/currency/destroy/{currency}', ['uses' => 'CurrencyController@destroy', 'as' => 'currency.destroy']); - - // piggy bank controller - Route::post('/piggy_banks/store', ['uses' => 'PiggyBankController@store', 'as' => 'piggy_banks.store']); - Route::post('/piggy_banks/update/{piggyBank}', ['uses' => 'PiggyBankController@update', 'as' => 'piggy_banks.update']); - Route::post('/piggy_banks/destroy/{piggyBank}', ['uses' => 'PiggyBankController@destroy', 'as' => 'piggy_banks.destroy']); - Route::post('/piggy_banks/add/{piggyBank}', ['uses' => 'PiggyBankController@postAdd', 'as' => 'piggy_banks.add']); # add money - Route::post('/piggy_banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@postRemove', 'as' => 'piggy_banks.remove']); # remove money. - - // repeated expense controller - Route::post('/repeatedexpense/store', ['uses' => 'RepeatedExpenseController@store', 'as' => 'repeated.store']); - Route::post('/repeatedexpense/update/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@update', 'as' => 'repeated.update']); - Route::post('/repeatedexpense/destroy/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@destroy', 'as' => 'repeated.destroy']); - - // preferences controller - Route::post('/preferences', ['uses' => 'PreferencesController@postIndex']); - - // profile controller - Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword']); - - // bills controller - Route::post('/bills/store', ['uses' => 'BillController@store', 'as' => 'bills.store']); - Route::post('/bills/update/{bill}', ['uses' => 'BillController@update', 'as' => 'bills.update']); - Route::post('/bills/destroy/{bill}', ['uses' => 'BillController@destroy', 'as' => 'bills.destroy']); - // transaction controller: Route::post('/transactions/store/{what}', ['uses' => 'TransactionController@store', 'as' => 'transactions.store'])->where( ['what' => 'expenses|revenue|withdrawal|deposit|transfer|transfers'] @@ -377,32 +333,12 @@ Route::group( Route::post('/transaction/update/{tj}', ['uses' => 'TransactionController@update', 'as' => 'transactions.update']); Route::post('/transaction/destroy/{tj}', ['uses' => 'TransactionController@destroy', 'as' => 'transactions.destroy']); -} -); - -// guest routes: -Route::group( - ['before' => 'guest'], function () { - // user controller - Route::get('/login', ['uses' => 'UserController@login', 'as' => 'login']); - Route::get('/register', ['uses' => 'UserController@register', 'as' => 'register', 'before' => 'allow-register']); - Route::get('/reset/{reset}', ['uses' => 'UserController@reset', 'as' => 'reset']); - Route::get('/remindMe', ['uses' => 'UserController@remindMe', 'as' => 'remindMe']); - - Route::get('/oauth2callback', ['uses' => 'HomeController@marauder', 'as' => 'marauder']); + /** + * Auth\Auth Controller + */ + Route::get('/logout', ['uses' => 'Auth\AuthController@getLogout', 'as' => 'logout']); } ); - -// guest + csrf routes: -Route::group( - ['before' => 'csrf|guest'], function () { - - // user controller - Route::post('/login', ['uses' => 'UserController@postLogin', 'as' => 'login.post']); - Route::post('/register', ['uses' => 'UserController@postRegister', 'as' => 'register.post', 'before' => 'allow-register']); - Route::post('/remindMe', ['uses' => 'UserController@postRemindMe', 'as' => 'remindMe.post']); -} -); diff --git a/app/models/AccountMeta.php b/app/Models/AccountMeta.php similarity index 50% rename from app/models/AccountMeta.php rename to app/Models/AccountMeta.php index 5a481a2c90..1aba876ce2 100644 --- a/app/models/AccountMeta.php +++ b/app/Models/AccountMeta.php @@ -1,35 +1,35 @@ - 'numeric|required|exists:accounts,id', - 'name' => 'required|between:1,250', + protected $fillable = ['account_id', 'name', 'data']; + protected $rules + = [ + 'account_id' => 'required|exists:accounts,id', + 'name' => 'required|between:1,100', 'data' => 'required' ]; - /** - * @var array - */ - protected $fillable = ['account_id', 'name', 'date']; - protected $table = 'account_meta'; + protected $table = 'account_meta'; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function account() { - return $this->belongsTo('Account'); + return $this->belongsTo('FireflyIII\Models\Account'); } + /** * @param $value * @@ -40,6 +40,14 @@ class AccountMeta extends Eloquent return json_decode($value); } + /** + * @return array + */ + public function getDates() + { + return ['created_at', 'updated_at']; + } + /** * @param $value */ @@ -48,4 +56,4 @@ class AccountMeta extends Eloquent $this->attributes['data'] = json_encode($value); } -} +} diff --git a/app/models/Piggybank.php b/app/Models/PiggyBank.php similarity index 56% rename from app/models/Piggybank.php rename to app/Models/PiggyBank.php index 49e7563445..305a8eb076 100644 --- a/app/models/Piggybank.php +++ b/app/Models/PiggyBank.php @@ -1,46 +1,33 @@ - 'required|exists:accounts,id', // link to Account - 'name' => 'required|between:1,255', // name - 'targetamount' => 'required|min:0.01|numeric', // amount you want to save - 'startdate' => 'date', // when you started - 'targetdate' => 'date', // when its due - 'repeats' => 'required|boolean', // does it repeat? - 'rep_length' => 'in:day,week,month,quarter,year', // how long is the period? - 'rep_every' => 'required|min:1|max:100', // how often does it repeat? every 3 years. - 'rep_times' => 'min:1|max:100', // how many times do you want to save this amount? eg. 3 times - 'reminder' => 'in:day,week,quarter,month,year', // want a reminder to put money in this? - 'reminder_skip' => 'required|min:0|max:100', // every week? every 2 months? - 'remind_me' => 'required|boolean', 'order' => 'required:min:1', // not yet used. - ]; + use SoftDeletes; + + protected $fillable = ['repeats', 'name', 'account_id','rep_every', 'rep_times', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder',]; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function account() { - return $this->belongsTo('Account'); + return $this->belongsTo('FireflyIII\Models\Account'); } /** * Grabs the PiggyBankRepetition that's currently relevant / active * - * @returns \PiggyBankRepetition + * @returns PiggyBankRepetition */ public function currentRelevantRep() { @@ -53,7 +40,7 @@ class PiggyBank extends Eloquent return $rep; } else { - $query = $this->piggyBankRepetitions()->where( + $query = $this->piggyBankRepetitions()->where( function (EloquentBuilder $q) { $q->where( @@ -83,9 +70,8 @@ class PiggyBank extends Eloquent } )->orderBy('startdate', 'ASC'); - $result = $query->first(['piggy_bank_repetitions.*']); + $result = $query->first(['piggy_bank_repetitions.*']); $this->currentRep = $result; - \Log::debug('Found relevant rep in currentRelevantRep(): ' . $result->id); return $result; } @@ -98,7 +84,7 @@ class PiggyBank extends Eloquent */ public function piggyBankRepetitions() { - return $this->hasMany('PiggyBankRepetition'); + return $this->hasMany('FireflyIII\Models\PiggyBankRepetition'); } /** @@ -106,7 +92,7 @@ class PiggyBank extends Eloquent */ public function getDates() { - return ['created_at', 'updated_at', 'targetdate', 'startdate']; + return ['created_at', 'updated_at', 'deleted_at', 'startdate', 'targetdate']; } /** @@ -114,7 +100,7 @@ class PiggyBank extends Eloquent */ public function piggyBankEvents() { - return $this->hasMany('PiggyBankEvent'); + return $this->hasMany('FireflyIII\Models\PiggyBankEvent'); } /** @@ -122,6 +108,6 @@ class PiggyBank extends Eloquent */ public function reminders() { - return $this->morphMany('Reminder', 'remindersable'); + return $this->morphMany('FireflyIII\Models\Reminder', 'remindersable'); } } diff --git a/app/models/Preference.php b/app/Models/Preference.php similarity index 53% rename from app/models/Preference.php rename to app/Models/Preference.php index b3e12a7ec6..b0c1cb7d03 100644 --- a/app/models/Preference.php +++ b/app/Models/Preference.php @@ -1,16 +1,16 @@ - 'required|exists:users,id', 'name' => 'required|between:1,255', 'data' => 'required']; + + protected $fillable = ['user_id', 'data', 'name']; /** * @param $value @@ -22,6 +22,14 @@ class Preference extends Eloquent return json_decode($value); } + /** + * @return array + */ + public function getDates() + { + return ['created_at', 'updated_at']; + } + /** * @param $value */ @@ -35,7 +43,7 @@ class Preference extends Eloquent */ public function user() { - return $this->belongsTo('User'); + return $this->belongsTo('FireflyIII\User'); } -} +} diff --git a/app/models/TransactionJournal.php b/app/Models/TransactionJournal.php similarity index 64% rename from app/models/TransactionJournal.php rename to app/Models/TransactionJournal.php index da22e42fe9..2745f8379f 100644 --- a/app/models/TransactionJournal.php +++ b/app/Models/TransactionJournal.php @@ -1,35 +1,42 @@ - 'required|exists:transaction_types,id', - 'transaction_currency_id' => 'required|exists:transaction_currencies,id', - 'description' => 'required|between:1,1024', - 'date' => 'required|date', - 'completed' => 'required|between:0,1']; + = [ + 'user_id' => 'required|exists:users,id', + 'transaction_type_id' => 'required|exists:transaction_types,id', + 'bill_id' => 'exists:bills,id', + 'transaction_currency_id' => 'required|exists:transaction_currencies,id', + 'description' => 'required|between:1,1024', + 'completed' => 'required|boolean', + 'date' => 'required|date', + 'encrypted' => 'required|boolean' + ]; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function bill() { - return $this->belongsTo('Bill'); + return $this->belongsTo('FireflyIII\Models\Bill'); } /** @@ -37,9 +44,7 @@ class TransactionJournal extends Eloquent */ public function budgets() { - return $this->belongsToMany( - 'Budget' - ); + return $this->belongsToMany('FireflyIII\Models\Budget'); } /** @@ -47,31 +52,7 @@ class TransactionJournal extends Eloquent */ public function categories() { - return $this->belongsToMany( - 'Category' - ); - } - - /** - * @param Account $account - * - * @return float - */ - public function getAmount(\Account $account = null) - { - $amount = 0; - foreach ($this->transactions as $t) { - if (!is_null($account) && $account->id == $t->account_id) { - $amount = floatval($t->amount); - break; - } - if (floatval($t->amount) > 0) { - $amount = floatval($t->amount); - break; - } - } - - return $amount; + return $this->belongsToMany('FireflyIII\Models\Category'); } /** @@ -79,7 +60,7 @@ class TransactionJournal extends Eloquent */ public function getDates() { - return ['created_at', 'updated_at', 'date']; + return ['created_at', 'updated_at', 'date', 'deleted_at']; } /** @@ -92,6 +73,7 @@ class TransactionJournal extends Eloquent if ($this->encrypted) { return Crypt::decrypt($value); } + // @codeCoverageIgnoreStart return $value; // @codeCoverageIgnoreEnd @@ -102,14 +84,14 @@ class TransactionJournal extends Eloquent */ public function piggyBankEvents() { - return $this->hasMany('PiggyBankEvent'); + return $this->hasMany('FireflyIII\Models\PiggyBankEvent'); } /** * @param EloquentBuilder $query * @param Account $account */ - public function scopeAccountIs(EloquentBuilder $query, \Account $account) + public function scopeAccountIs(EloquentBuilder $query, Account $account) { if (!isset($this->joinedTransactions)) { $query->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id'); @@ -156,22 +138,6 @@ class TransactionJournal extends Eloquent $query->where('transactions.amount', '<=', $amount); } - /** - * @param EloquentBuilder $query - * @param $amount - */ - public function scopeMoreThan(EloquentBuilder $query, $amount) - { - if (is_null($this->joinedTransactions)) { - $query->leftJoin( - 'transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id' - ); - $this->joinedTransactions = true; - } - - $query->where('transactions.amount', '>=', $amount); - } - /** * @param EloquentBuilder $query * @param Carbon $date @@ -209,7 +175,7 @@ class TransactionJournal extends Eloquent $query->with( ['transactions' => function (HasMany $q) { $q->orderBy('amount', 'ASC'); - }, 'transactiontype', 'budgets', 'categories', 'transactions.account.accounttype', 'bill', 'budgets', 'categories'] + }, 'transactiontype', 'transactioncurrency', 'budgets', 'categories', 'transactions.account.accounttype', 'bill', 'budgets', 'categories'] ); } @@ -218,7 +184,7 @@ class TransactionJournal extends Eloquent */ public function setDescriptionAttribute($value) { - $this->attributes['description'] = Crypt::encrypt($value); + $this->attributes['description'] = \Crypt::encrypt($value); $this->attributes['encrypted'] = true; } @@ -227,7 +193,7 @@ class TransactionJournal extends Eloquent */ public function transactionCurrency() { - return $this->belongsTo('TransactionCurrency'); + return $this->belongsTo('FireflyIII\Models\TransactionCurrency'); } /** @@ -235,7 +201,7 @@ class TransactionJournal extends Eloquent */ public function transactionType() { - return $this->belongsTo('TransactionType'); + return $this->belongsTo('FireflyIII\Models\TransactionType'); } /** @@ -243,7 +209,7 @@ class TransactionJournal extends Eloquent */ public function transactiongroups() { - return $this->belongsToMany('TransactionGroup'); + return $this->belongsToMany('FireflyIII\Models\TransactionGroup'); } /** @@ -251,17 +217,15 @@ class TransactionJournal extends Eloquent */ public function transactions() { - return $this->hasMany('Transaction'); + return $this->hasMany('FireflyIII\Models\Transaction'); } /** - * User - * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function user() { - return $this->belongsTo('User'); + return $this->belongsTo('FireflyIII\User'); } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000000..bfff79a9f2 --- /dev/null +++ b/app/Providers/AppServiceProvider.php @@ -0,0 +1,40 @@ +app->bind( + 'Illuminate\Contracts\Auth\Registrar', + 'FireflyIII\Services\Registrar' + ); + } + +} diff --git a/app/Providers/BusServiceProvider.php b/app/Providers/BusServiceProvider.php new file mode 100644 index 0000000000..0edb595695 --- /dev/null +++ b/app/Providers/BusServiceProvider.php @@ -0,0 +1,42 @@ +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 new file mode 100644 index 0000000000..94d9ee03fd --- /dev/null +++ b/app/Providers/ConfigServiceProvider.php @@ -0,0 +1,31 @@ + [ + 'EventListener', + ], + 'App\Events\JournalDeleted' => [ + 'App\Handlers\Events\JournalDeletedHandler@handle', + ], + ]; + + /** + * Register any other events for your application. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * + * @return void + */ + public function boot(DispatcherContract $events) + { + parent::boot($events); + + TransactionJournal::deleted( + function (TransactionJournal $journal) { + + /** @var Transaction $transaction */ + foreach ($journal->transactions()->get() as $transaction) { + $transaction->delete(); + } + } + ); + + Account::deleted( + function (Account $account) { + + /** @var Transaction $transaction */ + foreach ($account->transactions()->get() as $transaction) { + $journal = $transaction->transactionJournal()->first(); + $journal->delete(); + } + } + ); + + PiggyBank::created(function(PiggyBank $piggyBank) { + $repetition = new PiggyBankRepetition; + $repetition->piggyBank()->associate($piggyBank); + $repetition->startdate = $piggyBank->startdate; + $repetition->targetdate = $piggyBank->targetdate; + $repetition->currentamount = 0; + $repetition->save(); + }); + + BudgetLimit::saved( + function (BudgetLimit $budgetLimit) { + + $end = Navigation::addPeriod(clone $budgetLimit->startdate, $budgetLimit->repeat_freq, 0); + $end->subDay(); + + $set = $budgetLimit->limitrepetitions()->where('startdate', $budgetLimit->startdate->format('Y-m-d'))->where('enddate', $end->format('Y-m-d')) + ->get(); + /* + * Create new LimitRepetition: + */ + if ($set->count() == 0) { + + $repetition = new LimitRepetition; + $repetition->startdate = $budgetLimit->startdate; + $repetition->enddate = $end; + $repetition->amount = $budgetLimit->amount; + $repetition->budgetLimit()->associate($budgetLimit); + + try { + $repetition->save(); + } catch (QueryException $e) { + \Log::error('Trying to save new LimitRepetition failed!'); + \Log::error($e->getMessage()); + } + } else { + if ($set->count() == 1) { + /* + * Update existing one. + */ + $repetition = $set->first(); + $repetition->amount = $budgetLimit->amount; + $repetition->save(); + + } + } + } + ); + + + } + +} diff --git a/app/Providers/FireflyServiceProvider.php b/app/Providers/FireflyServiceProvider.php new file mode 100644 index 0000000000..549df90c5a --- /dev/null +++ b/app/Providers/FireflyServiceProvider.php @@ -0,0 +1,72 @@ +app->bind( + 'preferences', function () { + return new Preferences; + } + ); + $this->app->bind( + 'navigation', function () { + return new Navigation; + } + ); + $this->app->bind( + 'amount', function () { + return new Amount; + } + ); + + $this->app->bind( + 'steam', function () { + return new Steam; + } + ); + $this->app->bind( + 'expandedform', function () { + return new ExpandedForm; + } + ); + + $this->app->bind('FireflyIII\Repositories\Account\AccountRepositoryInterface', 'FireflyIII\Repositories\Account\AccountRepository'); + $this->app->bind('FireflyIII\Repositories\Budget\BudgetRepositoryInterface', 'FireflyIII\Repositories\Budget\BudgetRepository'); + $this->app->bind('FireflyIII\Repositories\Category\CategoryRepositoryInterface', 'FireflyIII\Repositories\Category\CategoryRepository'); + $this->app->bind('FireflyIII\Repositories\Journal\JournalRepositoryInterface', 'FireflyIII\Repositories\Journal\JournalRepository'); + $this->app->bind('FireflyIII\Repositories\Bill\BillRepositoryInterface', 'FireflyIII\Repositories\Bill\BillRepository'); + $this->app->bind('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface', 'FireflyIII\Repositories\PiggyBank\PiggyBankRepository'); + $this->app->bind('FireflyIII\Support\Search\SearchInterface', 'FireflyIII\Support\Search\Search'); + + $this->app->bind('FireflyIII\Helpers\Report\ReportHelperInterface', 'FireflyIII\Helpers\Report\ReportHelper'); + $this->app->bind('FireflyIII\Helpers\Report\ReportQueryInterface', 'FireflyIII\Helpers\Report\ReportQuery'); + + } + +} \ No newline at end of file diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php new file mode 100644 index 0000000000..cd51b4b800 --- /dev/null +++ b/app/Providers/RouteServiceProvider.php @@ -0,0 +1,70 @@ +before( + function (Request $request) { + + // put IP in session if not already there. + + $reminders = []; + + if ($request->user()) { + //Filter::setSessionDateRange(); + //Reminders::updateReminders(); + //Steam::removeEmptyBudgetLimits(); + //$reminders = Reminders::getReminders(); + } + // View::share('reminders', $reminders); + } + ); + } + + /** + * Define the routes for the application. + * + * @param \Illuminate\Routing\Router $router + * + * @return void + */ + public function map(Router $router) + { + $router->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 new file mode 100644 index 0000000000..ff26c311ca --- /dev/null +++ b/app/Providers/TestingServiceProvider.php @@ -0,0 +1,28 @@ +app->environment() == 'testing') { + $this->app['config']['session.driver'] = 'native'; + } + } + +} \ No newline at end of file diff --git a/app/Repositories/Account/AccountRepository.php b/app/Repositories/Account/AccountRepository.php new file mode 100644 index 0000000000..aff7831674 --- /dev/null +++ b/app/Repositories/Account/AccountRepository.php @@ -0,0 +1,330 @@ +delete(); + + return true; + } + + /** + * @param Account $account + * @param int $page + * @param string $range + * + * @return mixed + */ + public function getJournals(Account $account, $page, $range = 'session') + { + $offset = $page * 50; + $query = Auth::user() + ->transactionJournals() + ->withRelevantData() + ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->where('transactions.account_id', $account->id) + ->orderBy('date', 'DESC'); + + if ($range == 'session') { + $query->before(Session::get('end', Carbon::now()->startOfMonth())); + $query->after(Session::get('start', Carbon::now()->startOfMonth())); + } + $count = $query->count(); + $set = $query->take(50)->offset($offset)->get(['transaction_journals.*']); + $paginator = new LengthAwarePaginator($set, $count, 50, $page); + + return $paginator; + + //return Paginator::make($items, $count, 50); + + + } + + /** + * @param Account $account + * + * @return TransactionJournal|null + */ + public function openingBalanceTransaction(Account $account) + { + return TransactionJournal::accountIs($account) + ->orderBy('transaction_journals.date', 'ASC') + ->orderBy('created_at', 'ASC') + ->first(['transaction_journals.*']); + } + + /** + * @param array $data + * + * @return Account; + */ + public function store(array $data) + { + $newAccount = $this->_store($data); + $this->_storeMetadata($newAccount, $data); + + + // continue with the opposing account: + if ($data['openingBalance'] != 0) { + $type = $data['openingBalance'] < 0 ? 'expense' : 'revenue'; + $opposingData = [ + 'user' => $data['user'], + 'accountType' => $type, + 'name' => $data['name'] . ' initial balance', + 'active' => false, + ]; + $opposing = $this->_store($opposingData); + $this->_storeInitialBalance($newAccount, $opposing, $data); + + } + + return $newAccount; + + } + + /** + * @param Account $account + * @param array $data + */ + public function update(Account $account, array $data) + { + // update the account: + $account->name = $data['name']; + $account->active = $data['active'] == '1' ? true : false; + $account->save(); + + // update meta data: + /** @var AccountMeta $meta */ + foreach ($account->accountMeta()->get() as $meta) { + if ($meta->name == 'accountRole') { + $meta->data = $data['accountRole']; + $meta->save(); + } + } + + $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'], + 'accountType' => $type, + 'name' => $data['name'] . ' initial balance', + 'active' => false, + ]; + $opposing = $this->_store($opposingData); + $this->_storeInitialBalance($account, $opposing, $data); + } + + } else { + // opening balance is zero, should we delete it? + if ($openingBalance) { + // delete existing opening balance. + $openingBalance->delete(); + } + } + + return $account; + } + + /** + * @param array $data + * + * @return Account + */ + protected function _store(array $data) + { + $type = Config::get('firefly.accountTypeByIdentifier.' . $data['accountType']); + $accountType = AccountType::whereType($type)->first(); + $newAccount = new Account( + [ + 'user_id' => $data['user'], + 'account_type_id' => $accountType->id, + 'name' => $data['name'], + 'active' => $data['active'] === true ? true : false, + ] + ); + if (!$newAccount->isValid()) { + // does the account already exist? + $existingAccount = Account::where('user_id', $data['user'])->where('account_type_id', $accountType->id)->where('name', $data['name'])->first(); + if (!$existingAccount) { + Log::error('Account create error: ' . $newAccount->getErrors()->toJson()); + var_dump($newAccount->getErrors()->toArray()); + } + $newAccount = $existingAccount; + } + $newAccount->save(); + + return $newAccount; + } + + /** + * @param Account $account + * @param array $data + */ + protected function _storeMetadata(Account $account, array $data) + { + $metaData = new AccountMeta( + [ + 'account_id' => $account->id, + 'name' => 'accountRole', + 'data' => $data['accountRole'] + ] + ); + if (!$metaData->isValid()) { + App::abort(500); + } + $metaData->save(); + } + + /** + * @param Account $account + * @param Account $opposing + * @param array $data + * + * @return TransactionJournal + */ + protected function _storeInitialBalance(Account $account, Account $opposing, array $data) + { + $type = $data['openingBalance'] < 0 ? 'Withdrawal' : 'Deposit'; + $transactionType = TransactionType::whereType($type)->first(); + + $journal = new TransactionJournal( + [ + 'user_id' => $data['user'], + 'transaction_type_id' => $transactionType->id, + 'bill_id' => null, + 'transaction_currency_id' => $data['openingBalanceCurrency'], + 'description' => 'Initial balance for "' . $account->name . '"', + 'completed' => true, + 'date' => $data['openingBalanceDate'], + 'encrypted' => true + ] + ); + if (!$journal->isValid()) { + App::abort(500); + } + $journal->save(); + + + if ($data['openingBalance'] < 0) { + $firstAccount = $opposing; + $secondAccount = $account; + $firstAmount = $data['openingBalance'] * -1; + $secondAmount = $data['openingBalance']; + } else { + $firstAccount = $account; + $secondAccount = $opposing; + $firstAmount = $data['openingBalance']; + $secondAmount = $data['openingBalance'] * -1; + } + + // first transaction: from + $one = new Transaction( + [ + 'account_id' => $firstAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $firstAmount + ] + ); + if (!$one->isValid()) { + App::abort(500); + } + $one->save(); + + // second transaction: to + $two = new Transaction( + [ + 'account_id' => $secondAccount->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $secondAmount + ] + ); + if (!$two->isValid()) { + App::abort(500); + } + $two->save(); + + return $journal; + + } + + /** + * @param Account $account + * @param TransactionJournal $journal + * @param array $data + * + * @return TransactionJournal + */ + protected function _updateInitialBalance(Account $account, TransactionJournal $journal, array $data) + { + $journal->date = $data['openingBalanceDate']; + + /** @var Transaction $transaction */ + foreach ($journal->transactions()->get() as $transaction) { + if ($account->id == $transaction->account_id) { + $transaction->amount = $data['openingBalance']; + $transaction->save(); + } + if ($account->id != $transaction->account_id) { + $transaction->amount = $data['openingBalance'] * -1; + $transaction->save(); + } + } + + return $journal; + } + + /** + * @param Account $account + * + * @return float + */ + public function leftOnAccount(Account $account) + { + $balance = \Steam::balance($account); + /** @var PiggyBank $p */ + foreach ($account->piggybanks()->get() as $p) { + $balance -= $p->currentRelevantRep()->currentamount; + } + + return $balance; + + } +} \ No newline at end of file diff --git a/app/Repositories/Account/AccountRepositoryInterface.php b/app/Repositories/Account/AccountRepositoryInterface.php new file mode 100644 index 0000000000..619309d762 --- /dev/null +++ b/app/Repositories/Account/AccountRepositoryInterface.php @@ -0,0 +1,59 @@ +active == 0) { + return $finalDate; + } + + /* + * $today is the start of the next period, to make sure FF3 won't miss anything + * when the current period has a transaction journal. + */ + $today = Navigation::addPeriod(new Carbon, $bill->repeat_freq, 0); + + $skip = $bill->skip + 1; + $start = Navigation::startOfPeriod(new Carbon, $bill->repeat_freq); + /* + * go back exactly one month/week/etc because FF3 does not care about 'next' + * bills if they're too far into the past. + */ + + $counter = 0; + while ($start <= $today) { + if (($counter % $skip) == 0) { + // do something. + $end = Navigation::endOfPeriod(clone $start, $bill->repeat_freq); + $journalCount = $bill->transactionjournals()->before($end)->after($start)->count(); + if ($journalCount == 0) { + $finalDate = clone $start; + break; + } + } + + // add period for next round! + $start = Navigation::addPeriod($start, $bill->repeat_freq, 0); + $counter++; + } + + return $finalDate; + } + + /** + * @param Bill $bill + * @param TransactionJournal $journal + * + * @return bool + */ + public function scan(Bill $bill, TransactionJournal $journal) + { + /* + * Match words. + */ + $wordMatch = false; + $matches = explode(',', $bill->match); + $description = strtolower($journal->description); + Log::debug('Now scanning ' . $description); + + /* + * Attach expense account to description for more narrow matching. + */ + if (count($journal->transactions) < 2) { + $transactions = $journal->transactions()->get(); + } else { + $transactions = $journal->transactions; + } + /** @var Transaction $transaction */ + foreach ($transactions as $transaction) { + /** @var Account $account */ + $account = $transaction->account()->first(); + /** @var AccountType $type */ + $type = $account->accountType()->first(); + if ($type->type == 'Expense account' || $type->type == 'Beneficiary account') { + $description .= ' ' . strtolower($account->name); + } + } + Log::debug('Final description: ' . $description); + Log::debug('Matches searched: ' . join(':', $matches)); + + $count = 0; + foreach ($matches as $word) { + if (!(strpos($description, strtolower($word)) === false)) { + $count++; + } + } + if ($count >= count($matches)) { + $wordMatch = true; + Log::debug('word match is true'); + } else { + Log::debug('Count: ' . $count.', count(matches): ' . count($matches)); + } + + + /* + * Match amount. + */ + + $amountMatch = false; + if (count($transactions) > 1) { + + $amount = max(floatval($transactions[0]->amount), floatval($transactions[1]->amount)); + $min = floatval($bill->amount_min); + $max = floatval($bill->amount_max); + if ($amount >= $min && $amount <= $max) { + $amountMatch = true; + Log::debug('Amount match is true!'); + } + } + + + /* + * If both, update! + */ + if ($wordMatch && $amountMatch) { + Log::debug('TOTAL match is true!'); + $journal->bill()->associate($bill); + $journal->save(); + } + } + + /** + * @param array $data + * + * @return Bill + */ + public function store(array $data) + { + + + $bill = Bill::create( + [ + 'name' => $data['name'], + 'match' => $data['match'], + 'amount_min' => $data['amount_min'], + 'user_id' => $data['user'], + 'amount_max' => $data['amount_max'], + 'date' => $data['date'], + 'repeat_freq' => $data['repeat_freq'], + 'skip' => $data['skip'], + 'automatch' => $data['automatch'], + 'active' => $data['active'], + + ] + ); + + return $bill; + } + + /** + * @param Bill $bill + * @param array $data + * + * @return Bill|static + */ + public function update(Bill $bill, array $data) + { + + + $bill->name = $data['name']; + $bill->match = $data['match']; + $bill->amount_min = $data['amount_min']; + $bill->amount_max = $data['amount_max']; + $bill->date = $data['date']; + $bill->repeat_freq = $data['repeat_freq']; + $bill->skip = $data['skip']; + $bill->automatch = $data['automatch']; + $bill->active = $data['active']; + $bill->save(); + + return $bill; + } +} diff --git a/app/Repositories/Bill/BillRepositoryInterface.php b/app/Repositories/Bill/BillRepositoryInterface.php new file mode 100644 index 0000000000..ead38877b1 --- /dev/null +++ b/app/Repositories/Bill/BillRepositoryInterface.php @@ -0,0 +1,51 @@ +delete(); + + return true; + } + + /** + * Returns all the transaction journals for a limit, possibly limited by a limit repetition. + * + * @param Budget $budget + * @param LimitRepetition $repetition + * @param int $take + * + * @return \Illuminate\Pagination\Paginator + */ + public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50) + { + $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $take : 0; + + + $setQuery = $budget->transactionJournals()->withRelevantData()->take($take)->offset($offset)->orderBy('date', 'DESC'); + $countQuery = $budget->transactionJournals(); + + + if (!is_null($repetition->id)) { + $setQuery->after($repetition->startdate)->before($repetition->enddate); + $countQuery->after($repetition->startdate)->before($repetition->enddate); + } + + + $set = $setQuery->get(['transaction_journals.*']); + $count = $countQuery->count(); + return new LengthAwarePaginator($set, $count, $take, $offset); + } + + /** + * @param Budget $budget + * @param Carbon $date + * + * @return float + */ + public function spentInMonth(Budget $budget, Carbon $date) + { + $end = clone $date; + $date->startOfMonth(); + $end->endOfMonth(); + $sum = floatval($budget->transactionjournals()->before($end)->after($date)->lessThan(0)->sum('amount')) * -1; + + return $sum; + } + + /** + * @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->save(); + + return $budget; + } + + /** + * @param Budget $budget + * @param Carbon $date + * @param $amount + * + * @return LimitRepetition|null + */ + public function updateLimitAmount(Budget $budget, Carbon $date, $amount) + { + /** @var BudgetLimit $limit */ + $limit = $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']); + if (!$limit) { + // create one! + $limit = new BudgetLimit; + $limit->budget()->associate($budget); + $limit->startdate = $date; + $limit->amount = $amount; + $limit->repeat_freq = 'monthly'; + $limit->repeats = 0; + $limit->save(); + } else { + if ($amount > 0) { + $limit->amount = $amount; + $limit->save(); + } else { + $limit->delete(); + } + } + + return $limit; + + + } +} \ No newline at end of file diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php new file mode 100644 index 0000000000..eabda354f3 --- /dev/null +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -0,0 +1,66 @@ +delete(); + + return true; + } + + + /** + * @param array $data + * + * @return Category + */ + public function store(array $data) + { + $newCategory = new Category( + [ + 'user_id' => $data['user'], + 'name' => $data['name'], + ] + ); + $newCategory->save(); + + return $newCategory; + } + + /** + * @param Category $category + * @param array $data + * + * @return Category + */ + public function update(Category $category, array $data) + { + // update the account: + $category->name = $data['name']; + $category->save(); + + return $category; + } + +} \ No newline at end of file diff --git a/app/Repositories/Category/CategoryRepositoryInterface.php b/app/Repositories/Category/CategoryRepositoryInterface.php new file mode 100644 index 0000000000..5b099eb6c7 --- /dev/null +++ b/app/Repositories/Category/CategoryRepositoryInterface.php @@ -0,0 +1,36 @@ +transactionType->type) { + case 'Withdrawal': + $positive = false; + break; + } + /** @var Transaction $transaction */ + foreach ($journal->transactions()->get() as $transaction) { + if (floatval($transaction->amount) > 0 && $positive === true) { + return $transaction->account_id; + } + if (floatval($transaction->amount) < 0 && $positive === false) { + return $transaction->account_id; + } + + } + + return $journal->transactions()->first()->account_id; + } + + /** + * @param string $query + * @param TransactionJournal $journal + * + * @return Collection + */ + public function searchRelated($query, TransactionJournal $journal) + { + $start = clone $journal->date; + $end = clone $journal->date; + $start->startOfMonth(); + $end->endOfMonth(); + + // get already related transactions: + $exclude = [$journal->id]; + foreach ($journal->transactiongroups()->get() as $group) { + foreach ($group->transactionjournals()->get() as $current) { + $exclude[] = $current->id; + } + } + $exclude = array_unique($exclude); + + /** @var Collection $collection */ + $collection = Auth::user()->transactionjournals() + ->withRelevantData() + ->before($end)->after($start)->where('encrypted', 0) + ->whereNotIn('id', $exclude) + ->where('description', 'LIKE', '%' . $query . '%') + ->get(); + + // manually search encrypted entries: + /** @var Collection $encryptedCollection */ + $encryptedCollection = Auth::user()->transactionjournals() + ->withRelevantData() + ->before($end)->after($start) + ->where('encrypted', 1) + ->whereNotIn('id', $exclude) + ->get(); + $encrypted = $encryptedCollection->filter( + function (TransactionJournal $journal) use ($query) { + $strPos = strpos(strtolower($journal->description), strtolower($query)); + if ($strPos !== false) { + return $journal; + } + + return null; + } + ); + + return $collection->merge($encrypted); + } + + /** + * @param array $data + * + * @return TransactionJournal + */ + public function store(array $data) + { + // find transaction type. + $transactionType = TransactionType::where('type', ucfirst($data['what']))->first(); + + // store actual journal. + $journal = new TransactionJournal( + [ + 'user_id' => $data['user'], + 'transaction_type_id' => $transactionType->id, + 'transaction_currency_id' => $data['amount_currency_id'], + 'description' => $data['description'], + 'completed' => 0, + 'date' => $data['date'], + ] + ); + $journal->save(); + + + // store or get category + if (strlen($data['category']) > 0) { + $category = Category::firstOrCreate(['name' => $data['category'], 'user_id' => $data['user']]); + $journal->categories()->save($category); + } + + // store or get budget + if (intval($data['budget_id']) > 0) { + $budget = Budget::find($data['budget_id']); + $journal->budgets()->save($budget); + } + + // store accounts (depends on type) + switch ($transactionType->type) { + case 'Withdrawal': + + $from = Account::find($data['account_id']); + + if (strlen($data['expense_account']) > 0) { + $toType = AccountType::where('type', 'Expense account')->first(); + $to = Account::firstOrCreate( + ['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => $data['expense_account'], 'active' => 1] + ); + } else { + $toType = AccountType::where('type', 'Cash account')->first(); + $to = Account::firstOrCreate(['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => 'Cash account', 'active' => 1]); + } + break; + + case 'Deposit': + $to = Account::find($data['account_id']); + + if (strlen($data['revenue_account']) > 0) { + $fromType = AccountType::where('type', 'Revenue account')->first(); + $from = Account::firstOrCreate( + ['user_id' => $data['user'], 'account_type_id' => $fromType->id, 'name' => $data['revenue_account'], 'active' => 1] + ); + } else { + $toType = AccountType::where('type', 'Cash account')->first(); + $from = Account::firstOrCreate(['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => 'Cash account', 'active' => 1]); + } + + break; + case 'Transfer': + $from = Account::find($data['account_from_id']); + $to = Account::find($data['account_to_id']); + break; + } + + // store accompanying transactions. + Transaction::create( // first transaction. + [ + 'account_id' => $from->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $data['amount'] * -1 + ] + ); + Transaction::create( // second transaction. + [ + 'account_id' => $to->id, + 'transaction_journal_id' => $journal->id, + 'amount' => $data['amount'] + ] + ); + $journal->completed = 1; + $journal->save(); + + return $journal; + + + } + + + /** + * @param TransactionJournal $journal + * @param array $data + * + * @return mixed + */ + public function update(TransactionJournal $journal, array $data) + { + // update actual journal. + $journal->transaction_currency_id = $data['amount_currency_id']; + $journal->description = $data['description']; + $journal->date = $data['date']; + + + // unlink all categories, recreate them: + $journal->categories()->detach(); + if (strlen($data['category']) > 0) { + $category = Category::firstOrCreate(['name' => $data['category'], 'user_id' => $data['user']]); + $journal->categories()->save($category); + } + + // unlink all budgets and recreate them: + $journal->budgets()->detach(); + if (intval($data['budget_id']) > 0) { + $budget = Budget::find($data['budget_id']); + $journal->budgets()->save($budget); + } + + // store accounts (depends on type) + switch ($journal->transactionType->type) { + case 'Withdrawal': + + $from = Account::find($data['account_id']); + + if (strlen($data['expense_account']) > 0) { + $toType = AccountType::where('type', 'Expense account')->first(); + $to = Account::firstOrCreate( + ['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => $data['expense_account'], 'active' => 1] + ); + } else { + $toType = AccountType::where('type', 'Cash account')->first(); + $to = Account::firstOrCreate(['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => 'Cash account', 'active' => 1]); + } + break; + + case 'Deposit': + $to = Account::find($data['account_id']); + + if (strlen($data['revenue_account']) > 0) { + $fromType = AccountType::where('type', 'Revenue account')->first(); + $from = Account::firstOrCreate( + ['user_id' => $data['user'], 'account_type_id' => $fromType->id, 'name' => $data['revenue_account'], 'active' => 1] + ); + } else { + $toType = AccountType::where('type', 'Cash account')->first(); + $from = Account::firstOrCreate(['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => 'Cash account', 'active' => 1]); + } + + break; + case 'Transfer': + $from = Account::find($data['account_from_id']); + $to = Account::find($data['account_to_id']); + break; + } + + // update the from and to transaction. + /** @var Transaction $transaction */ + foreach ($journal->transactions()->get() as $transaction) { + if ($transaction->account_id === $from->id) { + // this is the from transaction, negative amount: + $transaction->amount = $data['amount'] * -1; + $transaction->save(); + } + if ($transaction->account_id === $to->id) { + $transaction->amount = $data['amount']; + $transaction->save(); + } + } + + + $journal->save(); + + return $journal; + } + +} \ No newline at end of file diff --git a/app/Repositories/Journal/JournalRepositoryInterface.php b/app/Repositories/Journal/JournalRepositoryInterface.php new file mode 100644 index 0000000000..f083fb9a3e --- /dev/null +++ b/app/Repositories/Journal/JournalRepositoryInterface.php @@ -0,0 +1,47 @@ + $request->get('rep_length'), + 'rep_every' => intval($request->get('rep_every')), + 'rep_times' => intval($request->get('rep_times')), + 'remind_me' => intval($request->get('remind_me')) == 1 ? true : false , + 'reminder' => $request->get('reminder'), + */ + + $piggyBank->name = $data['name']; + $piggyBank->account_id = intval($data['account_id']); + $piggyBank->targetamount = floatval($data['targetamount']); + $piggyBank->targetdate = $data['targetdate']; + $piggyBank->reminder = $data['reminder']; + $piggyBank->rep_length = isset($data['rep_length']) ? $data['rep_length'] : null; + $piggyBank->rep_every =isset($data['rep_every']) ? $data['rep_every'] : null; + $piggyBank->rep_times = isset($data['rep_times']) ? $data['rep_times'] : null; + $piggyBank->remind_me = isset($data['remind_me']) ? $data['remind_me'] : null; + + $piggyBank->save(); + return $piggyBank; + } + /** * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. * @@ -23,13 +65,13 @@ class RepeatedExpense extends PiggyBankShared implements CUDInterface, CommonDat * other variables this method tries to divide the piggy bank into equal parts. Each is * accommodated by a reminder (if everything goes to plan). * - * @param \PiggyBankRepetition $repetition + * @param PiggyBankRepetition $repetition * * @return Collection */ - public function calculateParts(\PiggyBankRepetition $repetition) + public function calculateParts(PiggyBankRepetition $repetition) { - /** @var \PiggyBank $piggyBank */ + /** @var PiggyBank $piggyBank */ $piggyBank = $repetition->piggyBank()->first(); $bars = new Collection; $currentStart = clone $repetition->startdate; @@ -44,7 +86,7 @@ class RepeatedExpense extends PiggyBankShared implements CUDInterface, CommonDat } while ($currentStart < $repetition->targetdate) { - $currentTarget = \DateKit::endOfX($currentStart, $piggyBank->reminder, $repetition->targetdate); + $currentTarget = Navigation::endOfX($currentStart, $piggyBank->reminder, $repetition->targetdate); $entry = ['repetition' => $repetition, 'amountPerBar' => null, 'currentAmount' => floatval($repetition->currentamount), 'cumulativeAmount' => null, 'startDate' => $currentStart, 'targetDate' => $currentTarget]; $bars->push($this->createPiggyBankPart($entry)); @@ -84,41 +126,4 @@ class RepeatedExpense extends PiggyBankShared implements CUDInterface, CommonDat return $part; } - - - /** - * @param array $data - * - * @return \Eloquent - */ - public function store(array $data) - { - - $data['rep_every'] = intval($data['rep_every']); - $data['reminder_skip'] = intval($data['reminder_skip']); - $data['order'] = intval($data['order']); - $data['remind_me'] = intval($data['remind_me']); - $data['account_id'] = intval($data['account_id']); - - - if ($data['remind_me'] == 0) { - $data['reminder'] = null; - } - - $repeated = new \PiggyBank($data); - $repeated->save(); - - return $repeated; - } - - /** - * Returns all objects. - * - * @return Collection - */ - public function get() - { - return $this->getUser()->piggyBanks()->where('repeats', 1)->get(); - } - -} +} \ No newline at end of file diff --git a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php new file mode 100644 index 0000000000..a06ed505be --- /dev/null +++ b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php @@ -0,0 +1,51 @@ + $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/Support/Amount.php b/app/Support/Amount.php new file mode 100644 index 0000000000..97a07e7055 --- /dev/null +++ b/app/Support/Amount.php @@ -0,0 +1,133 @@ +getCurrencySymbol(); + + return $this->formatWithSymbol($currencySymbol, $amount, $coloured); + + + } + + /** + * @param Transaction|\Transaction $transaction + * @param bool $coloured + * + * @return string + */ + public function formatTransaction(Transaction $transaction, $coloured = true) + { + $symbol = $transaction->transactionJournal->transactionCurrency->symbol; + $amount = floatval($transaction->amount); + + return $this->formatWithSymbol($symbol, $amount, $coloured); + + + } + + /** + * @param string $symbol + * @param float $amount + * @param bool $coloured + * + * @return string + */ + public function formatWithSymbol($symbol, $amount, $coloured = true) + { + $amount = floatval($amount); + $amount = round($amount, 2); + $string = number_format($amount, 2, ',', '.'); + + if ($coloured === true) { + if ($amount === 0.0) { + return '' . $symbol . ' ' . $string . ''; + } + if ($amount > 0) { + return '' . $symbol . ' ' . $string . ''; + } + + return '' . $symbol . ' ' . $string . ''; + } + + // € + return $symbol . ' ' . $string; + } + + + /** + * @return string + */ + public function getCurrencySymbol() + { + if (defined('FFCURRENCYSYMBOL')) { + return FFCURRENCYSYMBOL; + } + if (\Cache::has('FFCURRENCYSYMBOL')) { + define('FFCURRENCYSYMBOL', \Cache::get('FFCURRENCYSYMBOL')); + + return FFCURRENCYSYMBOL; + } + + $currencyPreference = Prefs::get('currencyPreference', 'EUR'); + $currency = TransactionCurrency::whereCode($currencyPreference->data)->first(); + + \Cache::forever('FFCURRENCYSYMBOL', $currency->symbol); + + define('FFCURRENCYSYMBOL', $currency->symbol); + + return $currency->symbol; + } + + /** + * @return string + */ + public function getCurrencyCode() + { + if (defined('FFCURRENCYCODE')) { + return FFCURRENCYCODE; + } + if (Cache::has('FFCURRENCYCODE')) { + define('FFCURRENCYCODE', Cache::get('FFCURRENCYCODE')); + + return FFCURRENCYCODE; + } + + + $currencyPreference = Prefs::get('currencyPreference', 'EUR'); + $currency = TransactionCurrency::whereCode($currencyPreference->data)->first(); + + \Cache::forever('FFCURRENCYCODE', $currency->code); + + define('FFCURRENCYCODE', $currency->code); + + return $currency->code; + } + + public function getDefaultCurrency() + { + $currencyPreference = Prefs::get('currencyPreference', 'EUR'); + $currency = TransactionCurrency::whereCode($currencyPreference->data)->first(); + + return $currency; + } +} \ No newline at end of file diff --git a/app/Support/ExpandedForm.php b/app/Support/ExpandedForm.php new file mode 100644 index 0000000000..94f462e6fe --- /dev/null +++ b/app/Support/ExpandedForm.php @@ -0,0 +1,317 @@ +label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $options['step'] = '1'; + $html = \View::make('form.integer', compact('classes', 'name', 'label', 'value', 'options'))->render(); + + return $html; + + } + + + /** + * @param $name + * @param null $value + * @param array $options + * + * @return string + */ + public function tags($name, $value = null, array $options = []) + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $options['data-role'] = 'tagsinput'; + $html = \View::make('form.tags', compact('classes', 'name', 'label', 'value', 'options'))->render(); + + return $html; + } + + /** + * @param $name + * @param null $value + * @param array $options + * + * @return string + */ + public function amount($name, $value = null, array $options = []) + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $options['step'] = 'any'; + $options['min'] = '0.01'; + $defaultCurrency = isset($options['currency']) ? $options['currency'] : \Amount::getDefaultCurrency(); + $currencies = TransactionCurrency::orderBy('code', 'ASC')->get(); + $html = View::make('form.amount', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); + + return $html; + + } + + /** + * @param $name + * @param $options + * + * @return mixed + */ + public function label($name, $options) + { + if (isset($options['label'])) { + return $options['label']; + } + $labels = ['amount_min' => 'Amount (min)', 'amount_max' => 'Amount (max)', 'match' => 'Matches on', 'repeat_freq' => 'Repetition', + 'account_from_id' => 'Account from', 'account_to_id' => 'Account to', 'account_id' => 'Asset account', 'budget_id' => 'Budget' + , 'piggy_bank_id' => 'Piggy bank']; + + + return isset($labels[$name]) ? $labels[$name] : str_replace('_', ' ', ucfirst($name)); + + } + + /** + * @param $name + * @param $label + * @param array $options + * + * @return array + */ + public 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 + */ + public function getHolderClasses($name) + { + /* + * Get errors, warnings and successes from session: + */ + /** @var MessageBag $errors */ + $errors = Session::get('errors'); + + /** @var MessageBag $successes */ + $successes = Session::get('successes'); + + switch (true) { + case (!is_null($errors) && $errors->has($name)): + $classes = 'form-group has-error has-feedback'; + break; + case (!is_null($successes) && $successes->has($name)): + $classes = 'form-group has-success has-feedback'; + break; + default: + $classes = 'form-group'; + break; + } + + return $classes; + } + + /** + * @param $name + * @param $value + * + * @return mixed + */ + public function fillFieldValue($name, $value) + { + if (Session::has('preFilled')) { + $preFilled = \Session::get('preFilled'); + $value = isset($preFilled[$name]) && is_null($value) ? $preFilled[$name] : $value; + } + if (!is_null(Input::old($name))) { + $value = Input::old($name); + } + + return $value; + } + + /** + * @param $name + * @param null $value + * @param array $options + * + * @return string + */ + public function balance($name, $value = null, array $options = []) + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $options['step'] = 'any'; + $defaultCurrency = isset($options['currency']) ? $options['currency'] : Amount::getDefaultCurrency(); + $currencies = TransactionCurrency::orderBy('code', 'ASC')->get(); + $html = View::make('form.balance', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); + + return $html; + } + + /** + * @param $name + * @param int $value + * @param null $checked + * @param array $options + * + * @return string + */ + public function checkbox($name, $value = 1, $checked = null, $options = []) + { + $options['checked'] = $checked === true ? true : null; + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + + unset($options['placeholder'], $options['autocomplete'], $options['class']); + + $html = View::make('form.checkbox', compact('classes', 'name', 'label', 'value', 'options'))->render(); + + return $html; + } + + /** + * @param $name + * @param null $value + * @param array $options + * + * @return string + */ + public function date($name, $value = null, array $options = []) + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $html = View::make('form.date', compact('classes', 'name', 'label', 'value', 'options'))->render(); + + return $html; + } + + /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * + * Takes any collection and tries to make a sensible select list compatible array of it. + * + * @param Collection $set + * @param bool $addEmpty + * + * @return mixed + */ + public function makeSelectList(Collection $set, $addEmpty = false) + { + $selectList = []; + if ($addEmpty) { + $selectList[0] = '(none)'; + } + $fields = ['title', 'name', 'description']; + /** @var \Eloquent $entry */ + foreach ($set as $entry) { + $id = intval($entry->id); + $title = null; + + foreach ($fields as $field) { + if (isset($entry->$field)) { + $title = $entry->$field; + } + } + $selectList[$id] = $title; + } + + return $selectList; + } + + /** + * @param $type + * @param $name + * + * @return string + */ + public function optionsList($type, $name) + { + $previousValue = \Input::old('post_submit_action'); + $previousValue = is_null($previousValue) ? 'store' : $previousValue; + $html = \View::make('form.options', compact('type', 'name', 'previousValue'))->render(); + + return $html; + } + + /** + * @param $name + * @param array $list + * @param null $selected + * @param array $options + * + * @return string + */ + public function select($name, array $list = [], $selected = null, array $options = []) + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $selected = $this->fillFieldValue($name, $selected); + $html = \View::make('form.select', compact('classes', 'name', 'label', 'selected', 'options', 'list'))->render(); + + return $html; + } + + /** + * @param $name + * @param null $value + * @param array $options + * + * @return string + */ + public function text($name, $value = null, array $options = []) + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $html = View::make('form.text', compact('classes', 'name', 'label', 'value', 'options'))->render(); + + return $html; + + } +} \ No newline at end of file diff --git a/app/lib/FireflyIII/Shared/Facade/Amount.php b/app/Support/Facades/Amount.php similarity index 63% rename from app/lib/FireflyIII/Shared/Facade/Amount.php rename to app/Support/Facades/Amount.php index 4a3eb4dba4..90562d745e 100644 --- a/app/lib/FireflyIII/Shared/Facade/Amount.php +++ b/app/Support/Facades/Amount.php @@ -1,19 +1,19 @@ endOfDay()->addDay(); + break; + case '1W': + $date->endOfWeek()->addDay()->startOfWeek(); + break; + case '1M': + $date->endOfMonth()->addDay()->startOfMonth(); + break; + case '3M': + $date->lastOfQuarter()->addDay(); + break; + case '6M': + if (intval($date->format('m')) >= 7) { + $date->startOfYear()->addYear(); + } else { + $date->startOfYear()->addMonths(6); + } + break; + case '1Y': + $date->startOfYear()->addYear(); + break; + default: + throw new FireflyException('Cannot do _next() on ' . $range); + break; + } + + return $date; + } + + /** + * @param $range + * @param Carbon $date + * + * @return Carbon + * @throws FireflyException + */ + public function jumpToPrevious($range, Carbon $date) + { + $functionMap = [ + '1D' => 'Day', + '1W' => 'Week', + '1M' => 'Month', + '1Y' => 'Year' + ]; + + if (isset($functionMap[$range])) { + $startFunction = 'startOf' . $functionMap[$range]; + $subFunction = 'sub' . $functionMap[$range]; + $date->$startFunction()->$subFunction(); + + return $date; + } + if ($range == '3M') { + $date->firstOfQuarter()->subMonths(3)->firstOfQuarter(); + + return $date; + } + if ($range == '6M') { + $month = intval($date->format('m')); + $date->startOfYear(); + if ($month <= 6) { + $date->subMonths(6); + } + + return $date; + } + throw new FireflyException('Cannot do _previous() on ' . $range); + } + + /** + * @param $range + * @param Carbon $date + * + * @return string + * @throws FireflyException + */ + public function periodName($range, Carbon $date) + { + $formatMap = [ + '1D' => 'jS F Y', + '1W' => '\w\e\ek W, Y', + '1M' => 'F Y', + '1Y' => 'Y', + ]; + if (isset($formatMap[$range])) { + return $date->format($formatMap[$range]); + } + if ($range == '3M') { + $month = intval($date->format('m')); + + return 'Q' . ceil(($month / 12) * 4) . ' ' . $date->format('Y'); + } + if ($range == '6M') { + $month = intval($date->format('m')); + $half = ceil(($month / 12) * 2); + $halfName = $half == 1 ? 'first' : 'second'; + + return $halfName . ' half of ' . $date->format('Y'); + } + throw new FireflyException('No _periodName() for range "' . $range . '"'); + } + /** * @param Carbon $date * @param $repeatFrequency @@ -214,45 +327,74 @@ class Date } /** - * @param Carbon $theDate - * @param $repeatFreq - * @param int $subtract + * @param $range + * @param Carbon $start * * @return Carbon * @throws FireflyException */ - public function subtractPeriod(Carbon $theDate, $repeatFreq, $subtract = 1) + public function updateEndDate($range, Carbon $start) { - $date = clone $theDate; - $functionMap = [ - 'daily' => 'subDays', - 'week' => 'subWeeks', - 'weekly' => 'subWeeks', - 'month' => 'subMonths', - 'monthly' => 'subMonths', - 'year' => 'subYears', - 'yearly' => 'subYears', + '1D' => 'endOfDay', + '1W' => 'endOfWeek', + '1M' => 'endOfMonth', + '3M' => 'lastOfQuarter', + '1Y' => 'endOfYear', ]; - $modifierMap = [ - 'quarter' => 3, - 'quarterly' => 3, - 'half-year' => 6, - ]; - if (isset($functionMap[$repeatFreq])) { - $function = $functionMap[$repeatFreq]; - $date->$function($subtract); + $end = clone $start; - return $date; + if (isset($functionMap[$range])) { + $function = $functionMap[$range]; + $end->$function(); + + return $end; } - if (isset($modifierMap[$repeatFreq])) { - $subtract = $subtract * $modifierMap[$repeatFreq]; - $date->subMonths($subtract); + if ($range == '6M') { + if (intval($start->format('m')) >= 7) { + $end->endOfYear(); + } else { + $end->startOfYear()->addMonths(6); + } - return $date; + return $end; } - - throw new FireflyException('Cannot do subtractPeriod for $repeat_freq ' . $repeatFreq); + throw new FireflyException('updateEndDate cannot handle $range ' . $range); } -} + /** + * @param $range + * @param Carbon $start + * + * @return Carbon + * @throws FireflyException + */ + public function updateStartDate($range, Carbon $start) + { + $functionMap = [ + '1D' => 'startOfDay', + '1W' => 'startOfWeek', + '1M' => 'startOfMonth', + '3M' => 'firstOfQuarter', + '1Y' => 'startOfYear', + ]; + if (isset($functionMap[$range])) { + $function = $functionMap[$range]; + $start->$function(); + + return $start; + } + if ($range == '6M') { + if (intval($start->format('m')) >= 7) { + $start->startOfYear()->addMonths(6); + } else { + $start->startOfYear(); + } + + return $start; + } + throw new FireflyException('updateStartDate cannot handle $range ' . $range); + } + + +} \ No newline at end of file diff --git a/app/lib/FireflyIII/Shared/Preferences/Preferences.php b/app/Support/Preferences.php similarity index 61% rename from app/lib/FireflyIII/Shared/Preferences/Preferences.php rename to app/Support/Preferences.php index 85ab05cbc7..98cab769c9 100644 --- a/app/lib/FireflyIII/Shared/Preferences/Preferences.php +++ b/app/Support/Preferences.php @@ -1,13 +1,17 @@ id)->where('name', $name)->first(); + $pref = Preference::where('user_id', Auth::user()->id)->where('name', $name)->first(); if (is_null($pref) && is_null($default)) { // return NULL return null; @@ -37,11 +41,11 @@ class Preferences implements PreferencesInterface */ public function set($name, $value) { - $pref = \Preference::where('user_id', \Auth::user()->id)->where('name', $name)->first(); + $pref = Preference::where('user_id', Auth::user()->id)->where('name', $name)->first(); if (is_null($pref)) { - $pref = new \Preference; + $pref = new Preference; $pref->name = $name; - $pref->user()->associate(\Auth::user()); + $pref->user()->associate(Auth::user()); } $pref->data = $value; @@ -51,4 +55,4 @@ class Preferences implements PreferencesInterface return $pref; } -} +} \ No newline at end of file diff --git a/app/lib/FireflyIII/Search/Search.php b/app/Support/Search/Search.php similarity index 91% rename from app/lib/FireflyIII/Search/Search.php rename to app/Support/Search/Search.php index 4a5d429634..7e0cd1de39 100644 --- a/app/lib/FireflyIII/Search/Search.php +++ b/app/Support/Search/Search.php @@ -1,17 +1,20 @@ budgets()->get(); $newSet = $set->filter( - function (\Budget $b) use ($words) { + function (Budget $b) use ($words) { $found = 0; foreach ($words as $word) { if (!(strpos(strtolower($b->name), strtolower($word)) === false)) { @@ -64,7 +67,7 @@ class Search /** @var Collection $set */ $set = \Auth::user()->categories()->get(); $newSet = $set->filter( - function (\Category $c) use ($words) { + function (Category $c) use ($words) { $found = 0; foreach ($words as $word) { if (!(strpos(strtolower($c->name), strtolower($word)) === false)) { diff --git a/app/Support/Search/SearchInterface.php b/app/Support/Search/SearchInterface.php new file mode 100644 index 0000000000..50d7c6ad08 --- /dev/null +++ b/app/Support/Search/SearchInterface.php @@ -0,0 +1,48 @@ + 'Others', - 'amount' => 0 - ]; - $return = []; - $count = 0; - foreach ($array as $id => $entry) { - if ($count < ($limit - 1)) { - $return[$id] = $entry; - } else { - $others['amount'] += $entry['amount']; - } - - $count++; - } - $return[0] = $others; - - return $return; + $date = is_null($date) ? Carbon::now() : $date; + $balance = floatval( + $account->transactions()->leftJoin( + 'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id' + )->where('transaction_journals.date', '<=', $date->format('Y-m-d'))->sum('transactions.amount') + ); + return $balance; } /** @@ -118,6 +109,38 @@ class ReportHelper implements ReportHelperInterface } + /** + * Only return the top X entries, group the rest by amount + * and described as 'Others'. id = 0 as well + * + * @param array $array + * @param int $limit + * + * @return array + */ + public function limitArray(array $array, $limit = 10) + { + $others = [ + 'name' => 'Others', + 'amount' => 0 + ]; + $return = []; + $count = 0; + foreach ($array as $id => $entry) { + if ($count < ($limit - 1)) { + $return[$id] = $entry; + } else { + $others['amount'] += $entry['amount']; + } + + $count++; + } + $return[0] = $others; + + return $return; + + } + /** * Sort an array where all 'amount' keys are negative floats. * @@ -139,4 +162,23 @@ class ReportHelper implements ReportHelperInterface return $array; } -} + + /** + * @param PiggyBank $piggyBank + * @param PiggyBankRepetition $repetition + * + * @return int + */ + public function percentage(PiggyBank $piggyBank, PiggyBankRepetition $repetition) + { + $pct = $repetition->currentamount / $piggyBank->targetamount * 100; + if ($pct > 100) { + // @codeCoverageIgnoreStart + return 100; + // @codeCoverageIgnoreEnd + } else { + return floor($pct); + } + } + +} \ No newline at end of file diff --git a/app/User.php b/app/User.php new file mode 100644 index 0000000000..4e09c591f0 --- /dev/null +++ b/app/User.php @@ -0,0 +1,110 @@ +hasMany('FireflyIII\Models\Account'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function bills() + { + return $this->hasMany('FireflyIII\Models\Bill'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function budgets() + { + return $this->hasMany('FireflyIII\Models\Budget'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function categories() + { + return $this->hasMany('FireflyIII\Models\Category'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough + */ + public function piggyBanks() + { + return $this->hasManyThrough('FireflyIII\Models\PiggyBank', 'FireflyIII\Models\Account'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function preferences() + { + return $this->hasMany('FireflyIII\Models\Preference'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function reminders() + { + return $this->hasMany('FireflyIII\Models\Reminder'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function transactionjournals() + { + return $this->hasMany('FireflyIII\Models\TransactionJournal'); + } + + /** + * @param $value + */ + public function setPasswordAttribute($value) + { + $this->attributes['password'] = \Hash::make($value); + } + +} diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php new file mode 100644 index 0000000000..1d06ba7c38 --- /dev/null +++ b/app/Validation/FireflyValidator.php @@ -0,0 +1,53 @@ +where('user_id', Auth::user()->id)->where('id', $value)->count(); + if ($count == 1) { + return true; + } + + return false; + + } + + /** + * @param $attribute + * @param $value + * @param $parameters + * + * @return bool + */ + public function validateUniqueForUser($attribute, $value, $parameters) + { + $count = DB::table($parameters[0])->where($parameters[1], $value)->count(); + if ($count == 0) { + return true; + } + + return false; + + } +} + diff --git a/app/commands/Cleanup.php b/app/commands/Cleanup.php deleted file mode 100644 index db76195588..0000000000 --- a/app/commands/Cleanup.php +++ /dev/null @@ -1,76 +0,0 @@ -info('Start!'); - Artisan::call('clear-compiled'); - $this->info('Cleared compiled...'); - Artisan::call('ide-helper:generate'); - $this->info('IDE helper, done...'); - Artisan::call('ide-helper:models'); - $this->info('IDE models, done...'); - Artisan::call('optimize'); - $this->info('Optimized...'); - Artisan::call('dump-autoload'); - $this->info('Done!'); - } - - /** - * Get the console command arguments. - * - * @return array - */ - protected function getArguments() - { - return [ - // ['example', InputArgument::REQUIRED, 'An example argument.'], - ]; - } - - /** - * Get the console command options. - * - * @return array - */ - protected function getOptions() - { - return [ - // ['example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null], - ]; - } - -} diff --git a/app/config/.gitignore b/app/config/.gitignore deleted file mode 100644 index 10601ce198..0000000000 --- a/app/config/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -local/ -laptop/ -vagrant/ -production/ diff --git a/app/config/app.php b/app/config/app.php deleted file mode 100644 index 4771579bbb..0000000000 --- a/app/config/app.php +++ /dev/null @@ -1,91 +0,0 @@ - false, - 'url' => 'http://localhost', - 'timezone' => 'UTC', - 'locale' => 'en', - 'fallback_locale' => 'en', - 'log_level' => 'notice', - 'key' => 'D93oqmVsIARg23FC3cbsHuBGk0uXQc3r', - 'cipher' => MCRYPT_RIJNDAEL_128, - 'providers' => [ - - 'Illuminate\Foundation\Providers\ArtisanServiceProvider', - 'Illuminate\Auth\AuthServiceProvider', - 'Illuminate\Cache\CacheServiceProvider', - 'Illuminate\Session\CommandsServiceProvider', - 'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider', - 'Illuminate\Routing\ControllerServiceProvider', - 'Illuminate\Cookie\CookieServiceProvider', - 'Illuminate\Database\DatabaseServiceProvider', - 'Illuminate\Encryption\EncryptionServiceProvider', - 'Illuminate\Filesystem\FilesystemServiceProvider', - 'Illuminate\Hashing\HashServiceProvider', - 'Illuminate\Html\HtmlServiceProvider', - 'Illuminate\Log\LogServiceProvider', - 'Illuminate\Mail\MailServiceProvider', - 'Illuminate\Database\MigrationServiceProvider', - 'Illuminate\Pagination\PaginationServiceProvider', - 'Illuminate\Queue\QueueServiceProvider', - 'Illuminate\Redis\RedisServiceProvider', - 'Illuminate\Remote\RemoteServiceProvider', - 'Illuminate\Auth\Reminders\ReminderServiceProvider', - 'Illuminate\Database\SeedServiceProvider', - 'Illuminate\Session\SessionServiceProvider', - 'Illuminate\Translation\TranslationServiceProvider', - 'Illuminate\Validation\ValidationServiceProvider', - 'Illuminate\View\ViewServiceProvider', - 'Illuminate\Workbench\WorkbenchServiceProvider', - //'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider', - //'Barryvdh\Debugbar\ServiceProvider', - 'FireflyIII\FF3ServiceProvider', - 'DaveJamesMiller\Breadcrumbs\ServiceProvider', - 'Grumpydictator\Gchart\GchartServiceProvider', - ], - 'manifest' => storage_path() . '/meta', - 'aliases' => [ - - 'App' => 'Illuminate\Support\Facades\App', - 'Artisan' => 'Illuminate\Support\Facades\Artisan', - 'Auth' => 'Illuminate\Support\Facades\Auth', - 'Blade' => 'Illuminate\Support\Facades\Blade', - 'Cache' => 'Illuminate\Support\Facades\Cache', - 'ClassLoader' => 'Illuminate\Support\ClassLoader', - 'Config' => 'Illuminate\Support\Facades\Config', - 'Controller' => 'Illuminate\Routing\Controller', - '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', - 'Form' => 'Illuminate\Support\Facades\Form', - 'Hash' => 'Illuminate\Support\Facades\Hash', - 'HTML' => 'Illuminate\Support\Facades\HTML', - 'Input' => 'Illuminate\Support\Facades\Input', - 'Lang' => 'Illuminate\Support\Facades\Lang', - 'Log' => 'Illuminate\Support\Facades\Log', - 'Mail' => 'Illuminate\Support\Facades\Mail', - 'Paginator' => 'Illuminate\Support\Facades\Paginator', - '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', - 'Seeder' => 'Illuminate\Database\Seeder', - 'Session' => 'Illuminate\Support\Facades\Session', - 'SoftDeletingTrait' => 'Illuminate\Database\Eloquent\SoftDeletingTrait', - 'SSH' => 'Illuminate\Support\Facades\SSH', - 'Str' => 'Illuminate\Support\Str', - 'URL' => 'Illuminate\Support\Facades\URL', - 'Validator' => 'Illuminate\Support\Facades\Validator', - 'View' => 'Illuminate\Support\Facades\View', - 'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade' - - ], - -]; diff --git a/app/config/auth.php b/app/config/auth.php deleted file mode 100644 index 6e606f0ebe..0000000000 --- a/app/config/auth.php +++ /dev/null @@ -1,16 +0,0 @@ - 'eloquent', - 'model' => 'User', - 'table' => 'users', - 'reminder' => [ - 'email' => 'emails.auth.reminder', - 'table' => 'password_reminders', - 'expire' => 60, - ], - 'verify_mail' => true, - 'verify_reset' => true, - 'allow_register' => true - -]; diff --git a/app/config/cache.php b/app/config/cache.php deleted file mode 100644 index 8fa089055b..0000000000 --- a/app/config/cache.php +++ /dev/null @@ -1,12 +0,0 @@ - 'file', - 'path' => storage_path() . '/cache', - 'connection' => null, - 'table' => 'cache', - 'memcached' => [ - ['host' => '127.0.0.1', 'port' => 11211, 'weight' => 100], - ], - 'prefix' => 'laravel', -]; diff --git a/app/config/compile.php b/app/config/compile.php deleted file mode 100644 index 0b67a5fe47..0000000000 --- a/app/config/compile.php +++ /dev/null @@ -1,3 +0,0 @@ - PDO::FETCH_CLASS, - 'default' => 'mysql', - 'connections' => [ - 'mysql' => [ - 'driver' => 'mysql', - 'host' => 'localhost', - 'database' => 'forge', - 'username' => 'forge', - 'password' => '', - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - ], - ], - 'migrations' => 'migrations', - 'redis' => [ - - 'cluster' => false, - - 'default' => [ - 'host' => '127.0.0.1', - 'port' => 6379, - 'database' => 0, - ], - - ], - -]; diff --git a/app/config/dev.php b/app/config/dev.php deleted file mode 100644 index a5f5e8f277..0000000000 --- a/app/config/dev.php +++ /dev/null @@ -1,4 +0,0 @@ - '' -]; diff --git a/app/config/firefly.php b/app/config/firefly.php deleted file mode 100644 index c17ca873e3..0000000000 --- a/app/config/firefly.php +++ /dev/null @@ -1,49 +0,0 @@ - ['1D', '1W', '1M', '3M', '6M', '1Y', 'custom'], - 'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'], - 'piggy_bank_periods' => [ - 'week' => 'Week', - 'month' => 'Month', - 'quarter' => 'Quarter', - 'year' => 'Year' - ], - 'periods_to_text' => [ - 'weekly' => 'A week', - 'monthly' => 'A month', - 'quarterly' => 'A quarter', - 'half-year' => 'Six months', - 'yearly' => 'A year', - ], - - 'accountRoles' => [ - 'defaultExpense' => 'Default expense account', - 'sharedExpense' => 'Shared expense account' - ], - - 'range_to_text' => [ - '1D' => 'day', - '1W' => 'week', - '1M' => 'month', - '3M' => 'three months', - '6M' => 'half year', - 'custom' => '(custom)' - ], - 'range_to_name' => [ - '1D' => 'one day', - '1W' => 'one week', - '1M' => 'one month', - '3M' => 'three months', - '6M' => 'six months', - '1Y' => 'one year', - ], - 'range_to_repeat_freq' => [ - '1D' => 'weekly', - '1W' => 'weekly', - '1M' => 'monthly', - '3M' => 'quarterly', - '6M' => 'half-year', - 'custom' => 'monthly' - ], -]; diff --git a/app/config/homestead/app.php b/app/config/homestead/app.php deleted file mode 100644 index 0f1dd6a103..0000000000 --- a/app/config/homestead/app.php +++ /dev/null @@ -1,15 +0,0 @@ - true, - 'log_level' => 'debug', -]; diff --git a/app/config/homestead/cache.php b/app/config/homestead/cache.php deleted file mode 100644 index 8fa089055b..0000000000 --- a/app/config/homestead/cache.php +++ /dev/null @@ -1,12 +0,0 @@ - 'file', - 'path' => storage_path() . '/cache', - 'connection' => null, - 'table' => 'cache', - 'memcached' => [ - ['host' => '127.0.0.1', 'port' => 11211, 'weight' => 100], - ], - 'prefix' => 'laravel', -]; diff --git a/app/config/homestead/database.php b/app/config/homestead/database.php deleted file mode 100644 index d585027ae3..0000000000 --- a/app/config/homestead/database.php +++ /dev/null @@ -1,37 +0,0 @@ - 'mysql', - 'connections' => [ - - 'mysql' => [ - 'driver' => 'mysql', - 'host' => 'localhost', - 'database' => 'homestead', - 'username' => 'homestead', - 'password' => 'secret', - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - ], - 'sqlite' => [ - 'driver' => 'sqlite', - 'database' => realpath(__DIR__.'/../../../tests/_data/testing.sqlite'), - 'prefix' => '' - ], - - 'pgsql' => [ - 'driver' => 'pgsql', - 'host' => 'localhost', - 'database' => 'homestead', - 'username' => 'homestead', - 'password' => 'secret', - 'charset' => 'utf8', - 'prefix' => '', - 'schema' => 'public', - ], - - ], - -]; diff --git a/app/config/homestead/mail.php b/app/config/homestead/mail.php deleted file mode 100644 index 28ee90f10c..0000000000 --- a/app/config/homestead/mail.php +++ /dev/null @@ -1,13 +0,0 @@ - 'smtp', - 'host' => 'smtp.gmail.com', - 'port' => 587, - 'from' => ['address' => 'empty@example.com', 'name' => 'Firefly III'], - 'encryption' => 'tls', - 'username' => 'empty@example.com', - 'password' => '', - 'sendmail' => '/usr/sbin/sendmail -bs', - 'pretend' => false, -]; diff --git a/app/config/mail.php b/app/config/mail.php deleted file mode 100644 index 9fe35072ad..0000000000 --- a/app/config/mail.php +++ /dev/null @@ -1,13 +0,0 @@ - 'smtp', - 'host' => '', - 'port' => 587, - 'from' => ['address' => '', 'name' => 'Firefly III'], - 'encryption' => 'tls', - 'username' => '', - 'password' => '', - 'sendmail' => '/usr/sbin/sendmail -bs', - 'pretend' => false, -]; diff --git a/app/config/packages/barryvdh/laravel-debugbar/config.php b/app/config/packages/barryvdh/laravel-debugbar/config.php deleted file mode 100644 index 3baf4b799a..0000000000 --- a/app/config/packages/barryvdh/laravel-debugbar/config.php +++ /dev/null @@ -1,127 +0,0 @@ - Config::get('app.debug'), - - 'storage' => [ - 'enabled' => true, - 'path' => storage_path() . '/debugbar', - ], - - /* - |-------------------------------------------------------------------------- - | Vendors - |-------------------------------------------------------------------------- - | - | Vendor files are included by default, but can be set to false. - | This can also be set to 'js' or 'css', to only include javascript or css vendor files. - | Vendor files are for css: font-awesome (including fonts) and highlight.js (css files) - | and for js: jquery and and highlight.js - | So if you want syntax highlighting, set it to true. - | jQuery is set to not conflict with existing jQuery scripts. - | - */ - - 'include_vendors' => true, - - /* - |-------------------------------------------------------------------------- - | Capture Ajax Requests - |-------------------------------------------------------------------------- - | - | The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors), - | you can use this option to disable sending the data through the headers. - | - */ - - 'capture_ajax' => true, - - /* - |-------------------------------------------------------------------------- - | Capture Console Commands - |-------------------------------------------------------------------------- - | - | The Debugbar can listen to Artisan commands. You can view them with the browse button in the Debugbar. - | - */ - - 'capture_console' => false, - - /* - |-------------------------------------------------------------------------- - | DataCollectors - |-------------------------------------------------------------------------- - | - | Enable/disable DataCollectors - | - */ - - 'collectors' => [ - 'phpinfo' => true, // Php version - 'messages' => true, // Messages - 'time' => true, // Time Datalogger - 'memory' => true, // Memory usage - 'exceptions' => true, // Exception displayer - 'log' => true, // Logs from Monolog (merged in messages if enabled) - 'db' => true, // Show database (PDO) queries and bindings - 'views' => true, // Views with their data - 'route' => true, // Current route information - 'laravel' => false, // Laravel version and environment - 'events' => false, // All events fired - 'default_request' => false, // Regular or special Symfony request logger - 'symfony_request' => true, // Only one can be enabled.. - 'mail' => true, // Catch mail messages - 'logs' => false, // Add the latest log messages - 'files' => false, // Show the included files - 'config' => false, // Display config settings - 'auth' => false, // Display Laravel authentication status - ], - - /* - |-------------------------------------------------------------------------- - | Extra options - |-------------------------------------------------------------------------- - | - | Configure some DataCollectors - | - */ - - 'options' => [ - 'auth' => [ - 'show_name' => false, // Also show the users name/email in the debugbar - ], - 'db' => [ - 'with_params' => true, // Render SQL with the parameters substituted - 'timeline' => false, // Add the queries to the timeline - ], - 'mail' => [ - 'full_log' => false - ], - 'views' => [ - 'data' => false, //Note: Can slow down the application, because the data can be quite large.. - ], - 'route' => [ - 'label' => true // show complete route on bar - ], - 'logs' => [ - 'file' => null - ], - ], - - /* - |-------------------------------------------------------------------------- - | Inject Debugbar in Response - |-------------------------------------------------------------------------- - | - | Usually, the debugbar is added just before , by listening to the - | Response after the App is done. If you disable this, you have to add them - | in your template yourself. See http://phpdebugbar.com/docs/rendering.html - | - */ - - 'inject' => true, - -]; diff --git a/app/config/packages/barryvdh/laravel-ide-helper/config.php b/app/config/packages/barryvdh/laravel-ide-helper/config.php deleted file mode 100644 index a49a469e62..0000000000 --- a/app/config/packages/barryvdh/laravel-ide-helper/config.php +++ /dev/null @@ -1,76 +0,0 @@ - '_ide_helper.php', - - /* - |-------------------------------------------------------------------------- - | Helper files to include - |-------------------------------------------------------------------------- - | - | Include helper files. By default not included, but can be toggled with the - | -- helpers (-H) option. Extra helper files can be included. - | - */ - - 'include_helpers' => false, - - 'helper_files' => [ - base_path() . '/vendor/laravel/framework/src/Illuminate/Support/helpers.php', - ], - - /* - |-------------------------------------------------------------------------- - | Model locations to include - |-------------------------------------------------------------------------- - | - | Define in which directories the ide-helper:models command should look - | for models. - | - */ - - 'model_locations' => [ - 'app/models', - ], - - - /* - |-------------------------------------------------------------------------- - | Extra classes - |-------------------------------------------------------------------------- - | - | These implementations are not really extended, but called with magic functions - | - */ - - 'extra' => [ - 'Artisan' => ['Illuminate\Foundation\Artisan'], - 'Eloquent' => ['Illuminate\Database\Eloquent\Builder', 'Illuminate\Database\Query\Builder'], - 'Session' => ['Illuminate\Session\Store'], - ], - - 'magic' => [ - 'Log' => [ - 'debug' => 'Monolog\Logger::addDebug', - 'info' => 'Monolog\Logger::addInfo', - 'notice' => 'Monolog\Logger::addNotice', - 'warning' => 'Monolog\Logger::addWarning', - 'error' => 'Monolog\Logger::addError', - 'critical' => 'Monolog\Logger::addCritical', - 'alert' => 'Monolog\Logger::addAlert', - 'emergency' => 'Monolog\Logger::addEmergency', - ] - ] - - -]; diff --git a/app/config/packages/davejamesmiller/laravel-breadcrumbs/config.php b/app/config/packages/davejamesmiller/laravel-breadcrumbs/config.php deleted file mode 100644 index e58b40faa9..0000000000 --- a/app/config/packages/davejamesmiller/laravel-breadcrumbs/config.php +++ /dev/null @@ -1,5 +0,0 @@ - 'laravel-breadcrumbs::bootstrap3', -]; diff --git a/app/config/queue.php b/app/config/queue.php deleted file mode 100644 index 79da1ff9c7..0000000000 --- a/app/config/queue.php +++ /dev/null @@ -1,45 +0,0 @@ - 'sync', - 'connections' => [ - - 'sync' => [ - 'driver' => 'sync', - ], - - 'beanstalkd' => [ - 'driver' => 'beanstalkd', - 'host' => 'localhost', - 'queue' => 'default', - 'ttr' => 60, - ], - - 'sqs' => [ - 'driver' => 'sqs', - 'key' => 'your-public-key', - 'secret' => 'your-secret-key', - 'queue' => 'your-queue-url', - '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', - ], - - ], - 'failed' => [ - 'database' => 'mysql', 'table' => 'failed_jobs', - ], - -]; diff --git a/app/config/remote.php b/app/config/remote.php deleted file mode 100644 index 3104bf7e34..0000000000 --- a/app/config/remote.php +++ /dev/null @@ -1,21 +0,0 @@ - 'production', - 'connections' => [ - - 'production' => [ - 'host' => '', - 'username' => '', - 'password' => '', - 'key' => '', - 'keyphrase' => '', - 'root' => '/var/www', - ], - ], - 'groups' => [ - 'web' => ['production'] - - ], - -]; diff --git a/app/config/services.php b/app/config/services.php deleted file mode 100644 index c252b2be65..0000000000 --- a/app/config/services.php +++ /dev/null @@ -1,19 +0,0 @@ - [ - 'domain' => '', - 'secret' => '', - ], - - 'mandrill' => [ - 'secret' => '', - ], - - 'stripe' => [ - 'model' => 'User', - 'secret' => '', - ], - -]; diff --git a/app/config/session.php b/app/config/session.php deleted file mode 100644 index a41728b267..0000000000 --- a/app/config/session.php +++ /dev/null @@ -1,16 +0,0 @@ - 'file', - 'lifetime' => 120, - 'expire_on_close' => false, - 'files' => storage_path() . '/sessions', - 'connection' => null, - 'table' => 'sessions', - 'lottery' => [2, 100], - 'cookie' => 'firefly_session', - 'path' => '/', - 'domain' => null, - 'secure' => false, - -]; diff --git a/app/config/testing/app.php b/app/config/testing/app.php deleted file mode 100644 index 7f9d13d6fb..0000000000 --- a/app/config/testing/app.php +++ /dev/null @@ -1,2 +0,0 @@ - 'debug',]; diff --git a/app/config/testing/auth.php b/app/config/testing/auth.php deleted file mode 100644 index 0fe9e0172d..0000000000 --- a/app/config/testing/auth.php +++ /dev/null @@ -1,8 +0,0 @@ - false, - 'verify_reset' => true, - 'allow_register' => true - -]; diff --git a/app/config/testing/cache.php b/app/config/testing/cache.php deleted file mode 100644 index fef1e78b52..0000000000 --- a/app/config/testing/cache.php +++ /dev/null @@ -1,3 +0,0 @@ - 'array',]; diff --git a/app/config/testing/database.php b/app/config/testing/database.php deleted file mode 100644 index e0be6a4063..0000000000 --- a/app/config/testing/database.php +++ /dev/null @@ -1,12 +0,0 @@ - 'sqlite', - 'connections' => [ - 'sqlite' => [ - 'driver' => 'sqlite', - 'database' => realpath(__DIR__.'/../../../tests/_data/db.sqlite'), - 'prefix' => '' - ] - - ] -]; diff --git a/app/config/testing/mail.php b/app/config/testing/mail.php deleted file mode 100644 index d2df78f4cd..0000000000 --- a/app/config/testing/mail.php +++ /dev/null @@ -1,13 +0,0 @@ - 'smtp', - 'host' => '', - 'port' => 587, - 'from' => ['address' => '', 'name' => 'Firefly III'], - 'encryption' => 'tls', - 'username' => '', - 'password' => '', - 'sendmail' => '/usr/sbin/sendmail -bs', - 'pretend' => true, -]; diff --git a/app/config/testing/session.php b/app/config/testing/session.php deleted file mode 100644 index fef1e78b52..0000000000 --- a/app/config/testing/session.php +++ /dev/null @@ -1,3 +0,0 @@ - 'array',]; diff --git a/app/config/testingInMemory/app.php b/app/config/testingInMemory/app.php deleted file mode 100644 index 7f9d13d6fb..0000000000 --- a/app/config/testingInMemory/app.php +++ /dev/null @@ -1,2 +0,0 @@ - 'debug',]; diff --git a/app/config/testingInMemory/auth.php b/app/config/testingInMemory/auth.php deleted file mode 100644 index 0fe9e0172d..0000000000 --- a/app/config/testingInMemory/auth.php +++ /dev/null @@ -1,8 +0,0 @@ - false, - 'verify_reset' => true, - 'allow_register' => true - -]; diff --git a/app/config/testingInMemory/cache.php b/app/config/testingInMemory/cache.php deleted file mode 100644 index fef1e78b52..0000000000 --- a/app/config/testingInMemory/cache.php +++ /dev/null @@ -1,3 +0,0 @@ - 'array',]; diff --git a/app/config/testingInMemory/database.php b/app/config/testingInMemory/database.php deleted file mode 100644 index 06b50aa143..0000000000 --- a/app/config/testingInMemory/database.php +++ /dev/null @@ -1,12 +0,0 @@ - 'sqlite', - 'connections' => [ - 'sqlite' => [ - 'driver' => 'sqlite', - 'database' => ':memory:', - 'prefix' => '' - ] - - ] -]; diff --git a/app/config/testingInMemory/mail.php b/app/config/testingInMemory/mail.php deleted file mode 100644 index d2df78f4cd..0000000000 --- a/app/config/testingInMemory/mail.php +++ /dev/null @@ -1,13 +0,0 @@ - 'smtp', - 'host' => '', - 'port' => 587, - 'from' => ['address' => '', 'name' => 'Firefly III'], - 'encryption' => 'tls', - 'username' => '', - 'password' => '', - 'sendmail' => '/usr/sbin/sendmail -bs', - 'pretend' => true, -]; diff --git a/app/config/testingInMemory/session.php b/app/config/testingInMemory/session.php deleted file mode 100644 index fef1e78b52..0000000000 --- a/app/config/testingInMemory/session.php +++ /dev/null @@ -1,3 +0,0 @@ - 'array',]; diff --git a/app/config/view.php b/app/config/view.php deleted file mode 100644 index f3b156d455..0000000000 --- a/app/config/view.php +++ /dev/null @@ -1,6 +0,0 @@ - [__DIR__ . '/../views'], - 'pagination' => 'pagination::slider-3', -]; diff --git a/app/config/workbench.php b/app/config/workbench.php deleted file mode 100644 index 62c843d71d..0000000000 --- a/app/config/workbench.php +++ /dev/null @@ -1,6 +0,0 @@ - '', - 'email' => '', -]; diff --git a/app/controllers/AccountController.php b/app/controllers/AccountController.php deleted file mode 100644 index fb38a501c0..0000000000 --- a/app/controllers/AccountController.php +++ /dev/null @@ -1,233 +0,0 @@ - ['Default account', 'Asset account'], - 'expense' => ['Expense account', 'Beneficiary account'], - 'revenue' => ['Revenue account'], - ]; - - /** @var AccountRepository */ - protected $_repository; - - /** @var array */ - protected $_shortNamesByFullName - = [ - 'Default account' => 'asset', - 'Asset account' => 'asset', - 'Expense account' => 'expense', - 'Beneficiary account' => 'expense', - 'Revenue account' => 'revenue', - 'Cash account' => 'cash', - ]; - - /** @var array */ - protected $_subIconsByIdentifier - = [ - 'asset' => 'fa-money', - 'Asset account' => 'fa-money', - 'Default account' => 'fa-money', - 'Cash account' => 'fa-money', - 'expense' => 'fa-shopping-cart', - 'Expense account' => 'fa-shopping-cart', - 'Beneficiary account' => 'fa-shopping-cart', - 'revenue' => 'fa-download', - 'Revenue account' => 'fa-download', - ]; - /** @var array */ - protected $_subTitlesByIdentifier - = [ - 'asset' => 'Asset accounts', - 'expense' => 'Expense accounts', - 'revenue' => 'Revenue accounts', - ]; - - /** - * @param AccountRepository $repository - */ - public function __construct(AccountRepository $repository) - { - $this->_repository = $repository; - View::share('mainTitleIcon', 'fa-credit-card'); - View::share('title', 'Accounts'); - } - - /** - * @param $what - * - * @return \Illuminate\View\View - */ - public function create($what) - { - $subTitleIcon = $this->_subIconsByIdentifier[$what]; - $subTitle = 'Create a new ' . e($what) . ' account'; - - return View::make('accounts.create', compact('subTitleIcon', 'what', 'subTitle')); - } - - /** - * @param Account $account - * - * @return $this - */ - public function delete(Account $account) - { - $subTitle = 'Delete ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"'; - - return View::make('accounts.delete', compact('account', 'subTitle')); - } - - /** - * @param Account $account - * - * @return $this|\Illuminate\Http\RedirectResponse - */ - public function destroy(Account $account) - { - - $type = $account->accountType->type; - $typeName = $this->_shortNamesByFullName[$type]; - $name = $account->name; - - $this->_repository->destroy($account); - - Session::flash('success', 'The ' . e($typeName) . ' account "' . e($name) . '" was deleted.'); - - return Redirect::route('accounts.index', $typeName); - } - - /** - * @param Account $account - * - * @return $this - */ - public function edit(Account $account) - { - - $openingBalance = $this->_repository->openingBalanceTransaction($account); - $subTitleIcon = $this->_subIconsByIdentifier[$account->accountType->type]; - $subTitle = 'Edit ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"'; - $what = $this->_shortNamesByFullName[$account->accountType->type]; - - // pre fill some useful values. - $preFilled = [ - 'account_role' => $account->getMeta('accountRole'), - 'openingBalanceDate' => $openingBalance ? $openingBalance->date->format('Y-m-d') : null, - 'openingBalance' => $openingBalance ? $openingBalance->getAmount($account) : null - ]; - Session::flash('preFilled', $preFilled); - - return View::make('accounts.edit', compact('account', 'what', 'subTitle', 'openingBalance', 'subTitleIcon')); - } - - /** - * - * @param string $what - * - * @return View - * @throws FireflyException - */ - public function index($what = 'default') - { - $subTitle = $this->_subTitlesByIdentifier[$what]; - $subTitleIcon = $this->_subIconsByIdentifier[$what]; - - $accounts = $this->_repository->getAccountsByType($this->_accountTypesByIdentifier[$what]); - - return View::make('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts')); - } - - /** - * @param Account $account - * @param string $range - * - * @return $this - */ - public function show(Account $account, $range = 'session') - { - $subTitleIcon = $this->_subIconsByIdentifier[$account->accountType->type]; - $what = $this->_shortNamesByFullName[$account->accountType->type]; - $journals = $this->_repository->getTransactionJournals($account, 50, $range); - $subTitle = 'Details for ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"'; - - return View::make('accounts.show', compact('account', 'what', 'range', 'subTitleIcon', 'journals', 'subTitle')); - } - - /** - * @return $this|\Illuminate\Http\RedirectResponse - * @throws FireflyException - */ - public function store() - { - $data = Input::except('_token'); - $messages = $this->_repository->validate($data); - - - // flash messages: - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not store account: ' . $messages['errors']->first()); - } - - // return to create screen: - if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { - return Redirect::route('accounts.create', e($data['what']))->withInput(); - } - - // store - $this->_repository->store($data); - Session::flash('success', 'Account "' . e($data['name']) . '" stored.'); - if ($data['post_submit_action'] == 'store') { - return Redirect::route('accounts.index', e($data['what'])); - } - - return Redirect::route('accounts.create', e($data['what']))->withInput(); - } - - /** - * @param Account $account - * - * @return $this - * @throws FireflyException - */ - public function update(Account $account) - { - $data = Input::except('_token'); - $messages = $this->_repository->validate($data); - - // flash messages: - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not update account: ' . $messages['errors']->first()); - } - - // return to update screen: - if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { - return Redirect::route('accounts.edit', $account->id)->withInput(); - } - - // update - $this->_repository->update($account, $data); - Session::flash('success', 'Account "' . e($data['name']) . '" updated.'); - - // go back to list - if ($data['post_submit_action'] == 'update') { - return Redirect::route('accounts.index', e($data['what'])); - } - - // go back to update screen. - return Redirect::route('accounts.edit', $account->id)->withInput(['post_submit_action' => 'return_to_edit']); - } -} diff --git a/app/controllers/BaseController.php b/app/controllers/BaseController.php deleted file mode 100644 index df09e3091d..0000000000 --- a/app/controllers/BaseController.php +++ /dev/null @@ -1,30 +0,0 @@ -layout)) { - $this->layout = View::make($this->layout); - } - } - -} diff --git a/app/controllers/BillController.php b/app/controllers/BillController.php deleted file mode 100644 index 0fdd0f7309..0000000000 --- a/app/controllers/BillController.php +++ /dev/null @@ -1,215 +0,0 @@ -_repository = $repository; - - View::share('title', 'Bills'); - View::share('mainTitleIcon', 'fa-calendar-o'); - } - - /** - * @return $this - */ - public function create() - { - $periods = \Config::get('firefly.periods_to_text'); - - return View::make('bills.create')->with('periods', $periods)->with('subTitle', 'Create new'); - } - - /** - * @param Bill $bill - * - * @return $this - */ - public function delete(Bill $bill) - { - return View::make('bills.delete')->with('bill', $bill)->with( - 'subTitle', 'Delete "' . e($bill->name) . '"' - ); - } - - /** - * @param Bill $bill - * - * @return \Illuminate\Http\RedirectResponse - */ - public function destroy(Bill $bill) - { - $this->_repository->destroy($bill); - Session::flash('success', 'The bill was deleted.'); - - return Redirect::route('bills.index'); - - } - - /** - * @param Bill $bill - * - * @return $this - */ - public function edit(Bill $bill) - { - $periods = \Config::get('firefly.periods_to_text'); - - return View::make('bills.edit')->with('periods', $periods)->with('bill', $bill)->with( - 'subTitle', 'Edit "' . e($bill->name) . '"' - ); - } - - /** - * @return $this - */ - public function index() - { - $bills = $this->_repository->get(); - $bills->each( - function (Bill $bill) { - $bill->nextExpectedMatch = $this->_repository->nextExpectedMatch($bill); - $bill->lastFoundMatch = $this->_repository->lastFoundMatch($bill); - } - ); - - return View::make('bills.index', compact('bills')); - } - - /** - * @param Bill $bill - * - * @return mixed - */ - public function rescan(Bill $bill) - { - if (intval($bill->active) == 0) { - Session::flash('warning', 'Inactive bills cannot be scanned.'); - - return Redirect::intended('/'); - } - - $this->_repository->scanEverything($bill); - - Session::flash('success', 'Rescanned everything.'); - - return Redirect::intended('/'); - } - - /** - * @param Bill $bill - * - * @return mixed - */ - public function show(Bill $bill) - { - $journals = $bill->transactionjournals()->withRelevantData()->orderBy('date', 'DESC')->get(); - $bill->nextExpectedMatch = $this->_repository->nextExpectedMatch($bill); - $hideBill = true; - - - return View::make('bills.show', compact('journals', 'hideBill', 'bill'))->with( - 'subTitle', e($bill->name) - ); - } - - /** - * @return $this - * @throws FireflyException - */ - public function store() - { - $data = Input::except(['_token', 'post_submit_action']); - $data['user_id'] = Auth::user()->id; - - - // always validate: - $messages = $this->_repository->validate($data); - - // flash messages: - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not store bill: ' . $messages['errors']->first()); - - return Redirect::route('bills.create')->withInput(); - } - - // return to create screen: - if (Input::get('post_submit_action') == 'validate_only') { - return Redirect::route('bills.create')->withInput(); - } - - // store - $this->_repository->store($data); - Session::flash('success', 'Bill "' . e($data['name']) . '" stored.'); - if (Input::get('post_submit_action') == 'store') { - return Redirect::route('bills.index'); - } - - return Redirect::route('bills.create')->withInput(); - - } - - /** - * @param Bill $bill - * - * @return $this - * @throws FireflyException - */ - public function update(Bill $bill) - { - $data = Input::except('_token'); - $data['active'] = intval(Input::get('active')); - $data['automatch'] = intval(Input::get('automatch')); - $data['user_id'] = Auth::user()->id; - - // always validate: - $messages = $this->_repository->validate($data); - - // flash messages: - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not update bill: ' . $messages['errors']->first()); - - return Redirect::route('bills.edit', $bill->id)->withInput(); - } - - // return to update screen: - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('bills.edit', $bill->id)->withInput(); - } - - // update - $this->_repository->update($bill, $data); - Session::flash('success', 'Bill "' . e($data['name']) . '" updated.'); - - // go back to list - if ($data['post_submit_action'] == 'update') { - return Redirect::route('bills.index'); - } - - // go back to update screen. - return Redirect::route('bills.edit', $bill->id)->withInput(['post_submit_action' => 'return_to_edit']); - - } -} diff --git a/app/controllers/BudgetController.php b/app/controllers/BudgetController.php deleted file mode 100644 index 5a42967adc..0000000000 --- a/app/controllers/BudgetController.php +++ /dev/null @@ -1,254 +0,0 @@ -_repository = $repository; - $this->_preferences = $preferences; - View::share('title', 'Budgets'); - View::share('mainTitleIcon', 'fa-tasks'); - } - - /** - * @param Budget $budget - * - * @return \Illuminate\Http\JsonResponse - * @throws Exception - */ - public function amount(Budget $budget) - { - $amount = intval(Input::get('amount')); - $date = Session::get('start', Carbon::now()->startOfMonth()); - $limitRepetition = $this->_repository->updateLimitAmount($budget, $date, $amount); - - return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0]); - - } - - /** - * @return $this - */ - public function create() - { - return View::make('budgets.create')->with('subTitle', 'Create a new budget'); - } - - /** - * @param Budget $budget - * - * @return $this - */ - public function delete(Budget $budget) - { - $subTitle = 'Delete budget "' . e($budget->name) . '"'; - - return View::make('budgets.delete', compact('budget', 'subTitle')); - } - - /** - * @param Budget $budget - * - * @return \Illuminate\Http\RedirectResponse - */ - public function destroy(Budget $budget) - { - Session::flash('success', 'Budget "' . e($budget->name) . '" was deleted.'); - $this->_repository->destroy($budget); - - - return Redirect::route('budgets.index'); - - } - - /** - * @param Budget $budget - * - * @return $this - */ - public function edit(Budget $budget) - { - $subTitle = 'Edit budget "' . e($budget->name) . '"'; - - return View::make('budgets.edit', compact('budget', 'subTitle')); - - } - - /** - * The index of the budget controller contains all budgets and the current relevant limit repetition. - * - * @return $this - */ - public function index() - { - $budgets = $this->_repository->get(); - - // loop the budgets: - $budgets->each( - function (Budget $budget) { - $budget->spent = $this->_repository->spentInMonth($budget, \Session::get('start', Carbon::now()->startOfMonth())); - $budget->currentRep = $this->_repository->getRepetitionByDate($budget, \Session::get('start', Carbon::now()->startOfMonth())); - } - ); - - $spent = $budgets->sum('spent'); - $amount = $this->_preferences->get('budgetIncomeTotal' . \Session::get('start', Carbon::now()->startOfMonth())->format('FY'), 1000)->data; - $overspent = $spent > $amount; - $spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100); - $budgetMax = $this->_preferences->get('budgetMaximum', 1000); - $budgetMaximum = $budgetMax->data; - - return View::make('budgets.index', compact('budgetMaximum', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount')); - } - - /** - * @return \Illuminate\View\View - */ - public function noBudget() - { - $start = \Session::get('start', Carbon::now()->startOfMonth()); - $end = \Session::get('end', Carbon::now()->startOfMonth()); - $list = $this->_repository->journalsNoBudget($start, $end); - $subTitle = 'Transactions without a budget in ' . $start->format('F Y'); - - return View::make('budgets.noBudget', compact('list', 'subTitle')); - } - - /** - * @return \Illuminate\Http\RedirectResponse - */ - public function postUpdateIncome() - { - $this->_preferences->set('budgetIncomeTotal' . Session::get('start', Carbon::now()->startOfMonth())->format('FY'), intval(Input::get('amount'))); - - return Redirect::route('budgets.index'); - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @param Budget $budget - * @param LimitRepetition $repetition - * - * @return \Illuminate\View\View - */ - public function show(Budget $budget, LimitRepetition $repetition = null) - { - if (!is_null($repetition) && $repetition->budgetLimit->budget->id != $budget->id) { - return View::make('error')->with('message', 'Invalid selection.'); - } - - $hideBudget = true; // used in transaction list. - $journals = $this->_repository->getJournals($budget, $repetition); - $limits = $repetition ? [$repetition->budgetLimit] : $budget->budgetLimits()->orderBy('startdate', 'DESC')->get(); - $subTitle = $repetition ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name); - - return View::make('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle', 'hideBudget')); - } - - /** - * @return $this|\Illuminate\Http\RedirectResponse - */ - public function store() - { - $data = Input::except('_token'); - $data['user_id'] = Auth::user()->id; - - // always validate: - $messages = $this->_repository->validate($data); - - // flash messages: - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not validate budget: ' . $messages['errors']->first()); - return Redirect::route('budgets.create')->withInput(); - } - - // return to create screen: - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('budgets.create')->withInput(); - } - - // store - $this->_repository->store($data); - Session::flash('success', 'Budget "' . e($data['name']) . '" stored.'); - if ($data['post_submit_action'] == 'store') { - return Redirect::route('budgets.index'); - } - - // create another. - return Redirect::route('budgets.create')->withInput(); - } - - /** - * @param Budget $budget - * - * @return $this|\Illuminate\Http\RedirectResponse - */ - public function update(Budget $budget) - { - - $data = Input::except('_token'); - $data['user_id'] = Auth::user()->id; - - // always validate: - $messages = $this->_repository->validate($data); - - // flash messages: - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not update budget: ' . $messages['errors']->first()); - return Redirect::route('budgets.edit', $budget->id)->withInput(); - } - - // return to update screen: - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('budgets.edit', $budget->id)->withInput(); - } - - // update - $this->_repository->update($budget, $data); - Session::flash('success', 'Budget "' . e($data['name']) . '" updated.'); - - // go back to list - if ($data['post_submit_action'] == 'update') { - return Redirect::route('budgets.index'); - } - - return Redirect::route('budgets.edit', $budget->id)->withInput(['post_submit_action' => 'return_to_edit']); - } - - /** - * @return $this - */ - public function updateIncome() - { - $budgetAmount = $this->_preferences->get('budgetIncomeTotal' . Session::get('start', Carbon::now()->startOfMonth())->format('FY'), 1000); - - return View::make('budgets.income')->with('amount', $budgetAmount); - } -} diff --git a/app/controllers/CategoryController.php b/app/controllers/CategoryController.php deleted file mode 100644 index bc5d0846f1..0000000000 --- a/app/controllers/CategoryController.php +++ /dev/null @@ -1,189 +0,0 @@ -_repository = $repository; - } - - /** - * @return \Illuminate\View\View - */ - public function create() - { - return View::make('categories.create')->with('subTitle', 'Create a new category'); - } - - /** - * @return \Illuminate\View\View - */ - public function noCategory() - { - $start = \Session::get('start', Carbon::now()->startOfMonth()); - $end = \Session::get('end', Carbon::now()->startOfMonth()); - $list = $this->_repository->journalsNoCategory($start, $end); - $subTitle = 'Transactions without a category in ' . $start->format('F Y'); - - return View::make('categories.noCategory', compact('list', 'subTitle')); - } - - /** - * @param Category $category - * - * @return $this - */ - public function delete(Category $category) - { - return View::make('categories.delete')->with('category', $category)->with('subTitle', 'Delete category "' . e($category->name) . '"'); - } - - /** - * @param Category $category - * - * @return \Illuminate\Http\RedirectResponse - */ - public function destroy(Category $category) - { - Session::flash('success', 'Category "' . e($category->name) . '" was deleted.'); - $this->_repository->destroy($category); - - - return Redirect::route('categories.index'); - } - - /** - * @param Category $category - * - * @return $this - */ - public function edit(Category $category) - { - return View::make('categories.edit')->with('category', $category)->with('subTitle', 'Edit category "' . e($category->name) . '"'); - } - - /** - * @return $this - */ - public function index() - { - $categories = $this->_repository->get(); - - return View::make('categories.index', compact('categories')); - } - - /** - * @param Category $category - * - * @return $this - */ - public function show(Category $category) - { - $hideCategory = true; // used in list. - $journals = $this->_repository->getTransactionJournals($category, 50); - - return View::make('categories.show', compact('category', 'journals', 'hideCategory')); - } - - /** - * - * @return $this - * @throws FireflyException - */ - public function store() - { - $data = Input::except('_token'); - $data['user_id'] = Auth::user()->id; - - // always validate: - $messages = $this->_repository->validate($data); - - // flash messages: - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not store category: ' . $messages['errors']->first()); - return Redirect::route('categories.create')->withInput(); - } - - // return to create screen: - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('categories.create')->withInput(); - } - - // store - $this->_repository->store($data); - Session::flash('success', 'Category "' . e($data['name']) . '" stored.'); - if ($data['post_submit_action'] == 'store') { - return Redirect::route('categories.index'); - } - - return Redirect::route('categories.create')->withInput(); - } - - /** - * - * @param Category $category - * - * @return $this - * @throws FireflyException - */ - public function update(Category $category) - { - $data = Input::except('_token'); - $data['user_id'] = Auth::user()->id; - - // always validate: - $messages = $this->_repository->validate($data); - - // flash messages: - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not update category: ' . $messages['errors']->first()); - return Redirect::route('categories.edit', $category->id)->withInput(); - } - - // return to update screen: - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('categories.edit', $category->id)->withInput(); - } - - // update - $this->_repository->update($category, $data); - Session::flash('success', 'Category "' . e($data['name']) . '" updated.'); - - // go back to list - if ($data['post_submit_action'] == 'update') { - return Redirect::route('categories.index'); - } - - // go back to update screen. - return Redirect::route('categories.edit', $category->id)->withInput(['post_submit_action' => 'return_to_edit']); - - - } - - -} diff --git a/app/controllers/CurrencyController.php b/app/controllers/CurrencyController.php deleted file mode 100644 index 9b55132333..0000000000 --- a/app/controllers/CurrencyController.php +++ /dev/null @@ -1,199 +0,0 @@ -_repository = $repository; - - - View::share('title', 'Currencies'); - View::share('mainTitleIcon', 'fa-usd'); - } - - /** - * @return \Illuminate\View\View - */ - public function create() - { - $subTitleIcon = 'fa-plus'; - $subTitle = 'Create a new currency'; - - return View::make('currency.create', compact('subTitleIcon', 'subTitle')); - } - - /** - * @param TransactionCurrency $currency - * - * @return \Illuminate\Http\RedirectResponse - */ - public function defaultCurrency(TransactionCurrency $currency) - { - /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ - $preferences = App::make('FireflyIII\Shared\Preferences\Preferences'); - - $currencyPreference = $preferences->get('currencyPreference', 'EUR'); - $currencyPreference->data = $currency->code; - $currencyPreference->save(); - - Session::flash('success', $currency->name.' is now the default currency.'); - Cache::forget('FFCURRENCYSYMBOL'); - Cache::forget('FFCURRENCYCODE'); - - return Redirect::route('currency.index'); - - } - - /** - * @param TransactionCurrency $currency - * - * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View - */ - public function delete(TransactionCurrency $currency) - { - if ($currency->transactionJournals()->count() > 0) { - Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.'); - - return Redirect::route('currency.index'); - } - - - return View::make('currency.delete', compact('currency')); - } - - /** - * @param TransactionCurrency $currency - * - * @return \Illuminate\Http\RedirectResponse - */ - public function destroy(TransactionCurrency $currency) - { - Session::flash('success', 'Currency "' . e($currency->name) . '" deleted'); - - $this->_repository->destroy($currency); - - return Redirect::route('currency.index'); - } - - /** - * @param TransactionCurrency $currency - * - * @return \Illuminate\View\View - */ - public function edit(TransactionCurrency $currency) - { - $subTitleIcon = 'fa-pencil'; - $subTitle = 'Edit currency "' . e($currency->name) . '"'; - $currency->symbol = htmlentities($currency->symbol); - - return View::make('currency.edit', compact('currency', 'subTitle', 'subTitleIcon')); - - } - - /** - * @return \Illuminate\View\View - */ - public function index() - { - $currencies = $this->_repository->get(); - - /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ - $preferences = App::make('FireflyIII\Shared\Preferences\Preferences'); - - $currencyPreference = $preferences->get('currencyPreference', 'EUR'); - $defaultCurrency = $this->_repository->findByCode($currencyPreference->data); - - - return View::make('currency.index', compact('currencies', 'defaultCurrency')); - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @return $this|\Illuminate\Http\RedirectResponse - */ - public function store() - { - $data = Input::except('_token'); - - // always validate: - $messages = $this->_repository->validate($data); - - // flash messages: - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not store currency: ' . $messages['errors']->first()); - } - - // return to create screen: - if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { - return Redirect::route('currency.create')->withInput(); - } - - // store - $this->_repository->store($data); - Session::flash('success', 'Currency "' . e($data['name']) . '" stored.'); - if ($data['post_submit_action'] == 'store') { - return Redirect::route('currency.index'); - } - - return Redirect::route('currency.create')->withInput(); - - } - - /** - * @param TransactionCurrency $currency - * - * @return $this|\Illuminate\Http\RedirectResponse - */ - public function update(TransactionCurrency $currency) - { - $data = Input::except('_token'); - - // always validate: - $messages = $this->_repository->validate($data); - - // flash messages: - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not update currency: ' . $messages['errors']->first()); - return Redirect::route('currency.edit', $currency->id)->withInput(); - } - - // return to update screen: - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('currency.edit', $currency->id)->withInput(); - } - - // update - $this->_repository->update($currency, $data); - Session::flash('success', 'Currency "' . e($data['name']) . '" updated.'); - - // go back to list - if ($data['post_submit_action'] == 'update') { - return Redirect::route('currency.index'); - } - - return Redirect::route('currency.edit', $currency->id)->withInput(['post_submit_action' => 'return_to_edit']); - - } - -} diff --git a/app/controllers/GoogleChartController.php b/app/controllers/GoogleChartController.php deleted file mode 100644 index 4e882653b1..0000000000 --- a/app/controllers/GoogleChartController.php +++ /dev/null @@ -1,537 +0,0 @@ -_chart = $chart; - $this->_repository = $repository; - $this->_start = Session::get('start', Carbon::now()->startOfMonth()); - $this->_end = Session::get('end', Carbon::now()->endOfMonth()); - - } - - /** - * @param Account $account - * @param string $view - * - * @return \Illuminate\Http\JsonResponse - */ - public function accountBalanceChart(Account $account, $view = 'session') - { - $this->_chart->addColumn('Day of month', 'date'); - $this->_chart->addColumn('Balance for ' . $account->name, 'number'); - $this->_chart->addCertainty(1); - - $start = $this->_start; - $end = $this->_end; - $count = $account->transactions()->count(); - - if ($view == 'all' && $count > 0) { - $first = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy( - 'date', 'ASC' - )->first(['transaction_journals.date']); - $last = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy( - 'date', 'DESC' - )->first(['transaction_journals.date']); - $start = new Carbon($first->date); - $end = new Carbon($last->date); - } - - $current = clone $start; - - while ($end >= $current) { - $this->_chart->addRow(clone $current, Steam::balance($account, $current), false); - $current->addDay(); - } - - - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - */ - public function allAccountsBalanceChart() - { - $this->_chart->addColumn('Day of the month', 'date'); - - /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ - $preferences = App::make('FireflyIII\Shared\Preferences\Preferences'); - $pref = $preferences->get('frontPageAccounts', []); - - /** @var \FireflyIII\Database\Account\Account $acct */ - $acct = App::make('FireflyIII\Database\Account\Account'); - $accounts = count($pref->data) > 0 ? $acct->getByIds($pref->data) : $acct->getAccountsByType(['Default account', 'Asset account']); - - $index = 1; - /** @var Account $account */ - foreach ($accounts as $account) { - $this->_chart->addColumn('Balance for ' . $account->name, 'number'); - $this->_chart->addCertainty($index); - $index++; - } - $current = clone $this->_start; - $current->subDay(); - $today = Carbon::now(); - while ($this->_end >= $current) { - $row = [clone $current]; - $certain = $current < $today; - foreach ($accounts as $account) { - - $row[] = Steam::balance($account, $current); - $row[] = $certain; - } - $this->_chart->addRowArray($row); - $current->addDay(); - } - - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - - } - - /** - * @param int $year - * - * @return $this|\Illuminate\Http\JsonResponse - */ - public function allBudgetsAndSpending($year) - { - try { - new Carbon('01-01-' . $year); - } catch (Exception $e) { - return View::make('error')->with('message', 'Invalid year.'); - } - /** @var \FireflyIII\Database\Budget\Budget $budgetRepository */ - $budgetRepository = App::make('FireflyIII\Database\Budget\Budget'); - $budgets = $budgetRepository->get(); - $budgets->sortBy('name'); - $this->_chart->addColumn('Month', 'date'); - foreach ($budgets as $budget) { - $this->_chart->addColumn($budget->name, 'number'); - } - $start = Carbon::createFromDate(intval($year), 1, 1); - $end = clone $start; - $end->endOfYear(); - - - while ($start <= $end) { - $row = [clone $start]; - foreach ($budgets as $budget) { - $spent = $budgetRepository->spentInMonth($budget, $start); - //$repetition = $budgetRepository->repetitionOnStartingOnDate($budget, $start); - $row[] = $spent; - } - $this->_chart->addRowArray($row); - $start->addMonth(); - } - - - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - - } - - /** - * @return \Illuminate\Http\JsonResponse - */ - public function allBudgetsHomeChart() - { - $this->_chart->addColumn('Budget', 'string'); - $this->_chart->addColumn('Budgeted', 'number'); - $this->_chart->addColumn('Spent', 'number'); - - /** @var \FireflyIII\Database\Budget\Budget $bdt */ - $bdt = App::make('FireflyIII\Database\Budget\Budget'); - $budgets = $bdt->get(); - - /** @var Budget $budget */ - foreach ($budgets as $budget) { - - /** @var \LimitRepetition $repetition */ - $repetition = $bdt->repetitionOnStartingOnDate($budget, $this->_start); - if (is_null($repetition)) { // use the session start and end for our search query - $searchStart = $this->_start; - $searchEnd = $this->_end; - $limit = 0; // the limit is zero: - } else { - // use the limit's start and end for our search query - $searchStart = $repetition->startdate; - $searchEnd = $repetition->enddate; - $limit = floatval($repetition->amount); // the limit is the repetitions limit: - } - - $expenses = floatval($budget->transactionjournals()->before($searchEnd)->after($searchStart)->lessThan(0)->sum('amount')) * -1; - if ($expenses > 0) { - $this->_chart->addRow($budget->name, $limit, $expenses); - } - } - - $noBudgetSet = $bdt->expenseNoBudget($this->_start, $this->_end); - $sum = $noBudgetSet->sum('amount') * -1; - $this->_chart->addRow('No budget', 0, $sum); - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - } - - /** - * @return \Illuminate\Http\JsonResponse - */ - public function allCategoriesHomeChart() - { - $this->_chart->addColumn('Category', 'string'); - $this->_chart->addColumn('Spent', 'number'); - - // query! - $set = $this->_repository->getCategorySummary($this->_start, $this->_end); - - foreach ($set as $entry) { - $entry->name = strlen($entry->name) == 0 ? '(no category)' : $entry->name; - $this->_chart->addRow($entry->name, floatval($entry->sum)); - } - - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - - } - - /** - * @param Bill $bill - * - * @return \Illuminate\Http\JsonResponse - */ - public function billOverview(Bill $bill) - { - - $this->_chart->addColumn('Date', 'date'); - $this->_chart->addColumn('Max amount', 'number'); - $this->_chart->addColumn('Min amount', 'number'); - $this->_chart->addColumn('Current entry', 'number'); - - // get first transaction or today for start: - $first = $bill->transactionjournals()->orderBy('date', 'ASC')->first(); - if ($first) { - $start = $first->date; - } else { - $start = new Carbon; - } - $end = new Carbon; - while ($start <= $end) { - $result = $bill->transactionjournals()->before($end)->after($start)->first(); - if ($result) { - $amount = $result->getAmount(); - } else { - $amount = 0; - } - unset($result); - $this->_chart->addRow(clone $start, $bill->amount_max, $bill->amount_min, $amount); - $start = DateKit::addPeriod($start, $bill->repeat_freq, 0); - } - - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - - } - - /** - * - * @return \Illuminate\Http\JsonResponse - * @throws \FireflyIII\Exception\FireflyException - */ - public function billsOverview() - { - $paid = ['items' => [], 'amount' => 0]; - $unpaid = ['items' => [], 'amount' => 0]; - $this->_chart->addColumn('Name', 'string'); - $this->_chart->addColumn('Amount', 'number'); - - $set = $this->_repository->getBillsSummary($this->_start, $this->_end); - - foreach ($set as $entry) { - if (intval($entry->journalId) == 0) { - $unpaid['items'][] = $entry->name; - $unpaid['amount'] += floatval($entry->averageAmount); - } else { - $description = intval($entry->encrypted) == 1 ? Crypt::decrypt($entry->description) : $entry->description; - $paid['items'][] = $description; - $paid['amount'] += floatval($entry->actualAmount); - } - } - $this->_chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']); - $this->_chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']); - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - } - - /** - * - * @param Budget $budget - * @param LimitRepetition $repetition - * - * @return \Illuminate\Http\JsonResponse - */ - public function budgetLimitSpending(\Budget $budget, \LimitRepetition $repetition) - { - $start = clone $repetition->startdate; - $end = $repetition->enddate; - - $this->_chart->addColumn('Day', 'date'); - $this->_chart->addColumn('Left', 'number'); - - - $amount = $repetition->amount; - - while ($start <= $end) { - /* - * Sum of expenses on this day: - */ - $sum = floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($start)->sum('amount')); - $amount += $sum; - $this->_chart->addRow(clone $start, $amount); - $start->addDay(); - } - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - - } - - /** - * - * @param Budget $budget - * - * @param int $year - * - * @return \Illuminate\Http\JsonResponse - */ - public function budgetsAndSpending(Budget $budget, $year = 0) - { - /** @var \FireflyIII\Database\Budget\Budget $budgetRepository */ - $budgetRepository = App::make('FireflyIII\Database\Budget\Budget'); - - $this->_chart->addColumn('Month', 'date'); - $this->_chart->addColumn('Budgeted', 'number'); - $this->_chart->addColumn('Spent', 'number'); - if ($year == 0) { - // grab the first budgetlimit ever: - $firstLimit = $budget->budgetlimits()->orderBy('startdate', 'ASC')->first(); - if ($firstLimit) { - $start = new Carbon($firstLimit->startdate); - } else { - $start = Carbon::now()->startOfYear(); - } - - // grab the last budget limit ever: - $lastLimit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first(); - if ($lastLimit) { - $end = new Carbon($lastLimit->startdate); - } else { - $end = Carbon::now()->endOfYear(); - } - } else { - $start = Carbon::createFromDate(intval($year), 1, 1); - $end = clone $start; - $end->endOfYear(); - } - - while ($start <= $end) { - $spent = $budgetRepository->spentInMonth($budget, $start); - $repetition = $budgetRepository->repetitionOnStartingOnDate($budget, $start); - - if ($repetition) { - $budgeted = floatval($repetition->amount); - \Log::debug('Found a repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name . '!'); - } else { - \Log::debug('No repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name); - $budgeted = null; - } - $this->_chart->addRow(clone $start, $budgeted, $spent); - $start->addMonth(); - } - - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - - - } - - /** - * - * @param Category $component - * @param $year - * - * @return \Illuminate\Http\JsonResponse - */ - public function categoriesAndSpending(Category $component, $year) - { - try { - new Carbon('01-01-' . $year); - } catch (Exception $e) { - return View::make('error')->with('message', 'Invalid year.'); - } - - /** @var \FireflyIII\Database\Category\Category $categoryRepository */ - $categoryRepository = App::make('FireflyIII\Database\Category\Category'); - - $this->_chart->addColumn('Month', 'date'); - $this->_chart->addColumn('Budgeted', 'number'); - $this->_chart->addColumn('Spent', 'number'); - - $start = new Carbon('01-01-' . $year); - $end = clone $start; - $end->endOfYear(); - while ($start <= $end) { - - $spent = $categoryRepository->spentInMonth($component, $start); - $budgeted = null; - - $this->_chart->addRow(clone $start, $budgeted, $spent); - - $start->addMonth(); - } - - - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - - - } - - /** - * @param PiggyBank $piggyBank - * - * @return \Illuminate\Http\JsonResponse - */ - public function piggyBankHistory(\PiggyBank $piggyBank) - { - $this->_chart->addColumn('Date', 'date'); - $this->_chart->addColumn('Balance', 'number'); - - $set = \DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]); - - foreach ($set as $entry) { - $this->_chart->addRow(new Carbon($entry->date), floatval($entry->sum)); - } - - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - - } - - /** - * - * @param $year - * - * @return \Illuminate\Http\JsonResponse - */ - public function yearInExp($year) - { - try { - $start = new Carbon('01-01-' . $year); - } catch (Exception $e) { - return View::make('error')->with('message', 'Invalid year.'); - } - $this->_chart->addColumn('Month', 'date'); - $this->_chart->addColumn('Income', 'number'); - $this->_chart->addColumn('Expenses', 'number'); - - /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ - $repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); - - $end = clone $start; - $end->endOfYear(); - while ($start < $end) { - - // total income: - $income = $repository->getSumOfIncomesByMonth($start); - $expense = $repository->getSumOfExpensesByMonth($start); - - $this->_chart->addRow(clone $start, $income, $expense); - $start->addMonth(); - } - - - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - - } - - /** - * - * @param $year - * - * @return \Illuminate\Http\JsonResponse - */ - public function yearInExpSum($year) - { - try { - $start = new Carbon('01-01-' . $year); - } catch (Exception $e) { - return View::make('error')->with('message', 'Invalid year.'); - } - $this->_chart->addColumn('Summary', 'string'); - $this->_chart->addColumn('Income', 'number'); - $this->_chart->addColumn('Expenses', 'number'); - - /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ - $repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); - - $end = clone $start; - $end->endOfYear(); - $income = 0; - $expense = 0; - $count = 0; - while ($start < $end) { - - // total income: - $income += $repository->getSumOfIncomesByMonth($start); - $expense += $repository->getSumOfExpensesByMonth($start); - $count++; - - $start->addMonth(); - } - $this->_chart->addRow('Sum', $income, $expense); - $count = $count > 0 ? $count : 1; - $this->_chart->addRow('Average', ($income / $count), ($expense / $count)); - - - $this->_chart->generate(); - - return Response::json($this->_chart->getData()); - - } -} diff --git a/app/controllers/HomeController.php b/app/controllers/HomeController.php deleted file mode 100644 index b9e15a285a..0000000000 --- a/app/controllers/HomeController.php +++ /dev/null @@ -1,101 +0,0 @@ -countAccountsByType(['Default account', 'Asset account']); - - $start = Session::get('start', Carbon::now()->startOfMonth()); - $end = Session::get('end', Carbon::now()->endOfMonth()); - - - // get the preference for the home accounts to show: - $frontPage = $preferences->get('frontPageAccounts', []); - if ($frontPage->data == []) { - $accounts = $acct->getAccountsByType(['Default account', 'Asset account']); - } else { - $accounts = $acct->getByIds($frontPage->data); - } - - $transactions = []; - foreach ($accounts as $account) { - $set = $journalRepository->getInDateRangeAccount($account, $start, $end, 10); - if (count($set) > 0) { - $transactions[] = [$set, $account]; - } - } - - // build the home screen: - return View::make('index')->with('count', $count)->with('transactions', $transactions)->with('title', 'Firefly')->with('subTitle', 'What\'s playing?') - ->with('mainTitleIcon', 'fa-fire'); - } - - /** - * @param $range - * - * @return \Illuminate\Http\RedirectResponse - */ - public function rangeJump($range) - { - - $valid = ['1D', '1W', '1M', '3M', '6M', '1Y',]; - - /** @var \FireflyIII\Shared\Preferences\PreferencesInterface $preferences */ - $preferences = App::make('FireflyIII\Shared\Preferences\PreferencesInterface'); - - if (in_array($range, $valid)) { - $preferences->set('viewRange', $range); - Session::forget('range'); - } - return Redirect::to(URL::previous()); - } - - /** - * @return \Illuminate\Http\RedirectResponse - */ - public function sessionNext() - { - Navigation::next(); - return Redirect::to(URL::previous()); - - } - - /** - * @return \Illuminate\Http\RedirectResponse - */ - public function sessionPrev() - { - Navigation::prev(); - return Redirect::to(URL::previous()); - } -} diff --git a/app/controllers/PreferencesController.php b/app/controllers/PreferencesController.php deleted file mode 100644 index d0d62d797d..0000000000 --- a/app/controllers/PreferencesController.php +++ /dev/null @@ -1,75 +0,0 @@ -getAccountsByType(['Default account', 'Asset account']); - $viewRange = $preferences->get('viewRange', '1M'); - $viewRangeValue = $viewRange->data; - $frontPage = $preferences->get('frontPageAccounts', []); - $budgetMax = $preferences->get('budgetMaximum', 1000); - $budgetMaximum = $budgetMax->data; - - return View::make('preferences.index', compact('budgetMaximum'))->with('accounts', $accounts)->with('frontPageAccounts', $frontPage)->with( - 'viewRange', $viewRangeValue - ); - } - - /** - * @return \Illuminate\Http\RedirectResponse - */ - public function postIndex() - { - /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ - $preferences = App::make('FireflyIII\Shared\Preferences\Preferences'); - - // front page accounts - $frontPageAccounts = []; - foreach (Input::get('frontPageAccounts') as $id) { - $frontPageAccounts[] = intval($id); - } - $preferences->set('frontPageAccounts', $frontPageAccounts); - - // view range: - $preferences->set('viewRange', Input::get('viewRange')); - // forget session values: - Session::forget('start'); - Session::forget('end'); - Session::forget('range'); - - // budget maximum: - $budgetMaximum = intval(Input::get('budgetMaximum')); - $preferences->set('budgetMaximum', $budgetMaximum); - - - Session::flash('success', 'Preferences saved!'); - - return Redirect::route('preferences'); - } - -} diff --git a/app/controllers/ReminderController.php b/app/controllers/ReminderController.php deleted file mode 100644 index 7b34fadb04..0000000000 --- a/app/controllers/ReminderController.php +++ /dev/null @@ -1,93 +0,0 @@ -remindersable); - - if ($class == 'PiggyBank') { - $amount = Reminders::amountForReminder($reminder); - $preFilled = [ - 'amount' => round($amount, 2), - 'description' => 'Money for ' . $reminder->remindersable->name, - 'piggy_bank_id' => $reminder->remindersable_id, - 'account_to_id' => $reminder->remindersable->account_id - ]; - Session::flash('preFilled', $preFilled); - - return Redirect::route('transactions.create', 'transfer'); - } - - return View::make('error')->with('message', 'This reminder has an invalid class connected to it.'); - } - - /** - * @param Reminder $reminder - * - * @return \Illuminate\Http\RedirectResponse - */ - public function dismiss(Reminder $reminder) - { - $reminder->active = 0; - $reminder->save(); - Session::flash('success', 'Reminder dismissed'); - - return Redirect::route('index'); - } - - /** - * @param Reminder $reminder - * - * @return \Illuminate\Http\RedirectResponse - */ - public function notNow(Reminder $reminder) - { - $reminder->active = 0; - $reminder->notnow = 1; - $reminder->save(); - Session::flash('success', 'Reminder dismissed'); - - return Redirect::route('index'); - } - - /** - * @param Reminder $reminder - * - * @return \Illuminate\View\View - */ - public function show(Reminder $reminder) - { - - $amount = null; - if (get_class($reminder->remindersable) == 'PiggyBank') { - - $amount = Reminders::amountForReminder($reminder); - } - - return View::make('reminders.show', compact('reminder', 'amount')); - } - -} diff --git a/app/controllers/RepeatedExpenseController.php b/app/controllers/RepeatedExpenseController.php deleted file mode 100644 index 73494b0377..0000000000 --- a/app/controllers/RepeatedExpenseController.php +++ /dev/null @@ -1,227 +0,0 @@ -_repository = $repository; - } - - /** - * @return $this - */ - public function create() - { - /** @var \FireflyIII\Database\Account\Account $acct */ - $acct = App::make('FireflyIII\Database\Account\Account'); - $periods = Config::get('firefly.piggy_bank_periods'); - $accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account'])); - - return View::make('repeatedExpense.create', compact('accounts', 'periods'))->with('subTitle', 'Create new repeated expense')->with( - 'subTitleIcon', 'fa-plus' - ); - } - - /** - * @param PiggyBank $repeatedExpense - * - * @return $this - */ - public function delete(PiggyBank $repeatedExpense) - { - $subTitle = 'Delete "' . e($repeatedExpense->name) . '"'; - - return View::make('repeatedExpense.delete', compact('repeatedExpense', 'subTitle')); - } - - /** - * @param PiggyBank $repeatedExpense - * - * @return \Illuminate\Http\RedirectResponse - */ - public function destroy(PiggyBank $repeatedExpense) - { - - Session::flash('success', 'Repeated expense "' . e($repeatedExpense->name) . '" deleted.'); - $this->_repository->destroy($repeatedExpense); - - return Redirect::route('repeated.index'); - } - - /** - * @param PiggyBank $repeatedExpense - * - * @return $this - */ - public function edit(PiggyBank $repeatedExpense) - { - - /** @var \FireflyIII\Database\Account\Account $acct */ - $acct = App::make('FireflyIII\Database\Account\Account'); - - $periods = Config::get('firefly.piggy_bank_periods'); - $accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account'])); - $subTitle = 'Edit repeated expense "' . e($repeatedExpense->name) . '"'; - $subTitleIcon = 'fa-pencil'; - - /* - * Flash some data to fill the form. - */ - $preFilled = ['name' => $repeatedExpense->name, - 'account_id' => $repeatedExpense->account_id, - 'targetamount' => $repeatedExpense->targetamount, - 'targetdate' => $repeatedExpense->targetdate->format('Y-m-d'), - 'reminder' => $repeatedExpense->reminder, - 'remind_me' => intval($repeatedExpense->remind_me) == 1 || !is_null($repeatedExpense->reminder) ? true : false - ]; - Session::flash('preFilled', $preFilled); - - return View::make('repeatedExpense.edit', compact('subTitle', 'subTitleIcon', 'repeatedExpense', 'accounts', 'periods', 'preFilled')); - } - - /** - * @return \Illuminate\View\View - */ - public function index() - { - - $subTitle = 'Overview'; - - $expenses = $this->_repository->get(); - $expenses->each( - function (PiggyBank $piggyBank) { - $piggyBank->currentRelevantRep(); - } - ); - - return View::make('repeatedExpense.index', compact('expenses', 'subTitle')); - } - - /** - * @param PiggyBank $repeatedExpense - * - * @return \Illuminate\View\View - */ - public function show(PiggyBank $repeatedExpense) - { - $subTitle = $repeatedExpense->name; - $today = Carbon::now(); - $repetitions = $repeatedExpense->piggyBankRepetitions()->get(); - - $repetitions->each( - function (PiggyBankRepetition $repetition) { - $repetition->bars = $this->_repository->calculateParts($repetition); - } - ); - - return View::make('repeatedExpense.show', compact('repetitions', 'repeatedExpense', 'today', 'subTitle')); - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - */ - public function store() - { - $data = Input::all(); - $data['repeats'] = 1; - $data['user_id'] = Auth::user()->id; - $targetDate = new Carbon($data['targetdate']); - $startDate = \DateKit::subtractPeriod($targetDate, $data['rep_length']); - $data['startdate'] = $startDate->format('Y-m-d'); - $data['targetdate'] = $targetDate->format('Y-m-d'); - $data['reminder_skip'] = 0; - $data['remind_me'] = isset($data['remind_me']) ? 1 : 0; - $data['order'] = 0; - - $messages = $this->_repository->validate($data); - - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not store repeated expense: ' . $messages['errors']->first()); - return Redirect::route('repeated.create')->withInput(); - } - - - // return to create screen: - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('repeated.create')->withInput(); - } - - // store - $piggyBank = $this->_repository->store($data); - Event::fire('piggy_bank.store', [$piggyBank]); // new and used. - Session::flash('success', 'Piggy bank "' . e($data['name']) . '" stored.'); - if ($data['post_submit_action'] == 'store') { - return Redirect::route('repeated.index'); - } - - return Redirect::route('repeated.create')->withInput(); - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @param PiggyBank $repeatedExpense - * - * @return $this - * @throws FireflyException - */ - public function update(PiggyBank $repeatedExpense) - { - - $data = Input::except('_token'); - $data['rep_every'] = 0; - $data['reminder_skip'] = 0; - $data['order'] = 0; - $data['repeats'] = 1; - $data['remind_me'] = isset($data['remind_me']) ? 1 : 0; - $data['user_id'] = Auth::user()->id; - - $messages = $this->_repository->validate($data); - - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not update repeated expense: ' . $messages['errors']->first()); - return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput(); - } - - // return to update screen: - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput(); - } - - // update - $this->_repository->update($repeatedExpense, $data); - Session::flash('success', 'Repeated expense "' . e($data['name']) . '" updated.'); - - // go back to list - if ($data['post_submit_action'] == 'update') { - return Redirect::route('repeated.index'); - } - - // go back to update screen. - return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput(['post_submit_action' => 'return_to_edit']); - - } -} diff --git a/app/controllers/ReportController.php b/app/controllers/ReportController.php deleted file mode 100644 index 6577ca5271..0000000000 --- a/app/controllers/ReportController.php +++ /dev/null @@ -1,136 +0,0 @@ -_journals = $journals; - $this->_repository = $repository; - /** @var \FireflyIII\Database\Budget\Budget _budgets */ - $this->_budgets = App::make('FireflyIII\Database\Budget\Budget'); - - - View::share('title', 'Reports'); - View::share('mainTitleIcon', 'fa-line-chart'); - - } - - /** - * @param string $year - * @param string $month - * - * @return \Illuminate\View\View - */ - public function budget($year = '2014', $month = '1') - { - try { - new Carbon($year . '-' . $month . '-01'); - } catch (Exception $e) { - return View::make('error')->with('message', 'Invalid date'); - } - $date = new Carbon($year . '-' . $month . '-01'); - $dayEarly = clone $date; - $subTitle = 'Budget report for ' . $date->format('F Y'); - $subTitleIcon = 'fa-calendar'; - $dayEarly = $dayEarly->subDay(); - $accounts = $this->_repository->getAccountListBudgetOverview($date); - $budgets = $this->_repository->getBudgetsForMonth($date); - - return View::make('reports.budget', compact('subTitle', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly')); - - } - - /** - * - */ - public function index() - { - $start = $this->_journals->firstDate(); - $months = $this->_repository->listOfMonths(clone $start); - $years = $this->_repository->listOfYears(clone $start); - $title = 'Reports'; - $mainTitleIcon = 'fa-line-chart'; - - return View::make('reports.index', compact('years', 'months', 'title', 'mainTitleIcon')); - } - - /** - * @param string $year - * @param string $month - * - * @return \Illuminate\View\View - */ - public function month($year = '2014', $month = '1') - { - try { - new Carbon($year . '-' . $month . '-01'); - } catch (Exception $e) { - return View::make('error')->with('message', 'Invalid date.'); - } - $date = new Carbon($year . '-' . $month . '-01'); - $subTitle = 'Report for ' . $date->format('F Y'); - $subTitleIcon = 'fa-calendar'; - $displaySum = true; // to show sums in report. - $income = $this->_repository->getIncomeForMonth($date); - $expenses = $this->_repository->getExpenseGroupedForMonth($date, 10); - $budgets = $this->_repository->getBudgetsForMonth($date); - $categories = $this->_repository->getCategoriesForMonth($date, 10); - $accounts = $this->_repository->getAccountsForMonth($date); - - return View::make( - 'reports.month', - compact('date', 'accounts', 'categories', 'budgets', 'expenses', 'subTitle', 'displaySum', 'subTitleIcon', 'income') - ); - } - - /** - * @param $year - * - * @return $this - */ - public function year($year) - { - try { - new Carbon('01-01-' . $year); - } catch (Exception $e) { - return View::make('error')->with('message', 'Invalid date.'); - } - $date = new Carbon('01-01-' . $year); - $end = clone $date; - $end->endOfYear(); - $title = 'Reports'; - $subTitle = $year; - $subTitleIcon = 'fa-bar-chart'; - $mainTitleIcon = 'fa-line-chart'; - - $balances = $this->_repository->yearBalanceReport($date); - $groupedIncomes = $this->_repository->revenueGroupedByAccount($date, $end); - $groupedExpenses = $this->_repository->expensesGroupedByAccount($date, $end, 15); - - return View::make( - 'reports.year', - compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon') - ); - } - -} diff --git a/app/controllers/TransactionController.php b/app/controllers/TransactionController.php deleted file mode 100644 index f1e6184fc1..0000000000 --- a/app/controllers/TransactionController.php +++ /dev/null @@ -1,328 +0,0 @@ -_repository = $repository; - $this->_helper = $helper; - View::share('title', 'Transactions'); - View::share('mainTitleIcon', 'fa-repeat'); - } - - - /** - * Shows the view helping the user to create a new transaction journal. - * - * @param string $what - * - * @return \Illuminate\View\View - */ - public function create($what = 'deposit') - { - $accounts = FFForm::makeSelectList($this->_helper->getAssetAccounts()); - $budgets = FFForm::makeSelectList($this->_helper->getBudgets()); - $budgets[0] = '(no budget)'; - $piggyBanks = $this->_helper->getPiggyBanks(); - $repeatedExpenses = $this->_helper->getRepeatedExpenses(); - $list = $piggyBanks->merge($repeatedExpenses); - $piggies = FFForm::makeSelectList($list); - $piggies[0] = '(no piggy bank)'; - $preFilled = Session::has('preFilled') ? Session::get('preFilled') : []; - $respondTo = ['account_id', 'account_from_id']; - $subTitle = 'Add a new ' . e($what); - - foreach ($respondTo as $r) { - if (!is_null(Input::get($r))) { - $preFilled[$r] = Input::get($r); - } - } - Session::put('preFilled', $preFilled); - - asort($piggies); - - - return View::make('transactions.create', compact('accounts', 'budgets', 'what', 'piggies', 'subTitle')); - } - - /** - * Shows the form that allows a user to delete a transaction journal. - * - * @param TransactionJournal $journal - * - * @return $this - */ - public function delete(TransactionJournal $journal) - { - $type = strtolower($journal->transactionType->type); - $subTitle = 'Delete ' . e($type) . ' "' . e($journal->description) . '"'; - - return View::make('transactions.delete', compact('journal', 'subTitle')); - - - } - - /** - * @param TransactionJournal $transactionJournal - * - * @return \Illuminate\Http\RedirectResponse - */ - public function destroy(TransactionJournal $transactionJournal) - { - $type = $transactionJournal->transactionType->type; - $return = 'withdrawal'; - - Session::flash('success', 'Transaction "' . e($transactionJournal->description) . '" destroyed.'); - - $this->_repository->destroy($transactionJournal); - - switch ($type) { - case 'Deposit': - $return = 'deposit'; - break; - case 'Transfer': - $return = 'transfers'; - break; - } - - return Redirect::route('transactions.index', $return); - } - - /** - * Shows the view to edit a transaction. - * - * @param TransactionJournal $journal - * - * @return $this - */ - public function edit(TransactionJournal $journal) - { - $what = strtolower($journal->transactiontype->type); - $subTitle = 'Edit ' . e($what) . ' "' . e($journal->description) . '"'; - $budgets = FFForm::makeSelectList($this->_helper->getBudgets(), true); - $accounts = FFForm::makeSelectList($this->_helper->getAssetAccounts()); - $piggies = FFForm::makeSelectList($this->_helper->getPiggyBanks(), true); - $transactions = $journal->transactions()->orderBy('amount', 'DESC')->get(); - $preFilled = [ - 'date' => $journal->date->format('Y-m-d'), - 'category' => '', - 'budget_id' => 0, - 'piggy_bank_id' => 0 - ]; - - $category = $journal->categories()->first(); - if (!is_null($category)) { - $preFilled['category'] = $category->name; - } - - $budget = $journal->budgets()->first(); - if (!is_null($budget)) { - $preFilled['budget_id'] = $budget->id; - } - - if ($journal->piggyBankEvents()->count() > 0) { - $preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->first()->piggy_bank_id; - } - - $preFilled['amount'] = $journal->getAmount(); - $preFilled['account_id'] = $this->_helper->getAssetAccount($what, $transactions); - $preFilled['expense_account'] = $transactions[0]->account->name; - $preFilled['revenue_account'] = $transactions[1]->account->name; - $preFilled['account_from_id'] = $transactions[1]->account->id; - $preFilled['account_to_id'] = $transactions[0]->account->id; - - - return View::make('transactions.edit', compact('journal', 'accounts', 'what', 'budgets', 'piggies', 'subTitle'))->with('data', $preFilled); - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's 7. More than 5 but alright. - * - * @param $what - * - * @return $this - */ - public function index($what) - { - switch ($what) { - case 'expenses': - case 'withdrawal': - $subTitleIcon = 'fa-long-arrow-left'; - $subTitle = 'Expenses'; - $journals = $this->_repository->getWithdrawalsPaginated(50); - break; - case 'revenue': - case 'deposit': - $subTitleIcon = 'fa-long-arrow-right'; - $subTitle = 'Revenue, income and deposits'; - $journals = $this->_repository->getDepositsPaginated(50); - break; - case 'transfer': - case 'transfers': - $subTitleIcon = 'fa-arrows-h'; - $subTitle = 'Transfers'; - $journals = $this->_repository->getTransfersPaginated(50); - break; - } - - return View::make('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals')); - - } - - - /** - * @param TransactionJournal $journal - * - * @return $this - */ - public function show(TransactionJournal $journal) - { - $journal->transactions->each( - function (\Transaction $t) use ($journal) { - $t->before = floatval( - $t->account->transactions()->leftJoin( - 'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id' - )->where('transaction_journals.date', '<=', $journal->date->format('Y-m-d'))->where( - 'transaction_journals.created_at', '<=', $journal->created_at->format('Y-m-d H:i:s') - )->where('transaction_journals.id', '!=', $journal->id)->sum('transactions.amount') - ); - $t->after = $t->before + $t->amount; - } - ); - $members = new Collection; - /** @var TransactionGroup $group */ - foreach ($journal->transactiongroups()->get() as $group) { - /** @var TransactionJournal $loopJournal */ - foreach ($group->transactionjournals()->get() as $loopJournal) { - if ($loopJournal->id != $journal->id) { - $members->push($loopJournal); - } - } - } - - return View::make('transactions.show', compact('journal', 'members'))->with( - 'subTitle', e($journal->transactionType->type) . ' "' . e($journal->description) . '"' - ); - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @param $what - * - * @return $this|\Illuminate\Http\RedirectResponse - * @throws FireflyException - */ - public function store($what) - { - $data = Input::except('_token'); - $transactionType = $this->_repository->getJournalType($what); - $transactionCurrency = $this->_repository->getJournalCurrencyById(intval($data['amount_currency_id'])); - $data['transaction_type_id'] = $transactionType->id; - $data['transaction_currency_id'] = $transactionCurrency->id; - $data['completed'] = 0; - $data['what'] = $what; - $messages = $this->_repository->validate($data); - - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not store transaction: ' . $messages['errors']->first()); - - return Redirect::route('transactions.create', $data['what'])->withInput(); - } - - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('transactions.create', $data['what'])->withInput(); - } - - $journal = $this->_repository->store($data); - Event::fire('transactionJournal.store', [$journal, Input::get('piggy_bank_id')]); // new and used. - - /** @var Transaction $transaction */ - foreach ($journal->transactions as $transaction) { - Event::fire('transaction.store', [$transaction]); - } - - Session::flash('success', 'Transaction "' . e($data['description']) . '" stored.'); - if ($data['post_submit_action'] == 'store') { - return Redirect::route('transactions.index', $data['what']); - } - - return Redirect::route('transactions.create', $data['what'])->withInput(); - } - - - /** - * @param TransactionJournal $journal - * - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @return $this - * @throws FireflyException - */ - public function update(TransactionJournal $journal) - { - $data = Input::except('_token'); - $data['what'] = strtolower($journal->transactionType->type); - $data['transaction_type_id'] = $journal->transaction_type_id; - $data['transaction_currency_id'] = intval($data['amount_currency_id']); - $data['completed'] = 1; - $messages = $this->_repository->validate($data); - - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('errors', $messages['errors']); - if ($messages['errors']->count() > 0) { - Session::flash('error', 'Could not update transaction: ' . $messages['errors']->first()); - - return Redirect::route('transactions.edit', $journal->id)->withInput(); - } - if ($data['post_submit_action'] == 'validate_only') { - return Redirect::route('transactions.edit', $journal->id)->withInput(); - } - $this->_repository->update($journal, $data); - Session::flash('success', 'Transaction "' . e($data['description']) . '" updated.'); - Event::fire('transactionJournal.update', [$journal]); // new and used. - /** @var Transaction $transaction */ - foreach ($journal->transactions()->get() as $transaction) { - Event::fire('transaction.update', [$transaction]); - } - if ($data['post_submit_action'] == 'update') { - return Redirect::route('transactions.index', $data['what']); - } - - // go back to update screen. - return Redirect::route('transactions.edit', $journal->id)->withInput(['post_submit_action' => 'return_to_edit']); - - - } - -} diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php deleted file mode 100644 index e4c96900f2..0000000000 --- a/app/controllers/UserController.php +++ /dev/null @@ -1,176 +0,0 @@ - Input::get('email'), 'password' => Input::get('password')]; - $result = Auth::attempt($data, $rememberMe); - if ($result) { - return Redirect::route('index'); - } - - Session::flash('error', 'No good!'); - - return View::make('user.login'); - } - - /** - * If allowed, register the user. - * - * Then: - * - * - Send password OR - * - Send reset code. - * - * @return $this|\Illuminate\View\View - */ - public function postRegister() - { - - /** @var \FireflyIII\Database\User\User $repository */ - $repository = App::make('FireflyIII\Database\User\User'); - - /** @var \FireflyIII\Shared\Mail\RegistrationInterface $email */ - $email = App::make('FireflyIII\Shared\Mail\RegistrationInterface'); - - $user = $repository->register(Input::all()); - - if ($user) { - $result = $email->sendVerificationMail($user); - if ($result === false && Config::get('mail.pretend') === false) { - // @codeCoverageIgnoreStart - $user->delete(); - - return View::make('error')->with('message', 'The email message could not be send. See the log files.'); - // @codeCoverageIgnoreEnd - } - - return View::make('user.verification-pending'); - } - - - return View::make('user.register'); - } - - /** - * If need to verify, send new reset code. - * Otherwise, send new password. - * - * @return \Illuminate\View\View - */ - public function postRemindMe() - { - - /** @var \FireflyIII\Database\User\User $repository */ - $repository = App::make('FireflyIII\Database\User\User'); - - /** @var \FireflyIII\Shared\Mail\RegistrationInterface $email */ - $email = App::make('FireflyIII\Shared\Mail\RegistrationInterface'); - - - $user = $repository->findByEmail(Input::get('email')); - if (!$user) { - Session::flash('error', 'No good!'); - - return View::make('user.remindMe'); - } - $email->sendResetVerification($user); - - return View::make('user.verification-pending'); - - } - - /** - * If allowed, show the register form. - * - * @return $this|\Illuminate\View\View - */ - public function register() - { - if ((Config::get('mail.from.address') == '@gmail.com' || Config::get('mail.from.address') == '') - && Config::get('mail.pretend') === false - ) { - return View::make('error')->with('message', 'Configuration error in app/config/' . App::environment() . '/mail.php'); - } - - return View::make('user.register'); - } - - /** - * Show form to help user get a new password. - * - * @return \Illuminate\View\View - */ - public function remindMe() - { - return View::make('user.remindMe'); - } - - /** - * Send a user a password based on his reset code. - * - * @param $reset - * - * @return $this|\Illuminate\View\View - */ - public function reset($reset) - { - - /** @var \FireflyIII\Database\User\User $repository */ - $repository = App::make('FireflyIII\Database\User\User'); - - /** @var \FireflyIII\Shared\Mail\RegistrationInterface $email */ - $email = App::make('FireflyIII\Shared\Mail\RegistrationInterface'); - - $user = $repository->findByReset($reset); - if ($user) { - $email->sendPasswordMail($user); - - return View::make('user.registered'); - } - - return View::make('error')->with('message', 'No reset code found!'); - } - -} diff --git a/app/database/migrations/2014_06_27_163259_create_accounts_table.php b/app/database/migrations/2014_06_27_163259_create_accounts_table.php deleted file mode 100644 index 3fb5541655..0000000000 --- a/app/database/migrations/2014_06_27_163259_create_accounts_table.php +++ /dev/null @@ -1,54 +0,0 @@ -increments('id'); - $table->timestamps(); - $table->softDeletes(); - $table->integer('user_id')->unsigned(); - $table->integer('account_type_id')->unsigned(); - $table->string('name', 100); - $table->boolean('active'); - - // connect accounts to users - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - - // connect accounts to account_types - $table->foreign('account_type_id')->references('id')->on('account_types')->onDelete('cascade'); - - // for a user, the account name must be unique. - $table->unique(['user_id', 'account_type_id', 'name']); - } - ); - } - -} diff --git a/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php b/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php deleted file mode 100644 index 67d527a66d..0000000000 --- a/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php +++ /dev/null @@ -1,60 +0,0 @@ -increments('id'); - $table->timestamps(); - $table->integer('account_id')->unsigned(); - $table->string('name', 100); - $table->decimal('targetamount', 10, 2); - $table->date('startdate')->nullable(); - $table->date('targetdate')->nullable(); - $table->boolean('repeats'); - $table->enum('rep_length', ['day', 'week', 'quarter', 'month', 'year'])->nullable(); - $table->smallInteger('rep_every')->unsigned(); - $table->smallInteger('rep_times')->unsigned()->nullable(); - $table->enum('reminder', ['day', 'week', 'quarter', 'month', 'year'])->nullable(); - $table->smallInteger('reminder_skip')->unsigned(); - $table->boolean('remind_me'); - $table->integer('order')->unsigned(); - - // connect account to piggy bank. - $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); - - // for an account, the name must be unique. - $table->unique(['account_id', 'name']); - - } - ); - } - -} diff --git a/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php b/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php deleted file mode 100644 index 724059c859..0000000000 --- a/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php +++ /dev/null @@ -1,59 +0,0 @@ -increments('id'); - $table->timestamps(); - $table->integer('user_id')->unsigned(); - $table->string('name', 50); - $table->string('match', 255); - $table->decimal('amount_min', 10, 2); - $table->decimal('amount_max', 10, 2); - $table->date('date'); - $table->boolean('active'); - - $table->boolean('automatch'); - $table->enum('repeat_freq', ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly']); - $table->smallInteger('skip')->unsigned(); - - // connect user id to users - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - - // for a user, the name must be unique - $table->unique(['user_id', 'name']); - - - } - ); - } - -} diff --git a/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php b/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php deleted file mode 100644 index 44ede35eb0..0000000000 --- a/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php +++ /dev/null @@ -1,62 +0,0 @@ -increments('id'); - $table->timestamps(); - $table->softDeletes(); - $table->integer('user_id')->unsigned(); - $table->integer('transaction_type_id')->unsigned(); - $table->integer('recurring_transaction_id')->unsigned()->nullable(); - $table->integer('transaction_currency_id')->unsigned(); - $table->string('description', 255)->nullable(); - $table->boolean('completed'); - $table->date('date'); - - // connect users - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - - // connect transaction journals to transaction types - $table->foreign('transaction_type_id')->references('id')->on('transaction_types')->onDelete('cascade'); - - // connect transaction journals to recurring transactions - $table->foreign('recurring_transaction_id')->references('id')->on('recurring_transactions')->onDelete('set null'); - - // connect transaction journals to transaction currencies - $table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('cascade'); - - - } - ); - } - -} diff --git a/app/database/migrations/2014_06_27_164836_create_transactions_table.php b/app/database/migrations/2014_06_27_164836_create_transactions_table.php deleted file mode 100644 index 66b2772534..0000000000 --- a/app/database/migrations/2014_06_27_164836_create_transactions_table.php +++ /dev/null @@ -1,60 +0,0 @@ -increments('id'); - $table->timestamps(); - $table->softDeletes(); - $table->integer('account_id')->unsigned(); - $table->integer('piggybank_id')->nullable()->unsigned(); - $table->integer('transaction_journal_id')->unsigned(); - $table->string('description', 255)->nullable(); - $table->decimal('amount', 10, 2); - - // connect account id: - $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); - - // connect piggy banks - $table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('set null'); - - // connect transactions to transaction journals - $table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade'); - - - - - - } - ); - } - -} diff --git a/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php b/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php deleted file mode 100644 index 8eebf01388..0000000000 --- a/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php +++ /dev/null @@ -1,51 +0,0 @@ -increments('id'); - $table->timestamps(); - $table->integer('piggybank_id')->unsigned(); - $table->integer('transaction_journal_id')->unsigned()->nullable(); - - $table->date('date'); - $table->decimal('amount', 10, 2); - - // connect instance to piggybank. - $table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('cascade'); - - // connect to journal: - $table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('set null'); - } - ); - } - -} diff --git a/app/database/migrations/2014_08_23_113221_create_reminders_table.php b/app/database/migrations/2014_08_23_113221_create_reminders_table.php deleted file mode 100644 index 1aaa49fb0a..0000000000 --- a/app/database/migrations/2014_08_23_113221_create_reminders_table.php +++ /dev/null @@ -1,50 +0,0 @@ -increments('id'); - $table->timestamps(); - $table->integer('user_id')->unsigned(); - $table->date('startdate'); - $table->date('enddate')->nullable(); - $table->boolean('active'); - $table->boolean('notnow')->default(0); - $table->integer('remindersable_id')->unsigned()->nullable(); - $table->string('remindersable_type')->nullable(); - - // connect reminders to users - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - } - ); - } - -} diff --git a/app/database/seeds/TransactionCurrencySeeder.php b/app/database/seeds/TransactionCurrencySeeder.php deleted file mode 100644 index 6bf2eb7010..0000000000 --- a/app/database/seeds/TransactionCurrencySeeder.php +++ /dev/null @@ -1,18 +0,0 @@ -delete(); - - TransactionCurrency::create(['code' => 'EUR','name' => 'Euro','symbol' => '€']); - TransactionCurrency::create(['code' => 'USD','name' => 'US Dollar','symbol' => '$']); - TransactionCurrency::create(['code' => 'HUF','name' => 'Hungarian forint','symbol' => 'Ft']); - } - -} diff --git a/app/filters.php b/app/filters.php deleted file mode 100644 index 27e9264440..0000000000 --- a/app/filters.php +++ /dev/null @@ -1,104 +0,0 @@ -with('message', 'Not possible'); - } -} -); diff --git a/app/lang/en/reminders.php b/app/lang/en/reminders.php deleted file mode 100644 index a416c65cb5..0000000000 --- a/app/lang/en/reminders.php +++ /dev/null @@ -1,24 +0,0 @@ - "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" => "Password reminder sent!", - -]; diff --git a/app/lib/FireflyIII/Chart/Chart.php b/app/lib/FireflyIII/Chart/Chart.php deleted file mode 100644 index 6d01ddaecd..0000000000 --- a/app/lib/FireflyIII/Chart/Chart.php +++ /dev/null @@ -1,76 +0,0 @@ -on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0); - } - ) - ->leftJoin( - 'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id' - ) - ->leftJoin('categories', 'categories.id', '=', 'category_transaction_journal.category_id') - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->before($end) - ->after($start) - ->where('transaction_types.type', 'Withdrawal') - ->groupBy('categories.id') - ->orderBy('sum', 'DESC') - ->get(['categories.id', 'categories.name', \DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]); - } - - /** - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function getBillsSummary(Carbon $start, Carbon $end) - { - return \Bill:: - leftJoin( - 'transaction_journals', function (JoinClause $join) use ($start, $end) { - $join->on('bills.id', '=', 'transaction_journals.bill_id') - ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d')); - } - ) - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '>', 0); - } - ) - ->where('active', 1) - ->groupBy('bills.id') - ->get( - ['bills.id', 'bills.name', 'transaction_journals.description', - 'transaction_journals.encrypted', - 'transaction_journals.id as journalId', - \DB::Raw('SUM(`bills`.`amount_min` + `bills`.`amount_max`) / 2 as `averageAmount`'), - 'transactions.amount AS actualAmount'] - ); - } -} diff --git a/app/lib/FireflyIII/Chart/ChartInterface.php b/app/lib/FireflyIII/Chart/ChartInterface.php deleted file mode 100644 index 62a2efa868..0000000000 --- a/app/lib/FireflyIII/Chart/ChartInterface.php +++ /dev/null @@ -1,31 +0,0 @@ -setUser(\Auth::user()); - } - - /** - * @param array $types - * - * @return int - */ - public function countAccountsByType(array $types) - { - return $this->getUser()->accounts()->accountTypeIn($types)->count(); - } - - /** - * @param array $types - * - * @return Collection - */ - public function getAccountsByType(array $types) - { - /* - * Basic query: - */ - $query = $this->getUser()->accounts()->accountTypeIn($types)->withMeta()->orderBy('name', 'ASC');; - $set = $query->get(['accounts.*', 'account_meta.data as accountRole']); - - $set->each( - function (\Account $account) { - /* - * Get last activity date. - */ - $account->lastActivityDate = $this->getLastActivity($account); - $account->accountRole = \Config::get('firefly.accountRoles.' . json_decode($account->accountRole)); - } - ); - - return $set; - } - - /** - * @param \Account $account - * - * @return \TransactionJournal|null - */ - public function openingBalanceTransaction(\Account $account) - { - - $first = \TransactionJournal::withRelevantData()->accountIs($account) - ->orderBy('transaction_journals.date', 'ASC') - ->orderBy('created_at', 'ASC') - ->first(['transaction_journals.*']); - $initial = strpos(strtolower($first->description), 'initial'); - $opening = strpos(strtolower($first->description), 'opening'); - if ($initial === false && $opening === false) { - return null; - } - - return $first; - - } - - /** - * @param \Account $account - * @param array $data - * - * @return bool - */ - public function storeInitialBalance(\Account $account, array $data) - { - /** @var \FireflyIII\Database\TransactionType\TransactionType $typeRepository */ - $typeRepository = \App::make('FireflyIII\Database\TransactionType\TransactionType'); - - /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $journals */ - $journals = \App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); - - // some initial variables: - $balance = floatval($data['openingBalance']); - $date = new Carbon($data['openingBalanceDate']); - - // some dynamic variables: - if ($balance < 0) { - $opposingType = 'expense'; - $transactionType = $typeRepository->findByWhat('withdrawal'); - $toAccount = $this->store(['name' => $account->name . ' Initial Balance Account', 'active' => 1, 'what' => $opposingType]); - $fromAccount = $account; - } else { - $opposingType = 'revenue'; - $transactionType = $typeRepository->findByWhat('deposit'); - $fromAccount = $this->store(['name' => $account->name . ' Initial Balance Account', 'active' => 1, 'what' => $opposingType]); - $toAccount = $account; - } - - // data for transaction journal: - $balance = $balance < 0 ? $balance * -1 : $balance; - $currency = $journals->getJournalCurrencyById(intval($data['balance_currency_id'])); - $opening = [ - 'transaction_type_id' => $transactionType->id, - 'transaction_currency_id' => $currency->id, - 'amount' => $balance, - 'what' => 'opening', - 'from' => $fromAccount, - 'completed' => 0, - 'to' => $toAccount, - 'date' => $date, - 'description' => 'Opening balance for new account ' . $account->name - ]; - - $validation = $journals->validate($opening); - if ($validation['errors']->count() == 0) { - $journals->store($opening); - - return true; - } else { - \Log::error('Initial balance created is not valid (Database/Account)'); - \Log::error($validation['errors']->all()); - \App::abort(500); - } - - return false; - } - - /** - * @param \Account $account - * - * @return int - */ - public function getLastActivity(\Account $account) - { - $lastActivityKey = 'account.' . $account->id . '.lastActivityDate'; - if (\Cache::has($lastActivityKey)) { - return \Cache::get($lastActivityKey); - } - - $transaction = $account->transactions() - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->orderBy('transaction_journals.date', 'DESC')->first(); - if ($transaction) { - $date = $transaction->transactionJournal->date; - } else { - $date = 0; - } - \Cache::forever($lastActivityKey, $date); - - return $date; - } - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) // cannot make it shorter because of query. - * @param Eloquent $model - * - * @return bool - */ - public function destroy(Eloquent $model) - { - $journals = \TransactionJournal::whereIn( - 'id', function (QueryBuilder $query) use ($model) { - $query->select('transaction_journal_id') - ->from('transactions') - ->whereIn( - 'account_id', function (QueryBuilder $query) use ($model) { - $query - ->select('accounts.id') - ->from('accounts') - ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') - ->where( - function (QueryBuilder $q) use ($model) { - $q->where('accounts.id', $model->id); - $q->orWhere( - function (QueryBuilder $q) use ($model) { - $q->where('accounts.name', 'LIKE', '%' . $model->name . '%'); - $q->where('account_types.type', 'Initial balance account'); - $q->where('accounts.active', 0); - } - ); - } - )->where('accounts.user_id', $this->getUser()->id); - } - )->get(); - } - )->get(); - $transactions = []; - /** @var \TransactionJournal $journal */ - foreach ($journals as $journal) { - /** @var \Transaction $t */ - foreach ($journal->transactions as $t) { - $transactions[] = intval($t->id); - } - $journal->delete(); - } - if (count($transactions) > 0) { - \Transaction::whereIn('id', $transactions)->delete(); - } - \Event::fire('account.destroy', [$model]); - - // get account type: - /** @var \FireflyIII\Database\AccountType\AccountType $acctType */ - $acctType = \App::make('FireflyIII\Database\AccountType\AccountType'); - - $accountType = $acctType->findByWhat('initial'); - - //$q->where('account_types.type', ''); - - \Account::where( - function (EloquentBuilder $q) use ($model, $accountType) { - $q->where('id', $model->id); - $q->orWhere( - function (EloquentBuilder $q) use ($model, $accountType) { - $q->where('accounts.name', 'LIKE', '%' . $model->name . '%'); - $q->where('accounts.account_type_id', $accountType->id); - $q->where('accounts.active', 0); - } - ); - } - )->delete(); - - return true; - - } - - /** - * @param array $data - * - * @return \Eloquent - */ - public function store(array $data) - { - - /** @var \FireflyIII\Database\AccountType\AccountType $acctType */ - $acctType = \App::make('FireflyIII\Database\AccountType\AccountType'); - - $accountType = $acctType->findByWhat($data['what']); - - $data['user_id'] = $this->getUser()->id; - $data['account_type_id'] = $accountType->id; - $data['active'] = isset($data['active']) && intval($data['active']) === 1 ? 1 : 0; - - $data = array_except($data, ['_token', 'what']); - $account = new \Account($data); - if (!$account->isValid()) { - \Log::error('Account created is not valid (Database/Account)'); - \Log::error($account->getErrors()->all()); - \App::abort(500); - } - $account->save(); - if (isset($data['openingBalance']) && floatval($data['openingBalance']) != 0) { - $this->storeInitialBalance($account, $data); - } - - switch ($account->accountType->type) { - case 'Asset account': - case 'Default account': - $account->updateMeta('accountRole', $data['account_role']); - break; - } - - - /* Tell transaction journal to store a new one.*/ - \Event::fire('account.store', [$account]); - - - return $account; - - } - - /** - * @param Eloquent $model - * @param array $data - * - * @return bool - */ - public function update(Eloquent $model, array $data) - { - $model->name = $data['name']; - $model->active = isset($data['active']) ? intval($data['active']) : 0; - - switch ($model->accountType->type) { - case 'Asset account': - case 'Default account': - $model->updateMeta('accountRole', $data['account_role']); - break; - } - - $model->save(); - - if (isset($data['openingBalance']) && isset($data['openingBalanceDate']) && strlen($data['openingBalanceDate']) > 0) { - $this->updateInitialBalance($model, $data); - - } - \Event::fire('account.update', [$model]); - - return true; - } - - /** - * Validates a model. Returns an array containing MessageBags - * errors/warnings/successes. - * - * @param array $model - * - * @return array - */ - public function validate(array $model) - { - $model['active'] = !isset($model['active']) ? false : $model['active']; - $successes = new MessageBag; - $account = new \Account($model); - $account->isValid('form_input', false); - $errors = $account->getErrors(); - - if (isset($model['account_role']) && !in_array($model['account_role'], array_keys(\Config::get('firefly.accountRoles')))) { - $errors->add('account_role', 'Invalid account role'); - } - /* - * Opening balance and opening balance date. - */ - if (isset($model['what']) && $model['what'] == 'asset') { - if (isset($model['openingBalance']) && strlen($model['openingBalance']) > 0 && !is_numeric($model['openingBalance'])) { - $errors->add('openingBalance', 'This is not a number.'); - } - if (isset($model['openingBalanceDate']) && strlen($model['openingBalanceDate']) > 0) { - try { - new Carbon($model['openingBalanceDate']); - } catch (\Exception $e) { - $errors->add('openingBalanceDate', 'This date is invalid.'); - } - } - } - $fields = ['name', 'openingBalance', 'openingBalanceDate', 'active', 'account_role']; - foreach ($fields as $field) { - if (!$errors->has($field)) { - $successes->add($field, 'OK'); - } - } - - return ['errors' => $errors, 'successes' => $successes]; - } - - /** - * @param Eloquent $model - * @param array $data - */ - public function updateInitialBalance(Eloquent $model, array $data) - { - /** @noinspection PhpParamsInspection */ - $openingBalance = $this->openingBalanceTransaction($model); - if (is_null($openingBalance)) { - $this->storeInitialBalance($model, $data); - } else { - $openingBalance->date = new Carbon($data['openingBalanceDate']); - $openingBalance->save(); - $amount = floatval($data['openingBalance']); - /** @var \Transaction $transaction */ - foreach ($openingBalance->transactions as $transaction) { - if ($transaction->account_id == $model->id) { - $transaction->amount = $amount; - } else { - $transaction->amount = $amount * -1; - } - $transaction->save(); - } - } - } - - /** - * Returns an object with id $id. - * - * @param int $objectId - * - * @return \Eloquent - */ - public function find($objectId) - { - return $this->getUser()->accounts()->find($objectId); - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @codeCoverageIgnore - * - * @param $what - * - * @throws NotImplementedException - * @return \AccountType|null - */ - public function findByWhat($what) - { - throw new NotImplementedException; - } - - /** - * Returns all objects. - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function get() - { - throw new NotImplementedException; - } - - /** - * @param array $ids - * - * @return Collection - */ - public function getByIds(array $ids) - { - return $this->getUser()->accounts()->whereIn('id', $ids)->get(); - } - - /** - * @param $name - * - * @return static - * @throws \FireflyIII\Exception\FireflyException - */ - public function firstExpenseAccountOrCreate($name) - { - /** @var \FireflyIII\Database\AccountType\AccountType $typeRepository */ - $typeRepository = \App::make('FireflyIII\Database\AccountType\AccountType'); - - $accountType = $typeRepository->findByWhat('expense'); - - // if name is "", find cash account: - if (strlen($name) == 0) { - $cashAccountType = $typeRepository->findByWhat('cash'); - - // find or create cash account: - return \Account::firstOrCreate( - ['name' => 'Cash account', 'account_type_id' => $cashAccountType->id, 'active' => 0, 'user_id' => $this->getUser()->id,] - ); - } - - $data = ['user_id' => $this->getUser()->id, 'account_type_id' => $accountType->id, 'name' => $name, 'active' => 1]; - - return \Account::firstOrCreate($data); - - } - - /** - * @param $name - * - * @return static - * @throws \FireflyIII\Exception\FireflyException - */ - public function firstRevenueAccountOrCreate($name) - { - /** @var \FireflyIII\Database\AccountType\AccountType $typeRepository */ - $typeRepository = \App::make('FireflyIII\Database\AccountType\AccountType'); - - $accountType = $typeRepository->findByWhat('revenue'); - - // if name is "", find cash account: - if (strlen($name) == 0) { - $cashAccountType = $typeRepository->findByWhat('cash'); - - // find or create cash account: - return \Account::firstOrCreate( - ['name' => 'Cash account', 'account_type_id' => $cashAccountType->id, 'active' => 0, 'user_id' => $this->getUser()->id,] - ); - } - - $data = ['user_id' => $this->getUser()->id, 'account_type_id' => $accountType->id, 'name' => $name, 'active' => 1]; - - return \Account::firstOrCreate($data); - - } - - /** - * @param \Account $account - * @param int $limit - * @param string $range - * - * @return \Illuminate\Pagination\Paginator - */ - public function getTransactionJournals(\Account $account, $limit = 50, $range = 'session') - { - $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0; - $items = []; - $query = $this->getUser() - ->transactionJournals() - ->withRelevantData() - ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') - ->where('transactions.account_id', $account->id) - ->orderBy('date', 'DESC'); - - if ($range == 'session') { - $query->before(\Session::get('end', Carbon::now()->startOfMonth())); - $query->after(\Session::get('start', Carbon::now()->startOfMonth())); - } - $count = $query->count(); - $set = $query->take($limit)->offset($offset)->get(['transaction_journals.*']); - - foreach ($set as $entry) { - $items[] = $entry; - } - - return \Paginator::make($items, $count, $limit); - - - } - -} diff --git a/app/lib/FireflyIII/Database/Account/AccountInterface.php b/app/lib/FireflyIII/Database/Account/AccountInterface.php deleted file mode 100644 index c9d21ba229..0000000000 --- a/app/lib/FireflyIII/Database/Account/AccountInterface.php +++ /dev/null @@ -1,48 +0,0 @@ - 'Expense account', - 'asset' => 'Asset account', - 'revenue' => 'Revenue account', - 'cash' => 'Cash account', - 'initial' => 'Initial balance account', - ]; - if (isset($typeMap[$what])) { - return \AccountType::whereType($typeMap[$what])->first(); - } - throw new FireflyException('Cannot find account type described as "' . e($what) . '".'); - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Returns all objects. - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function get() - { - throw new NotImplementedException; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param array $ids - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function getByIds(array $ids) - { - throw new NotImplementedException; - } -} diff --git a/app/lib/FireflyIII/Database/Bill/Bill.php b/app/lib/FireflyIII/Database/Bill/Bill.php deleted file mode 100644 index 642f5163a4..0000000000 --- a/app/lib/FireflyIII/Database/Bill/Bill.php +++ /dev/null @@ -1,356 +0,0 @@ -setUser(\Auth::user()); - } - - /** - * @param Eloquent $model - * - * @return bool - */ - public function destroy(Eloquent $model) - { - $model->delete(); - - return true; - } - - /** - * @param array $data - * - * @return \Eloquent - */ - public function store(array $data) - { - $bill = new \Bill; - $bill->user()->associate($this->getUser()); - $bill->name = $data['name']; - $bill->match = $data['match']; - $bill->amount_max = floatval($data['amount_max']); - $bill->amount_min = floatval($data['amount_min']); - - $date = new Carbon($data['date']); - - - $bill->active = intval($data['active']); - $bill->automatch = intval($data['automatch']); - $bill->repeat_freq = $data['repeat_freq']; - - /* - * Jump to the start of the period. - */ - $date = \DateKit::startOfPeriod($date, $data['repeat_freq']); - $bill->date = $date; - $bill->skip = intval($data['skip']); - - $bill->save(); - - return $bill; - } - - /** - * @param Eloquent $model - * @param array $data - * - * @return bool - */ - public function update(Eloquent $model, array $data) - { - $model->name = $data['name']; - $model->match = $data['match']; - $model->amount_max = floatval($data['amount_max']); - $model->amount_min = floatval($data['amount_min']); - - $date = new Carbon($data['date']); - - $model->date = $date; - $model->active = intval($data['active']); - $model->automatch = intval($data['automatch']); - $model->repeat_freq = $data['repeat_freq']; - $model->skip = intval($data['skip']); - $model->save(); - - return true; - } - - /** - * Validates an array. Returns an array containing MessageBags - * errors/warnings/successes. - * - * ignored because this method will be gone soon. - * - * @param array $model - * - * @return array - */ - public function validate(array $model) - { - $warnings = new MessageBag; - $successes = new MessageBag; - $errors = new MessageBag; - if (floatval($model['amount_min']) > floatval($model['amount_max'])) { - $errors->add('amount_max', 'Maximum amount can not be less than minimum amount.'); - $errors->add('amount_min', 'Minimum amount can not be more than maximum amount.'); - } - $object = new \Bill($model); - $object->isValid(); - $errors->merge($object->getErrors()); - - $set = ['name', 'match', 'amount_min', 'amount_max', 'date', 'repeat_freq', 'skip', 'automatch', 'active']; - foreach ($set as $entry) { - if (!$errors->has($entry)) { - $successes->add($entry, 'OK'); - } - } - - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Returns an object with id $id. - * - * @param int $objectId - * - * @return \Eloquent - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function find($objectId) - { - throw new NotImplementedException; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. - * - * @param $what - * - * @return \AccountType|null - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function findByWhat($what) - { - throw new NotImplementedException; - } - - /** - * Returns all objects. - * - * @return Collection - */ - public function get() - { - return $this->getUser()->bills()->orderBy('name')->get(); - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @param array $ids - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function getByIds(array $ids) - { - throw new NotImplementedException; - } - - /** - * @param \Bill $bill - * - * @return Carbon|null - */ - public function lastFoundMatch(\Bill $bill) - { - $last = $bill->transactionjournals()->orderBy('date', 'DESC')->first(); - if ($last) { - return $last->date; - } - - return null; - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @param \Bill $bill - * - * @return Carbon|null - */ - public function nextExpectedMatch(\Bill $bill) - { - $finalDate = null; - if ($bill->active == 0) { - return $finalDate; - } - - /* - * $today is the start of the next period, to make sure FF3 won't miss anything - * when the current period has a transaction journal. - */ - $today = \DateKit::addPeriod(new Carbon, $bill->repeat_freq, 0); - - $skip = $bill->skip + 1; - $start = \DateKit::startOfPeriod(new Carbon, $bill->repeat_freq); - /* - * go back exactly one month/week/etc because FF3 does not care about 'next' - * bills if they're too far into the past. - */ - - $counter = 0; - while ($start <= $today) { - if (($counter % $skip) == 0) { - // do something. - $end = \DateKit::endOfPeriod(clone $start, $bill->repeat_freq); - $journalCount = $bill->transactionjournals()->before($end)->after($start)->count(); - if ($journalCount == 0) { - $finalDate = clone $start; - break; - } - } - - // add period for next round! - $start = \DateKit::addPeriod($start, $bill->repeat_freq, 0); - $counter++; - } - - return $finalDate; - } - - /** - * @param \Bill $bill - * @param \TransactionJournal $journal - * - * @return bool - */ - public function scan(\Bill $bill, \TransactionJournal $journal) - { - /* - * Match words. - */ - $wordMatch = false; - $matches = explode(',', $bill->match); - $description = strtolower($journal->description); - - /* - * Attach expense account to description for more narrow matching. - */ - if (count($journal->transactions) < 2) { - $transactions = $journal->transactions()->get(); - } else { - $transactions = $journal->transactions; - } - /** @var \Transaction $transaction */ - foreach ($transactions as $transaction) { - /** @var \Account $account */ - $account = $transaction->account()->first(); - /** @var \AccountType $type */ - $type = $account->accountType()->first(); - if ($type->type == 'Expense account' || $type->type == 'Beneficiary account') { - $description .= ' ' . strtolower($account->name); - } - } - \Log::debug('Final description: ' . $description); - \Log::debug('Matches searched: ' . join(':', $matches)); - - $count = 0; - foreach ($matches as $word) { - if (!(strpos($description, strtolower($word)) === false)) { - $count++; - } - } - if ($count >= count($matches)) { - $wordMatch = true; - \Log::debug('word match is true'); - } - - - /* - * Match amount. - */ - - $amountMatch = false; - if (count($transactions) > 1) { - - $amount = max(floatval($transactions[0]->amount), floatval($transactions[1]->amount)); - $min = floatval($bill->amount_min); - $max = floatval($bill->amount_max); - if ($amount >= $min && $amount <= $max) { - $amountMatch = true; - \Log::debug('Amount match is true!'); - } - } - - /* - * If both, update! - */ - if ($wordMatch && $amountMatch) { - $journal->bill()->associate($bill); - $journal->save(); - } - } - - /** - * @param \Bill $bill - * - * @return bool - */ - public function scanEverything(\Bill $bill) - { - // get all journals that (may) be relevant. - // this is usually almost all of them. - - /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $journalRepository */ - $journalRepository = \App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); - - $set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max) - ->get(['transaction_journal_id']); - $ids = []; - - /** @var \Transaction $entry */ - foreach ($set as $entry) { - $ids[] = intval($entry->transaction_journal_id); - } - if (count($ids) > 0) { - $journals = $journalRepository->getByIds($ids); - /** @var \TransactionJournal $journal */ - foreach ($journals as $journal) { - $this->scan($bill, $journal); - } - } - - return true; - } -} diff --git a/app/lib/FireflyIII/Database/Bill/BillInterface.php b/app/lib/FireflyIII/Database/Bill/BillInterface.php deleted file mode 100644 index ec75dd1167..0000000000 --- a/app/lib/FireflyIII/Database/Bill/BillInterface.php +++ /dev/null @@ -1,43 +0,0 @@ -setUser(\Auth::user()); - } - - /** - * @param Eloquent $model - * - * @return bool - */ - public function destroy(Eloquent $model) - { - $model->delete(); - - return true; - } - - /** - * @param array $data - * - * @return \Eloquent - * @throws FireflyException - */ - public function store(array $data) - { - $budget = new \Budget($data); - - if (!$budget->isValid()) { - \Log::error('Could not store budget: ' . $budget->getErrors()->toJson()); - throw new FireflyException($budget->getErrors()->first()); - } - $budget->save(); - - return $budget; - } - - /** - * @param Eloquent $model - * @param array $data - * - * @return bool - */ - public function update(Eloquent $model, array $data) - { - $model->name = $data['name']; - $model->save(); - - return true; - } - - /** - * Validates an array. Returns an array containing MessageBags - * errors/warnings/successes. - * - * @param array $model - * - * @return array - */ - public function validate(array $model) - { - $warnings = new MessageBag; - $successes = new MessageBag; - $budget = new \Budget($model); - $budget->isValid(); - $errors = $budget->getErrors(); - - if (!$errors->has('name')) { - $successes->add('name', 'OK'); - } - - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; - } - - /** - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function expenseNoBudget(Carbon $start, Carbon $end) - { - // Add expenses that have no budget: - return $this->getUser() - ->transactionjournals() - ->whereNotIn( - 'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) { - $query - ->select('transaction_journals.id') - ->from('transaction_journals') - ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00')); - } - ) - ->before($end) - ->after($start) - ->lessThan(0) - ->transactionTypes(['Withdrawal']) - ->get(); - } - - /** - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function journalsNoBudget(Carbon $start, Carbon $end) - { - $set = $this->getUser() - ->transactionjournals() - ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->whereNull('budget_transaction_journal.id') - ->before($end) - ->after($start) - ->orderBy('transaction_journals.date') - ->get(['transaction_journals.*']); - - return $set; - } - - /** - * This method includes the time because otherwise, SQLite does not understand it. - * - * @param \Budget $budget - * @param Carbon $date - * - * @return \LimitRepetition|null - */ - public function repetitionOnStartingOnDate(\Budget $budget, Carbon $date) - { - return \LimitRepetition:: - leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') - ->where('limit_repetitions.startdate', $date->format('Y-m-d 00:00:00')) - ->where('budget_limits.budget_id', $budget->id) - ->first(['limit_repetitions.*']); - } - - /** - * Returns an object with id $id. - * - * @param int $objectId - * - * @return \Eloquent - */ - public function find($objectId) - { - return $this->getUser()->budgets()->find($objectId); - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. - * - * @param $what - * - * @return \AccountType|null - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function findByWhat($what) - { - throw new NotImplementedException; - } - - /** - * Returns all objects. - * - * @return Collection - */ - public function get() - { - $budgets = $this->getUser()->budgets()->get(); - - return $budgets; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param array $ids - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function getByIds(array $ids) - { - throw new NotImplementedException; - } - - /** - * Returns all the transaction journals for a limit, possibly limited by a limit repetition. - * - * @param \Budget $budget - * @param \LimitRepetition $repetition - * @param int $take - * - * @return \Illuminate\Pagination\Paginator - */ - public function getJournals(\Budget $budget, \LimitRepetition $repetition = null, $take = 50) - { - $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $take : 0; - - - $setQuery = $budget->transactionJournals()->withRelevantData()->take($take)->offset($offset)->orderBy('date', 'DESC'); - $countQuery = $budget->transactionJournals(); - - - if (!is_null($repetition)) { - $setQuery->after($repetition->startdate)->before($repetition->enddate); - $countQuery->after($repetition->startdate)->before($repetition->enddate); - } - - - $set = $setQuery->get(['transaction_journals.*']); - $count = $countQuery->count(); - $items = []; - foreach ($set as $entry) { - $items[] = $entry; - } - - return \Paginator::make($items, $count, $take); - } - - /** - * @param \Budget $budget - * @param Carbon $date - * - * @return \LimitRepetition - */ - public function getRepetitionByDate(\Budget $budget, Carbon $date) - { - return $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']); - } - - /** - * @param \Budget $budget - * @param Carbon $date - * - * @return float - */ - public function spentInMonth(\Budget $budget, Carbon $date) - { - $end = clone $date; - $date->startOfMonth(); - $end->endOfMonth(); - $sum = floatval($budget->transactionjournals()->before($end)->after($date)->lessThan(0)->sum('amount')) * -1; - - return $sum; - } - - /** - * This method updates the amount (envelope) for the given date and budget. This results in a (new) limit (aka an envelope) - * for that budget. Returned to the user is the new limit repetition. - * - * @param \Budget $budget - * @param Carbon $date - * @param $amount - * - * @return \LimitRepetition - * @throws \Exception - */ - public function updateLimitAmount(\Budget $budget, Carbon $date, $amount) - { - /** @var \BudgetLimit $limit */ - $limit = $this->limitOnStartingOnDate($budget, $date); - if (!$limit) { - // create one! - $limit = new \BudgetLimit; - $limit->budget()->associate($budget); - $limit->startdate = $date; - $limit->amount = $amount; - $limit->repeat_freq = 'monthly'; - $limit->repeats = 0; - $limit->save(); - \Log::info('ID: ' . $limit->id); - /* - * A newly stored limit also created a limit repetition. - */ - \Event::fire('limits.store', [$limit]); - } else { - if ($amount > 0) { - $limit->amount = $amount; - $limit->save(); - /* - * An updated limit also updates the associated limit repetitions. - */ - \Event::fire('limits.update', [$limit]); - } else { - $limit->delete(); - } - } - - return $limit->limitrepetitions()->first(); - - - } - - /** - * @param \Budget $budget - * @param Carbon $date - * - * @return \BudgetLimit - */ - public function limitOnStartingOnDate(\Budget $budget, Carbon $date) - { - return $budget->budgetLimits()->where('startdate', $date->format('Y-m-d 00:00:00'))->first(); - - - } -} diff --git a/app/lib/FireflyIII/Database/Budget/BudgetInterface.php b/app/lib/FireflyIII/Database/Budget/BudgetInterface.php deleted file mode 100644 index b81b786c85..0000000000 --- a/app/lib/FireflyIII/Database/Budget/BudgetInterface.php +++ /dev/null @@ -1,40 +0,0 @@ -setUser(\Auth::user()); - } - - /** - * @param Eloquent $model - * - * @return bool - */ - public function destroy(Eloquent $model) - { - $model->delete(); - - return true; - } - - /** - * @param array $data - * - * @return \Eloquent - * @throws FireflyException - */ - public function store(array $data) - { - $category = new \Category; - $category->name = $data['name']; - $category->user()->associate($this->getUser()); - if (!$category->isValid()) { - \Log::error('Could not store category: ' . $category->getErrors()->toJson()); - throw new FireflyException($category->getErrors()->first()); - } - $category->save(); - - return $category; - } - - /** - * @param Eloquent $model - * @param array $data - * - * @return bool - * @throws FireflyException - */ - public function update(Eloquent $model, array $data) - { - $model->name = $data['name']; - $model->save(); - - return true; - } - - /** - * Validates an array. Returns an array containing MessageBags - * errors/warnings/successes. - * - * @param array $model - * - * @return array - */ - public function validate(array $model) - { - $warnings = new MessageBag; - $successes = new MessageBag; - $category = new \Category($model); - $category->isValid(); - $errors = $category->getErrors(); - - if (!$errors->has('name')) { - $successes->add('name', 'OK'); - } - - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Returns an object with id $id. - * - * @param int $objectId - * - * @return \Eloquent - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function find($objectId) - { - throw new NotImplementedException; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. - * - * @param $what - * - * @return \AccountType|null - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function findByWhat($what) - { - throw new NotImplementedException; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Returns all objects. - * - * @return Collection - */ - public function get() - { - return $this->getUser()->categories()->orderBy('name', 'ASC')->get(); - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param array $ids - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function getByIds(array $ids) - { - throw new NotImplementedException; - } - - /** - * @param $name - * - * @return \Category - */ - public function firstOrCreate($name) - { - return \Category::firstOrCreate(['user_id' => $this->getUser()->id, 'name' => $name]); - } - - /** - * @param \Category $category - * @param int $limit - * - * @return \Illuminate\Pagination\Paginator - */ - public function getTransactionJournals(\Category $category, $limit = 50) - { - $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0; - $set = $category->transactionJournals()->withRelevantData()->take($limit)->offset($offset)->orderBy('date', 'DESC')->get(['transaction_journals.*']); - $count = $category->transactionJournals()->count(); - $items = []; - foreach ($set as $entry) { - $items[] = $entry; - } - - return \Paginator::make($items, $count, $limit); - - } - - /** - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function journalsNoCategory(Carbon $start, Carbon $end) - { - $set = $this->getUser() - ->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') - ->get(['transaction_journals.*']); - - return $set; - } - - /** - * @param \Category $category - * @param Carbon $date - * - * @return float - */ - public function spentInMonth(\Category $category, Carbon $date) - { - $end = clone $date; - $date->startOfMonth(); - $end->endOfMonth(); - $sum = floatval($category->transactionjournals()->before($end)->after($date)->lessThan(0)->sum('amount')) * -1; - - return $sum; - } -} diff --git a/app/lib/FireflyIII/Database/CommonDatabaseCallsInterface.php b/app/lib/FireflyIII/Database/CommonDatabaseCallsInterface.php deleted file mode 100644 index 6fbf57c68b..0000000000 --- a/app/lib/FireflyIII/Database/CommonDatabaseCallsInterface.php +++ /dev/null @@ -1,47 +0,0 @@ -piggyBankRepetitions()->get(); - if ($reps->count() == 1) { - return $reps->first(); - } - // should filter the one we need: - $repetitions = $reps->filter( - function (\PiggyBankRepetition $rep) use ($date) { - if ($date->between($rep->startdate, $rep->targetdate)) { - return $rep; - } - - return null; - } - ); - if ($repetitions->count() == 0) { - return null; - } - - return $repetitions->first(); - } - - /** - * Returns all objects. - * - * @return Collection - */ - public function get() - { - return $this->getUser()->piggyBanks()->where('repeats', 0)->orderBy('name')->get(); - } -} diff --git a/app/lib/FireflyIII/Database/PiggyBank/PiggyBankShared.php b/app/lib/FireflyIII/Database/PiggyBank/PiggyBankShared.php deleted file mode 100644 index be969c4259..0000000000 --- a/app/lib/FireflyIII/Database/PiggyBank/PiggyBankShared.php +++ /dev/null @@ -1,186 +0,0 @@ -setUser(\Auth::user()); - } - - /** - * @param Eloquent $model - * - * @return bool - */ - public function destroy(Eloquent $model) - { - $reminders = \Reminder::where('remindersable_id', $model->id)->get(); - /** @var \Reminder $reminder */ - foreach ($reminders as $reminder) { - $reminder->delete(); - } - $model->delete(); - - } - - /** - * Returns an object with id $id. - * - * @param int $objectId - * - * @return \Eloquent - */ - public function find($objectId) - { - return \PiggyBank:: - leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')->where('piggy_banks.id', '=', $objectId)->where( - 'accounts.user_id', $this->getUser()->id - ) - ->first(['piggy_banks.*']); - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. - * - * @param $what - * - * @return \AccountType|null - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function findByWhat($what) - { - throw new NotImplementedException; - } - - /** - * @param array $ids - * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function getByIds(array $ids) - { - throw new NotImplementedException; - } - - /** - * @param \Account $account - * - * @return float - */ - public function leftOnAccount(\Account $account) - { - \Log::debug('Now in leftOnAccount() for account #' . $account->id . ' (' . $account->name . ')'); - $balance = \Steam::balance($account); - \Log::debug('Steam says: ' . $balance); - /** @var \PiggyBank $p */ - foreach ($account->piggyBanks()->get() as $p) { - $balance -= $p->currentRelevantRep()->currentamount; - } - - return $balance; - - } - - /** - * @param array $data - * - * @return \Eloquent - */ - public function store(array $data) - { - if (!isset($data['remind_me']) || (isset($data['remind_me']) && $data['remind_me'] == 0)) { - $data['reminder'] = null; - } - $piggyBank = new \PiggyBank($data); - $piggyBank->save(); - - return $piggyBank; - } - - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @param Eloquent $model - * @param array $data - * - * @return bool - */ - public function update(Eloquent $model, array $data) - { - /** @var \PiggyBank $model */ - $model->name = $data['name']; - $model->account_id = intval($data['account_id']); - $model->targetamount = floatval($data['targetamount']); - $model->targetdate = isset($data['targetdate']) && $data['targetdate'] != '' ? $data['targetdate'] : null; - $model->rep_every = intval($data['rep_every']); - $model->reminder_skip = intval($data['reminder_skip']); - $model->order = intval($data['order']); - $model->remind_me = intval($data['remind_me']); - $model->reminder = isset($data['reminder']) ? $data['reminder'] : 'month'; - - if ($model->remind_me == 0) { - $model->reminder = null; - } - - $model->save(); - - return true; - } - - /** - * Validates an array. Returns an array containing MessageBags - * errors/warnings/successes. - * - * Ignore PHPMD rules because Laravel 5.0 will make this method superfluous anyway. - * - * @param array $model - * - * @return array - */ - public function validate(array $model) - { - $warnings = new MessageBag; - $successes = new MessageBag; - $model = new \PiggyBank($model); - $model->isValid(); - $errors = $model->getErrors(); - - // add ok messages. - $list = ['name', 'account_id', 'targetamount', 'targetdate', 'remind_me', 'reminder']; - foreach ($list as $entry) { - if (!$errors->has($entry) && !$warnings->has($entry)) { - $successes->add($entry, 'OK'); - } - } - - - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; - } - -} diff --git a/app/lib/FireflyIII/Database/PiggyBank/PiggybankInterface.php b/app/lib/FireflyIII/Database/PiggyBank/PiggybankInterface.php deleted file mode 100644 index 3c26f1c969..0000000000 --- a/app/lib/FireflyIII/Database/PiggyBank/PiggybankInterface.php +++ /dev/null @@ -1,19 +0,0 @@ -_user; - } - - /** - * @param $user - */ - public function setUser($user) - { - $this->_user = $user; - } -} diff --git a/app/lib/FireflyIII/Database/Transaction/Transaction.php b/app/lib/FireflyIII/Database/Transaction/Transaction.php deleted file mode 100644 index d8c2ea909d..0000000000 --- a/app/lib/FireflyIII/Database/Transaction/Transaction.php +++ /dev/null @@ -1,156 +0,0 @@ -account()->associate($data['account']); - $transaction->transactionJournal()->associate($data['transaction_journal']); - $transaction->amount = floatval($data['amount']); - if (isset($data['piggyBank'])) { - $transaction->piggyBank()->associate($data['piggyBank']); - } - if (isset($data['description'])) { - $transaction->description = $data['description']; - } - if ($transaction->isValid()) { - $transaction->save(); - } else { - throw new FireflyException($transaction->getErrors()->first()); - } - - return $transaction; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param Eloquent $model - * @param array $data - * - * @return bool - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function update(Eloquent $model, array $data) - { - throw new NotImplementedException; - } - - /** - * Validates an array. Returns an array containing MessageBags - * errors/warnings/successes. - * - * @param array $model - * - * @return MessageBag - */ - public function validate(array $model) - { - $errors = new MessageBag; - if (is_null($model['account'])) { - $errors->add('account', 'No account present'); - } - if (is_null($model['transaction_journal'])) { - $errors->add('transaction_journal', 'No valid transaction journal present'); - } - - return $errors; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Returns an object with id $id. - * - * @param int $objectId - * - * @return \Eloquent - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function find($objectId) - { - throw new NotImplementedException; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. - * - * @param $what - * - * @return \AccountType|null - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function findByWhat($what) - { - throw new NotImplementedException; - } - - /** - * Returns all objects. - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function get() - { - throw new NotImplementedException; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param array $ids - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function getByIds(array $ids) - { - throw new NotImplementedException; - } -} diff --git a/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrency.php b/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrency.php deleted file mode 100644 index 3eeb6eb5f9..0000000000 --- a/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrency.php +++ /dev/null @@ -1,154 +0,0 @@ -delete(); - } - - /** - * @param array $data - * - * @return Eloquent - */ - public function store(array $data) - { - $currency = new \TransactionCurrency($data); - $currency->save(); - - return $currency; - } - - /** - * @param Eloquent $model - * @param array $data - * - * @return bool - */ - public function update(Eloquent $model, array $data) - { - $model->symbol = $data['symbol']; - $model->code = $data['code']; - $model->name = $data['name']; - $model->save(); - - return true; - } - - /** - * Validates an array. Returns an array containing MessageBags - * errors/warnings/successes. - * - * @param array $model - * - * @return array - */ - public function validate(array $model) - { - $warnings = new MessageBag; - $successes = new MessageBag; - \Log::debug('Now in TransactionCurrency::validate()'); - - $currency = new \TransactionCurrency($model); - $currency->isValid(); - $errors = $currency->getErrors(); - - \Log::debug('Data: ' . json_encode($model)); - \Log::debug('Error-content: ' . json_encode($errors->all())); - \Log::debug('Error count is: ' . $errors->count()); - - $fields = ['name', 'code', 'symbol']; - foreach ($fields as $field) { - if (!$errors->has($field)) { - $successes->add($field, 'OK'); - } - } - - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Returns an object with id $id. - * - * @param int $objectId - * - * @return \Eloquent - */ - public function find($objectId) - { - return \TransactionCurrency::find($objectId); - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. - * - * @param $what - * @throws NotImplementedException - * @codeCoverageIgnore - * - * @return \AccountType|null - */ - public function findByWhat($what) - { - throw new NotImplementedException; - } - - /** - * Returns all objects. - * - * @return Collection - */ - public function get() - { - return \TransactionCurrency::orderBy('code', 'ASC')->get(); - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param array $objectIds - * @throws NotImplementedException - * @codeCoverageIgnore - * - * @return Collection - */ - public function getByIds(array $objectIds) - { - throw new NotImplementedException; - } - - /** - * @param string $code - * - * @return \TransactionCurrency|null - */ - public function findByCode($code) - { - return \TransactionCurrency::whereCode($code)->first(); - } -} diff --git a/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrencyInterface.php b/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrencyInterface.php deleted file mode 100644 index bd2c0a159d..0000000000 --- a/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrencyInterface.php +++ /dev/null @@ -1,20 +0,0 @@ -setUser(\Auth::user()); - } - - /** - * @param Eloquent $model - * - * @return bool - */ - public function destroy(Eloquent $model) - { - /* - * Trigger deletion. - */ - \Event::fire('transactionJournal.destroy', [$model]); // new and used. - /* - * Since this event will also destroy both transactions, trigger on those as - * well because we might want to update some caches and what-not. - */ - /** @var Transaction $transaction */ - foreach ($model->transactions as $transaction) { - \Event::fire('transaction.destroy', [$transaction]); - } - - $model->delete(); - - return true; - } - - /** - * @param array $data - * - * @return \Eloquent - * @throws FireflyException - */ - public function store(array $data) - { - $journal = new \TransactionJournal( - [ - 'transaction_type_id' => $data['transaction_type_id'], - 'transaction_currency_id' => $data['transaction_currency_id'], - 'user_id' => $this->getUser()->id, - 'description' => $data['description'], - 'date' => $data['date'], 'completed' => 0] - ); - $journal->save(); - - list($fromAccount, $toAccount) = $this->storeAccounts($data); - - - $this->storeTransaction( - ['account_id' => $fromAccount->id, 'account' => $fromAccount, 'transaction_journal' => $journal, 'transaction_journal_id' => $journal->id, - 'amount' => floatval($data['amount'] * -1)] - ); - $this->storeTransaction( - ['account_id' => $toAccount->id, 'account' => $toAccount, 'transaction_journal' => $journal, 'transaction_journal_id' => $journal->id, - 'amount' => floatval($data['amount'])] - ); - $this->storeBudget($data, $journal); - $this->storeCategory($data, $journal); - - $journal->completed = 1; - $journal->save(); - - return $journal; - } - - /** - * @param Eloquent $model - * @param array $data - * - * @return bool - * @throws FireflyException - */ - public function update(Eloquent $model, array $data) - { - $journalType = $this->getJournalType($data['what']); - $currency = $this->getJournalCurrencyById($data['transaction_currency_id']); - $model->description = $data['description']; - $model->date = $data['date']; - - $model->transactionType()->associate($journalType); - $model->transactionCurrency()->associate($currency); - $model->user()->associate($this->getUser()); - $model->save(); - - list($fromAccount, $toAccount) = $this->storeAccounts($data); - - /** @noinspection PhpParamsInspection */ - $this->storeBudget($data, $model); - $this->storeCategory($data, $model); - - $amount = floatval($data['amount']); - /** @var \Transaction $transaction */ - foreach ($model->transactions()->get() as $transaction) { - if (floatval($transaction->amount) > 0) { - // the TO transaction. - $transaction->account()->associate($toAccount); - $transaction->amount = $amount; - } else { - $transaction->account()->associate($fromAccount); - $transaction->amount = $amount * -1; - } - if (!$transaction->isValid()) { - throw new FireflyException('Could not validate transaction while saving.'); - } - $transaction->save(); - } - - return true; - } - - /** - * Validates an array. Returns an array containing MessageBags - * errors/warnings/successes. - * - * ignored because this method will be gone soon. - * - * @param array $model - * - * @return array - * @throws FireflyException - */ - public function validate(array $model) - { - - $warnings = new MessageBag; - $successes = new MessageBag; - - $journal = new \TransactionJournal($model); - $journal->isValid(); - $errors = $journal->getErrors(); - - if (!isset($model['what']) && !isset($model['transaction_type_id'])) { - $errors->add('description', 'Internal error: need to know type of transaction!'); - } - if (strlen($model['description']) == 0) { - $errors->add('description', 'The description field is required.'); - } - $errors = $errors->merge($this->_validateAmount($model)); - $errors = $errors->merge($this->_validateBudget($model)); - $errors = $errors->merge($this->_validateAccount($model)); - - $list = ['date', 'description', 'amount', 'budget_id', 'from', 'to', 'account_from_id', 'account_to_id', 'category', 'account_id', 'expense_account', - 'revenue_account']; - foreach ($list as $entry) { - if (!$errors->has($entry)) { - $successes->add($entry, 'OK'); - } - } - - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; - - - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @param array $data - * - * @return array - * @throws FireflyException - */ - public function storeAccounts(array $data) - { - /** @var \FireflyIII\Database\Account\Account $accountRepository */ - $accountRepository = \App::make('FireflyIII\Database\Account\Account'); - $fromAccount = null; - $toAccount = null; - - switch ($data['what']) { - case 'withdrawal': - $fromAccount = $accountRepository->find($data['account_id']); - $toAccount = $accountRepository->firstExpenseAccountOrCreate($data['expense_account']); - break; - case 'opening': - $fromAccount = $data['from']; - $toAccount = $data['to']; - break; - case 'deposit': - $fromAccount = $accountRepository->firstRevenueAccountOrCreate($data['revenue_account']); - $toAccount = $accountRepository->find($data['account_id']); - break; - case 'transfer': - $fromAccount = $accountRepository->find($data['account_from_id']); - $toAccount = $accountRepository->find($data['account_to_id']); - break; - - default: - throw new FireflyException('Cannot save transaction journal with accounts based on $what "' . $data['what'] . '".'); - break; - } - - return [$fromAccount, $toAccount]; - } - - /** - * @param array $data - * - * @return \Eloquent - * @throws FireflyException - */ - public function storeTransaction($data) - { - - /** @var \FireflyIII\Database\Transaction\Transaction $repository */ - $repository = \App::make('FireflyIII\Database\Transaction\Transaction'); - - $errors = $repository->validate($data); - if ($errors->count() > 0) { - \Log::error('Could not store transaction: ' . $errors->toJson()); - throw new FireflyException('store() transaction failed, but it should not!'); - } - - return $repository->store($data); - } - - /** - * @param array $data - * @param \TransactionJournal|\Eloquent $journal - */ - public function storeBudget($data, \TransactionJournal $journal) - { - if (isset($data['budget_id']) && intval($data['budget_id']) > 0) { - /** @var \FireflyIII\Database\Budget\Budget $budgetRepository */ - $budgetRepository = \App::make('FireflyIII\Database\Budget\Budget'); - $budget = $budgetRepository->find(intval($data['budget_id'])); - if ($budget) { - $journal->budgets()->sync([$budget->id]); - } - } - } - - /** - * @param array $data - * @param \TransactionJournal|\Eloquent $journal - */ - public function storeCategory(array $data, \TransactionJournal $journal) - { - if (isset($data['category']) && strlen($data['category']) > 0) { - /** @var \FireflyIII\Database\Category\Category $categoryRepository */ - $categoryRepository = \App::make('FireflyIII\Database\Category\Category'); - $category = $categoryRepository->firstOrCreate($data['category']); - if ($category) { - $journal->categories()->sync([$category->id]); - } - - return; - } - $journal->categories()->sync([]); - - return; - } - - /** - * @param $type - * - * @return \TransactionType|null - * @throws FireflyException - */ - public function getJournalType($type) - { - /** @var \FireflyIII\Database\TransactionType\TransactionType $typeRepository */ - $typeRepository = \App::make('FireflyIII\Database\TransactionType\TransactionType'); - - return $typeRepository->findByWhat($type); - } - - /** - * @param int $currencyId - * - * @return null|\TransactionCurrency - */ - public function getJournalCurrencyById($currencyId) - { - /** @var \FireflyIII\Database\TransactionCurrency\TransactionCurrency $currencyRepository */ - $currencyRepository = \App::make('FireflyIII\Database\TransactionCurrency\TransactionCurrency'); - - return $currencyRepository->find($currencyId); - } - - /** - * @SuppressWarnings("CamelCase") // I'm fine with this. - * - * @param array $model - * - * @return MessageBag - */ - protected function _validateAmount(array $model) - { - $errors = new MessageBag; - if (isset($model['amount']) && floatval($model['amount']) < 0.01) { - $errors->add('amount', 'Amount must be > 0.01'); - } else { - if (!isset($model['amount'])) { - $errors->add('amount', 'Amount must be set!'); - } - } - - return $errors; - } - - /** - * @SuppressWarnings("CamelCase") // I'm fine with this. - * - * @param array $model - * - * @return MessageBag - */ - protected function _validateBudget(array $model) - { - /* - * Budget (is not in rules) - */ - $errors = new MessageBag; - if (isset($model['budget_id']) && !ctype_digit($model['budget_id'])) { - $errors->add('budget_id', 'Invalid budget'); - } - - return $errors; - } - - /** - * @SuppressWarnings("CamelCase") // I'm fine with this. - * - * @param array $model - * - * @return MessageBag - * @throws FireflyException - */ - protected function _validateAccount(array $model) - { - $errors = new MessageBag; - switch (true) { - // this combination is often seen in withdrawals. - case (isset($model['account_id']) && isset($model['expense_account'])): - if (intval($model['account_id']) < 1) { - $errors->add('account_id', 'Invalid account.'); - } - break; - // often seen in deposits - case (isset($model['account_id']) && isset($model['revenue_account'])): - if (intval($model['account_id']) < 1) { - $errors->add('account_id', 'Invalid account.'); - } - break; - // often seen in transfers - case (isset($model['account_from_id']) && isset($model['account_to_id'])): - if (intval($model['account_from_id']) < 1 || intval($model['account_from_id']) < 1) { - $errors->add('account_from_id', 'Invalid account selected.'); - $errors->add('account_to_id', 'Invalid account selected.'); - - } else { - if (intval($model['account_from_id']) == intval($model['account_to_id'])) { - $errors->add('account_to_id', 'Cannot be the same as "from" account.'); - $errors->add('account_from_id', 'Cannot be the same as "to" account.'); - } - } - break; - case (isset($model['from']) && isset($model['to'])): - break; - default: - throw new FireflyException('Cannot validate accounts for transaction journal.'); - break; - } - - return $errors; - } - - /** - * Returns an object with id $id. - * - * @param int $objectId - * - * @codeCoverageIgnore - * @throws NotImplementedException - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @return \Eloquent - */ - public function find($objectId) - { - throw new NotImplementedException; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. - * - * @param $what - * - * @return \AccountType|null - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function findByWhat($what) - { - throw new NotImplementedException; - } - - /** - * Returns all objects. - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function get() - { - throw new NotImplementedException; - } - - /** - * @param array $ids - * - * @return Collection - */ - public function getByIds(array $ids) - { - return $this->getUser()->transactionjournals()->with('transactions')->whereIn('id', $ids)->orderBy('date', 'ASC')->get(); - } - - /** - * @return Carbon - */ - public function firstDate() - { - $journal = $this->first(); - if ($journal) { - return $journal->date; - } - - return Carbon::now(); - } - - /** - * @return TransactionJournal - */ - public function first() - { - return $this->getUser()->transactionjournals()->orderBy('date', 'ASC')->first(); - } - - /** - * @param Carbon $date - * - * @return float - */ - public function getSumOfExpensesByMonth(Carbon $date) - { - /** @var \FireflyIII\Report\ReportInterface $reportRepository */ - $reportRepository = \App::make('FireflyIII\Report\ReportInterface'); - - $set = $reportRepository->getExpenseGroupedForMonth($date, 200); - $sum = 0; - foreach ($set as $entry) { - $sum += $entry['amount']; - } - - - return $sum; - } - - /** - * @param Carbon $date - * - * @return float - */ - public function getSumOfIncomesByMonth(Carbon $date) - { - /** @var \FireflyIII\Report\ReportInterface $reportRepository */ - $reportRepository = \App::make('FireflyIII\Report\ReportInterface'); - - $incomes = $reportRepository->getIncomeForMonth($date); - $totalIn = 0; - /** @var \TransactionJournal $entry */ - foreach ($incomes as $entry) { - $totalIn += $entry->getAmount(); - } - - return $totalIn; - } - - /** - * @param int $limit - * - * @return \Illuminate\Pagination\Paginator - */ - public function getDepositsPaginated($limit = 50) - { - $offset = intval(\Input::get('page')) > 0 ? (intval(\Input::get('page')) - 1) * $limit : 0; - - $set = $this->getUser()->transactionJournals()->transactionTypes(['Deposit'])->withRelevantData()->take($limit)->offset($offset)->orderBy( - 'date', 'DESC' - )->get(['transaction_journals.*']); - $count = $this->getUser()->transactionJournals()->transactionTypes(['Deposit'])->count(); - $items = []; - foreach ($set as $entry) { - $items[] = $entry; - } - - return \Paginator::make($items, $count, $limit); - } - - /** - * @param \Account $account - * @param Carbon $start - * @param Carbon $end - * @param int $count - * - * @return Collection - */ - public function getInDateRangeAccount(\Account $account, Carbon $start, Carbon $end, $count = 20) - { - - $accountID = $account->id; - $query = $this->_user->transactionjournals()->with(['transactions', 'transactioncurrency', 'transactiontype'])->leftJoin( - 'transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id' - )->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $accountID)->where( - 'date', '>=', $start->format('Y-m-d') - )->where('date', '<=', $end->format('Y-m-d'))->orderBy('transaction_journals.date', 'DESC')->orderBy('transaction_journals.id', 'DESC')->take( - $count - )->get(['transaction_journals.*']); - - return $query; - } - - /** - * @param $currency - * - * @return null|\TransactionCurrency - */ - public function getJournalCurrency($currency) - { - /** @var \FireflyIII\Database\TransactionCurrency\TransactionCurrency $currencyRepository */ - $currencyRepository = \App::make('FireflyIII\Database\TransactionCurrency\TransactionCurrency'); - - return $currencyRepository->findByCode($currency); - } - - /** - * @param int $limit - * - * @return \Illuminate\Pagination\Paginator - */ - public function getTransfersPaginated($limit = 50) - { - $offset = intval(\Input::get('page')) > 0 ? (intval(\Input::get('page')) - 1) * $limit : 0; - - $set = $this->getUser()->transactionJournals()->transactionTypes(['Transfer'])->withRelevantData()->take($limit)->offset($offset)->orderBy( - 'date', 'DESC' - )->get(['transaction_journals.*']); - $count = $this->getUser()->transactionJournals()->transactionTypes(['Transfer'])->count(); - $items = []; - foreach ($set as $entry) { - $items[] = $entry; - } - - return \Paginator::make($items, $count, $limit); - } - - /** - * @param int $limit - * - * @return \Illuminate\Pagination\Paginator - */ - public function getWithdrawalsPaginated($limit = 50) - { - $offset = intval(\Input::get('page')) > 0 ? (intval(\Input::get('page')) - 1) * $limit : 0; - - $set = $this->getUser()->transactionJournals()->transactionTypes(['Withdrawal'])->withRelevantData()->take($limit)->offset($offset)->orderBy( - 'date', 'DESC' - )->get(['transaction_journals.*']); - $count = $this->getUser()->transactionJournals()->transactionTypes(['Withdrawal'])->count(); - $items = []; - foreach ($set as $entry) { - $items[] = $entry; - } - - return \Paginator::make($items, $count, $limit); - } -} diff --git a/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournalInterface.php b/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournalInterface.php deleted file mode 100644 index 264aeb5200..0000000000 --- a/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournalInterface.php +++ /dev/null @@ -1,36 +0,0 @@ - 'Opening balance', - 'transfer' => 'Transfer', - 'withdrawal' => 'Withdrawal', - 'deposit' => 'Deposit', - ]; - if (!isset($translation[$what])) { - throw new FireflyException('Cannot find transaction type described as "' . e($what) . '".'); - } - - return \TransactionType::whereType($translation[$what])->first(); - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * Returns all objects. - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function get() - { - throw new NotImplementedException; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param array $ids - * - * @return Collection - * @throws NotImplementedException - * @codeCoverageIgnore - */ - public function getByIds(array $ids) - { - throw new NotImplementedException; - } -} diff --git a/app/lib/FireflyIII/Database/User/User.php b/app/lib/FireflyIII/Database/User/User.php deleted file mode 100644 index f60bfc3037..0000000000 --- a/app/lib/FireflyIII/Database/User/User.php +++ /dev/null @@ -1,73 +0,0 @@ -first(); - } - - /** - * @param $reset - * - * @return null|User - */ - public function findByReset($reset) - { - return \User::where('reset', $reset)->first(); - } - - /** - * @param array $data - * - * @return bool|\User - */ - public function register(array $data) - { - $user = new \User; - $user->email = isset($data['email']) ? $data['email'] : null; - $user->reset = \Str::random(32); - $user->password = \Hash::make(\Str::random(12)); - - // validate user: - if (!$user->isValid()) { - \Log::error('Invalid user with data: ' . isset($data['email']) ? $data['email'] : '(no email!)'); - \Session::flash('error', 'Input invalid, please try again: ' . $user->getErrors()->first()); - - return false; - } - $user->save(); - - return $user; - - } - - /** - * @param \User $user - * @param $password - * - * @return bool - */ - public function updatePassword(\User $user, $password) - { - $user->password = $password; - $user->forceSave(); - - return true; - } - -} diff --git a/app/lib/FireflyIII/Event/Account.php b/app/lib/FireflyIII/Event/Account.php deleted file mode 100644 index 6890d5b1e1..0000000000 --- a/app/lib/FireflyIII/Event/Account.php +++ /dev/null @@ -1,53 +0,0 @@ -id . '.latestBalance'); - \Cache::forget('account.' . $account->id . '.lastActivityDate'); - } - - /** - * @param \Account $account - */ - public function store(\Account $account) - { - - \Cache::forget('account.' . $account->id . '.latestBalance'); - \Cache::forget('account.' . $account->id . '.lastActivityDate'); - } - - /** - * @param Dispatcher $events - */ - public function subscribe(Dispatcher $events) - { - // triggers when others are updated. - $events->listen('account.store', 'FireflyIII\Event\Account@store'); - $events->listen('account.update', 'FireflyIII\Event\Account@update'); - $events->listen('account.destroy', 'FireflyIII\Event\Account@destroy'); - } - - /** - * @param \Account $account - */ - public function update(\Account $account) - { - \Cache::forget('account.' . $account->id . '.latestBalance'); - \Cache::forget('account.' . $account->id . '.lastActivityDate'); - } -} diff --git a/app/lib/FireflyIII/Event/Budget.php b/app/lib/FireflyIII/Event/Budget.php deleted file mode 100644 index 940f87d887..0000000000 --- a/app/lib/FireflyIII/Event/Budget.php +++ /dev/null @@ -1,67 +0,0 @@ -startdate, $budgetLimit->repeat_freq, 0); - $end->subDay(); - - $set = $budgetLimit->limitrepetitions()->where('startdate', $budgetLimit->startdate->format('Y-m-d'))->where('enddate', $end->format('Y-m-d'))->get(); - /* - * Create new LimitRepetition: - */ - if ($set->count() == 0) { - - $repetition = new \LimitRepetition(); - $repetition->startdate = $budgetLimit->startdate; - $repetition->enddate = $end; - $repetition->amount = $budgetLimit->amount; - $repetition->budgetLimit()->associate($budgetLimit); - - try { - $repetition->save(); - } catch (QueryException $e) { - \Log::error('Trying to save new LimitRepetition failed!'); - \Log::error($e->getMessage()); - } - } else { - if ($set->count() == 1) { - /* - * Update existing one. - */ - $repetition = $set->first(); - $repetition->amount = $budgetLimit->amount; - $repetition->save(); - - } - } - - } - - /** - * @param Dispatcher $events - */ - public function subscribe(Dispatcher $events) - { - $events->listen('limits.store', 'FireflyIII\Event\Budget@storeOrUpdateLimit'); - $events->listen('limits.update', 'FireflyIII\Event\Budget@storeOrUpdateLimit'); - - } -} diff --git a/app/lib/FireflyIII/Event/Event.php b/app/lib/FireflyIII/Event/Event.php deleted file mode 100644 index 34980e5a8d..0000000000 --- a/app/lib/FireflyIII/Event/Event.php +++ /dev/null @@ -1,45 +0,0 @@ -piggyBanks()->get(); - - // get reminders for each - /** @var \PiggyBank $piggyBank */ - foreach ($piggies as $piggyBank) { - $reminders = $piggyBank->reminders()->get(); - /** @var \Reminder $reminder */ - foreach ($reminders as $reminder) { - $reminder->delete(); - } - } - } - - - /** - * @param Dispatcher $events - */ - public function subscribe(Dispatcher $events) - { - // triggers when others are updated. - $events->listen('account.destroy', 'FireflyIII\Event\Event@deleteAccount'); - } -} diff --git a/app/lib/FireflyIII/Event/Piggybank.php b/app/lib/FireflyIII/Event/Piggybank.php deleted file mode 100644 index 9273f5c600..0000000000 --- a/app/lib/FireflyIII/Event/Piggybank.php +++ /dev/null @@ -1,293 +0,0 @@ - 0) { - $event = new \PiggyBankEvent; - $event->piggyBank()->associate($piggyBank); - $event->amount = floatval($amount); - $event->date = new Carbon; - if (!$event->isValid()) { - \Log::error($event->getErrors()); - \App::abort(500); - } - $event->save(); - } - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @param \TransactionJournal $journal - * - * @throws \FireflyIII\Exception\FireflyException - * @throws \FireflyIII\Exception\NotImplementedException - */ - public function destroyTransfer(\TransactionJournal $journal) - { - if ($journal->piggyBankEvents()->count() > 0) { - - /** @var \FireflyIII\Database\PiggyBank\PiggyBank $repository */ - $repository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank'); - - /** @var \PiggyBank $piggyBank */ - $piggyBank = $journal->piggyBankEvents()->first()->piggyBank()->first(); - - /** @var \PiggyBankRepetition $repetition */ - $repetition = $repository->findRepetitionByDate($piggyBank, $journal->date); - - $relevantTransaction = null; - /** @var \Transaction $transaction */ - foreach ($journal->transactions as $transaction) { - if ($transaction->account_id == $piggyBank->account_id) { - $relevantTransaction = $transaction; - } - } - if (is_null($relevantTransaction)) { - return; - } - - $repetition->currentamount += floatval($relevantTransaction->amount * -1); - $repetition->save(); - - - $event = new \PiggyBankEvent; - $event->piggyBank()->associate($piggyBank); - $event->amount = floatval($relevantTransaction->amount * -1); - $event->date = new Carbon; - $event->save(); - } - } - - /** - * @param \PiggyBank $piggyBank - * @param float $amount - */ - public function removeMoney(\PiggyBank $piggyBank, $amount = 0.0) - { - $amount = $amount * -1; - if ($amount < 0) { - $event = new \PiggyBankEvent; - $event->piggyBank()->associate($piggyBank); - $event->amount = floatval($amount); - $event->date = new Carbon; - $event->save(); - } - } - - /** - * @param \PiggyBank $piggyBank - */ - public function storePiggyBank(\PiggyBank $piggyBank) - { - $repetition = new \PiggyBankRepetition; - $repetition->piggyBank()->associate($piggyBank); - $repetition->startdate = $piggyBank->startdate; - $repetition->targetdate = $piggyBank->targetdate; - $repetition->currentamount = 0; - $repetition->save(); - } - - /* - * - */ - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @param \TransactionJournal $journal - * @param int $piggyBankId - */ - public function storeTransfer(\TransactionJournal $journal, $piggyBankId = 0) - { - if (intval($piggyBankId) == 0) { - return; - } - /** @var \FireflyIII\Database\PiggyBank\PiggyBank $repository */ - $repository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank'); - - /** @var \PiggyBank $piggyBank */ - $piggyBank = $repository->find($piggyBankId); - - if ($journal->transactions()->where('account_id', $piggyBank->account_id)->count() == 0) { - return; - } - /** @var \PiggyBankRepetition $repetition */ - $repetition = $repository->findRepetitionByDate($piggyBank, $journal->date); - $amount = floatval($piggyBank->targetamount); - $leftToSave = $amount - floatval($repetition->currentamount); - $transaction = $journal->transactions()->where('account_id', $piggyBank->account_id)->first(); - // must be in range of journal. Continue determines if we can move it. - if (floatval($transaction->amount < 0)) { - // amount removed from account, so removed from piggy bank. - $continue = ($transaction->amount * -1 <= floatval($repetition->currentamount)); - } else { - // amount added - $continue = $transaction->amount <= $leftToSave; - } - if ($continue) { - \Log::debug('Update repetition.'); - $repetition->currentamount += floatval($transaction->amount); - $repetition->save(); - $event = new \PiggyBankEvent; - $event->piggyBank()->associate($piggyBank); - $event->transactionjournal()->associate($journal); - $event->amount = floatval($transaction->amount); - $event->date = new Carbon; - $event->save(); - } - } - - /** - * @param Dispatcher $events - */ - public function subscribe(Dispatcher $events) - { - // triggers on piggy bank events: - $events->listen('piggy_bank.addMoney', 'FireflyIII\Event\PiggyBank@addMoney'); - $events->listen('piggy_bank.removeMoney', 'FireflyIII\Event\PiggyBank@removeMoney'); - $events->listen('piggy_bank.store', 'FireflyIII\Event\PiggyBank@storePiggyBank'); - $events->listen('piggy_bank.update', 'FireflyIII\Event\PiggyBank@updatePiggyBank'); - - \App::before( - function () { - $this->validateRepeatedExpenses(); - } - ); - - // triggers when others are updated. - $events->listen('transactionJournal.store', 'FireflyIII\Event\PiggyBank@storeTransfer'); - $events->listen('transactionJournal.update', 'FireflyIII\Event\PiggyBank@updateTransfer'); - $events->listen('transactionJournal.destroy', 'FireflyIII\Event\PiggyBank@destroyTransfer'); - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's 6. More than 5 but alright. - * - * Validates the presence of repetitions for all repeated expenses! - */ - public function validateRepeatedExpenses() - { - if (!\Auth::check()) { - return; - } - /** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repository */ - $repository = \App::make('FireflyIII\Database\PiggyBank\RepeatedExpense'); - $list = $repository->get(); - $today = Carbon::now(); - /** @var \PiggyBank $entry */ - foreach ($list as $entry) { - $count = $entry->piggyBankrepetitions()->starts($entry->startdate)->targets($entry->targetdate)->count(); - if ($count == 0) { - $repetition = new \PiggyBankRepetition; - $repetition->piggyBank()->associate($entry); - $repetition->startdate = $entry->startdate; - $repetition->targetdate = $entry->targetdate; - $repetition->currentamount = 0; - $repetition->save(); - } - $currentTarget = clone $entry->startdate; - $currentStart = null; - while ($currentTarget < $today) { - $currentStart = \DateKit::subtractPeriod($currentTarget, $entry->rep_length, 0); - $currentTarget = \DateKit::addPeriod($currentTarget, $entry->rep_length, 0); - $count = $entry->piggyBankRepetitions()->starts($currentStart)->targets($currentTarget)->count(); - if ($count == 0) { - $repetition = new \PiggyBankRepetition; - $repetition->piggyBank()->associate($entry); - $repetition->startdate = $currentStart; - $repetition->targetdate = $currentTarget; - $repetition->currentamount = 0; - $repetition->save(); - } - - } - } - } - - /** - * @param \PiggyBank $piggyBank - */ - public function updatePiggyBank(\PiggyBank $piggyBank) - { - // get the repetition: - $repetition = $piggyBank->currentRelevantRep(); - $repetition->startdate = $piggyBank->startdate; - $repetition->targetdate = $piggyBank->targetdate; - $repetition->save(); - } - - /** - * @param \TransactionJournal $journal - * - * @throws \FireflyIII\Exception\FireflyException - * @throws \FireflyIII\Exception\NotImplementedException - */ - public function updateTransfer(\TransactionJournal $journal) - { - - if ($journal->piggyBankEvents()->count() > 0) { - - $event = $journal->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->first(); - $eventSum = floatval($journal->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->sum('amount')); - - /** @var \FireflyIII\Database\PiggyBank\PiggyBank $repository */ - $repository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank'); - - /** @var \PiggyBank $piggyBank */ - $piggyBank = $journal->piggyBankEvents()->first()->piggyBank()->first(); - - /** @var \PiggyBankRepetition $repetition */ - $repetition = $repository->findRepetitionByDate($piggyBank, $journal->date); - - $relevantTransaction = null; - /** @var \Transaction $transaction */ - foreach ($journal->transactions as $transaction) { - if ($transaction->account_id == $piggyBank->account_id) { - $relevantTransaction = $transaction; - } - } - if (is_null($relevantTransaction)) { - return; - } - - $diff = floatval($relevantTransaction->amount) - floatval($eventSum); - /* - * Create an event to remove /add the difference from the piggy - */ - $repetition->currentamount += $diff; - $repetition->save(); - - - $event = new \PiggyBankEvent; - $event->piggyBank()->associate($piggyBank); - $event->transactionJournal()->associate($journal); - $event->amount = $diff; - $event->date = new Carbon; - if (!$event->isValid()) { - \Log::error($event->getErrors()); - \App::abort(500); - } - $event->save(); - } - - } -} diff --git a/app/lib/FireflyIII/Event/Transaction.php b/app/lib/FireflyIII/Event/Transaction.php deleted file mode 100644 index 9c96070cd0..0000000000 --- a/app/lib/FireflyIII/Event/Transaction.php +++ /dev/null @@ -1,55 +0,0 @@ -account_id . '.latestBalance'); - \Cache::forget('account.' . $transaction->account_id . '.lastActivityDate'); - - // delete transaction: - $transaction->delete(); - } - - /** - * @param \Transaction $transaction - */ - public function store(\Transaction $transaction) - { - \Cache::forget('account.' . $transaction->account_id . '.latestBalance'); - \Cache::forget('account.' . $transaction->account_id . '.lastActivityDate'); - } - - /** - * @param Dispatcher $events - */ - public function subscribe(Dispatcher $events) - { - // triggers when others are updated. - $events->listen('transaction.store', 'FireflyIII\Event\Transaction@store'); - $events->listen('transaction.update', 'FireflyIII\Event\Transaction@update'); - $events->listen('transaction.destroy', 'FireflyIII\Event\Transaction@destroy'); - } - - /** - * @param \Transaction $transaction - */ - public function update(\Transaction $transaction) - { - \Cache::forget('account.' . $transaction->account_id . '.latestBalance'); - \Cache::forget('account.' . $transaction->account_id . '.lastActivityDate'); - } -} diff --git a/app/lib/FireflyIII/Event/TransactionJournal.php b/app/lib/FireflyIII/Event/TransactionJournal.php deleted file mode 100644 index c7cabb911c..0000000000 --- a/app/lib/FireflyIII/Event/TransactionJournal.php +++ /dev/null @@ -1,57 +0,0 @@ -get(); - - - /** @var \Bill $entry */ - foreach ($set as $entry) { - $repository->scan($entry, $journal); - } - } - - /** - * @param Dispatcher $events - */ - public function subscribe(Dispatcher $events) - { - // triggers when others are updated. - $events->listen('transactionJournal.store', 'FireflyIII\Event\TransactionJournal@store'); - $events->listen('transactionJournal.update', 'FireflyIII\Event\TransactionJournal@update'); - } - - /** - * @param \TransactionJournal $journal - */ - public function update(\TransactionJournal $journal) - { - /** @var \FireflyIII\Database\Bill\Bill $repository */ - $repository = \App::make('FireflyIII\Database\Bill\Bill'); - $set = $repository->get(); - $journal->bill_id = null; - $journal->save(); - - /** @var \Bill $entry */ - foreach ($set as $entry) { - $repository->scan($entry, $journal); - } - } -} diff --git a/app/lib/FireflyIII/FF3ServiceProvider.php b/app/lib/FireflyIII/FF3ServiceProvider.php deleted file mode 100644 index ade2e75683..0000000000 --- a/app/lib/FireflyIII/FF3ServiceProvider.php +++ /dev/null @@ -1,134 +0,0 @@ -app->validator->resolver( - function ($translator, $data, $rules, $messages) { - return new FireflyValidator($translator, $data, $rules, $messages); - } - ); - } - - /** - * Return the services bla bla. - * - * @codeCoverageIgnore - * @return array - */ - public function provides() - { - // @codeCoverageIgnoreStart - return ['reminders', 'filters', 'datekit', 'navigation']; - // @codeCoverageIgnoreEnd - } - - /** - * Triggered automatically by Laravel - */ - public function register() - { - $this->registerFacades(); - $this->registerInterfaces(); - $this->registerAliases(); - - - } - - public function registerFacades() - { - $this->app->bind( - 'reminders', function () { - return new Reminders; - } - ); - $this->app->bind( - 'filter', function () { - return new Filter; - } - ); - $this->app->bind( - 'datekit', function () { - return new Date; - } - ); - $this->app->bind( - 'navigation', function () { - return new Navigation; - } - ); - $this->app->bind( - 'ffform', function () { - return new Form; - } - ); - $this->app->bind( - 'steam', function () { - return new Steam; - } - ); - $this->app->bind( - 'amount', function () { - return new Amount; - } - ); - } - - public function registerInterfaces() - { - // preferences - $this->app->bind('FireflyIII\Shared\Preferences\PreferencesInterface', 'FireflyIII\Shared\Preferences\Preferences'); - - // registration and user mail - $this->app->bind('FireflyIII\Shared\Mail\RegistrationInterface', 'FireflyIII\Shared\Mail\Registration'); - - // reports - $this->app->bind('FireflyIII\Report\ReportInterface', 'FireflyIII\Report\Report'); - $this->app->bind('FireflyIII\Report\ReportQueryInterface', 'FireflyIII\Report\ReportQuery'); - $this->app->bind('FireflyIII\Report\ReportHelperInterface', 'FireflyIII\Report\ReportHelper'); - - $this->app->bind('FireflyIII\Helper\Related\RelatedInterface', 'FireflyIII\Helper\Related\Related'); - - $this->app->bind('FireflyIII\Helper\TransactionJournal\HelperInterface', 'FireflyIII\Helper\TransactionJournal\Helper'); - - // chart - $this->app->bind('FireflyIII\Chart\ChartInterface', 'FireflyIII\Chart\Chart'); - } - - public function registerAliases() - { - // Shortcut so developers don't need to add an Alias in app/config/app.php - $this->app->booting( - function () { - $loader = AliasLoader::getInstance(); - $loader->alias('Reminders', 'FireflyIII\Shared\Facade\Reminders'); - $loader->alias('Filter', 'FireflyIII\Shared\Facade\Filter'); - $loader->alias('DateKit', 'FireflyIII\Shared\Facade\DateKit'); - $loader->alias('Navigation', 'FireflyIII\Shared\Facade\Navigation'); - $loader->alias('FFForm', 'FireflyIII\Shared\Facade\FFForm'); - $loader->alias('Steam', 'FireflyIII\Shared\Facade\Steam'); - $loader->alias('Amount', 'FireflyIII\Shared\Facade\Amount'); - } - ); - } - -} diff --git a/app/lib/FireflyIII/Form/Form.php b/app/lib/FireflyIII/Form/Form.php deleted file mode 100644 index 0396a0a33d..0000000000 --- a/app/lib/FireflyIII/Form/Form.php +++ /dev/null @@ -1,290 +0,0 @@ -get(); - $html = \View::make('form.amount', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); - - return $html; - - } - - /** - * @param $name - * @param $options - * - * @return string - */ - public static function label($name, $options) - { - if (isset($options['label'])) { - return $options['label']; - } - $labels = ['amount_min' => 'Amount (min)', 'amount_max' => 'Amount (max)', 'match' => 'Matches on', 'repeat_freq' => 'Repetition', - 'account_from_id' => 'Account from', 'account_to_id' => 'Account to', 'account_id' => 'Asset account', 'budget_id' => 'Budget' - , 'piggy_bank_id' => 'Piggy bank']; - - - return isset($labels[$name]) ? $labels[$name] : str_replace('_', ' ', ucfirst($name)); - - } - - /** - * @param $name - * @param $label - * @param array $options - * - * @return array - */ - public static 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 - */ - public static function getHolderClasses($name) - { - /* - * Get errors, warnings and successes from session: - */ - /** @var MessageBag $errors */ - $errors = \Session::get('errors'); - - /** @var MessageBag $successes */ - $successes = \Session::get('successes'); - - switch (true) { - case (!is_null($errors) && $errors->has($name)): - $classes = 'form-group has-error has-feedback'; - break; - case (!is_null($successes) && $successes->has($name)): - $classes = 'form-group has-success has-feedback'; - break; - default: - $classes = 'form-group'; - break; - } - - return $classes; - } - - /** - * @param $name - * @param $value - * - * @return mixed - */ - public static function fillFieldValue($name, $value) - { - if (\Session::has('preFilled')) { - $preFilled = \Session::get('preFilled'); - $value = isset($preFilled[$name]) && is_null($value) ? $preFilled[$name] : $value; - } - if (!is_null(\Input::old($name))) { - $value = \Input::old($name); - } - - return $value; - } - - /** - * @param $name - * @param null $value - * @param array $options - * - * @return string - * @throws FireflyException - */ - public static function ffBalance($name, $value = null, array $options = []) - { - $label = self::label($name, $options); - $options = self::expandOptionArray($name, $label, $options); - $classes = self::getHolderClasses($name); - $value = self::fillFieldValue($name, $value); - $options['step'] = 'any'; - $defaultCurrency = isset($options['currency']) ? $options['currency'] : \Amount::getDefaultCurrency(); - $currencies = \TransactionCurrency::orderBy('code', 'ASC')->get(); - $html = \View::make('form.balance', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); - - return $html; - } - - /** - * @param $name - * @param int $value - * @param null $checked - * @param array $options - * - * @return string - * @throws FireflyException - */ - public static function ffCheckbox($name, $value = 1, $checked = null, $options = []) - { - $options['checked'] = $checked === true ? true : null; - $label = self::label($name, $options); - $options = self::expandOptionArray($name, $label, $options); - $classes = self::getHolderClasses($name); - $value = self::fillFieldValue($name, $value); - - unset($options['placeholder'], $options['autocomplete'], $options['class']); - - $html = \View::make('form.checkbox', compact('classes', 'name', 'label', 'value', 'options'))->render(); - - return $html; - } - - /** - * @param $name - * @param null $value - * @param array $options - * - * @return string - * @throws FireflyException - */ - public static function ffDate($name, $value = null, array $options = []) - { - $label = self::label($name, $options); - $options = self::expandOptionArray($name, $label, $options); - $classes = self::getHolderClasses($name); - $value = self::fillFieldValue($name, $value); - $html = \View::make('form.date', compact('classes', 'name', 'label', 'value', 'options'))->render(); - - return $html; - } - - /** - * @param $name - * @param null $value - * @param array $options - * - * @return string - * @throws FireflyException - */ - public static function ffInteger($name, $value = null, array $options = []) - { - $label = self::label($name, $options); - $options = self::expandOptionArray($name, $label, $options); - $classes = self::getHolderClasses($name); - $value = self::fillFieldValue($name, $value); - $options['step'] = '1'; - $html = \View::make('form.integer', compact('classes', 'name', 'label', 'value', 'options'))->render(); - - return $html; - - } - - /** - * Return buttons for update/validate/return. - * - * @param $type - * @param $name - * - * @return string - * @throws FireflyException - */ - public static function ffOptionsList($type, $name) - { - $previousValue = \Input::old('post_submit_action'); - $previousValue = is_null($previousValue) ? 'store' : $previousValue; - $html = \View::make('form.options', compact('type', 'name', 'previousValue'))->render(); - - return $html; - } - - /** - * @param $name - * @param array $list - * @param null $selected - * @param array $options - * - * @return string - */ - public static function ffSelect($name, array $list = [], $selected = null, array $options = []) - { - $label = self::label($name, $options); - $options = self::expandOptionArray($name, $label, $options); - $classes = self::getHolderClasses($name); - $selected = self::fillFieldValue($name, $selected); - $html = \View::make('form.select', compact('classes', 'name', 'label', 'selected', 'options', 'list'))->render(); - - return $html; - } - - /** - * @param $name - * @param null $value - * @param array $options - * - * @return string - * @throws FireflyException - */ - public static function ffTags($name, $value = null, array $options = []) - { - $label = self::label($name, $options); - $options = self::expandOptionArray($name, $label, $options); - $classes = self::getHolderClasses($name); - $value = self::fillFieldValue($name, $value); - $options['data-role'] = 'tagsinput'; - $html = \View::make('form.tags', compact('classes', 'name', 'label', 'value', 'options'))->render(); - - return $html; - } - - /** - * @param $name - * @param null $value - * @param array $options - * - * @return string - * @throws FireflyException - */ - public static function ffText($name, $value = null, array $options = []) - { - $label = self::label($name, $options); - $options = self::expandOptionArray($name, $label, $options); - $classes = self::getHolderClasses($name); - $value = self::fillFieldValue($name, $value); - $html = \View::make('form.text', compact('classes', 'name', 'label', 'value', 'options'))->render(); - - return $html; - - } -} diff --git a/app/lib/FireflyIII/Helper/Related/Related.php b/app/lib/FireflyIII/Helper/Related/Related.php deleted file mode 100644 index 06e1047858..0000000000 --- a/app/lib/FireflyIII/Helper/Related/Related.php +++ /dev/null @@ -1,88 +0,0 @@ -setUser(\Auth::user()); - } - - /** - * @param array $objectIds - * - * @return Collection - */ - public function getJournalsByIds(array $objectIds) - { - /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ - $repository = \App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); - - return $repository->getByIds($objectIds); - } - - /** - * @param string $query - * @param \TransactionJournal $journal - * - * @return Collection - */ - public function search($query, \TransactionJournal $journal) - { - $start = clone $journal->date; - $end = clone $journal->date; - $start->startOfMonth(); - $end->endOfMonth(); - - // get already related transactions: - $exclude = [$journal->id]; - foreach ($journal->transactiongroups()->get() as $group) { - foreach ($group->transactionjournals()->get() as $current) { - $exclude[] = $current->id; - } - } - $exclude = array_unique($exclude); - - /** @var Collection $collection */ - $collection = $this->getUser()->transactionjournals() - ->withRelevantData() - ->before($end)->after($start)->where('encrypted', 0) - ->whereNotIn('id', $exclude) - ->where('description', 'LIKE', '%' . $query . '%') - ->get(); - - // manually search encrypted entries: - /** @var Collection $encryptedCollection */ - $encryptedCollection = $this->getUser()->transactionjournals() - ->withRelevantData() - ->before($end)->after($start) - ->where('encrypted', 1) - ->whereNotIn('id', $exclude) - ->get(); - $encrypted = $encryptedCollection->filter( - function (\TransactionJournal $journal) use ($query) { - $strPos = strpos(strtolower($journal->description), strtolower($query)); - if ($strPos !== false) { - return $journal; - } - - return null; - } - ); - - return $collection->merge($encrypted); - } -} diff --git a/app/lib/FireflyIII/Helper/Related/RelatedInterface.php b/app/lib/FireflyIII/Helper/Related/RelatedInterface.php deleted file mode 100644 index f2072cf823..0000000000 --- a/app/lib/FireflyIII/Helper/Related/RelatedInterface.php +++ /dev/null @@ -1,29 +0,0 @@ -account->id); - } - - // otherwise (its a deposit), it's been paid into account #0. - return intval($transactions[0]->account->id); - } - - /** - * @return Collection - */ - public function getAssetAccounts() - { - /** @var \FireflyIII\Database\Account\Account $accountRepository */ - $accountRepository = \App::make('FireflyIII\Database\Account\Account'); - - /** @var Collection $list */ - $list = $accountRepository->getAccountsByType(['Default account', 'Asset account']); - $filtered = $list->filter( - function (\Account $account) { - if (intval($account->active) === 1) { - return $account; - } - return null; - } - ); - - return $filtered; - } - - /** - * @return Collection - */ - public function getBudgets() - { - /** @var \FireflyIII\Database\Budget\Budget $budgetRepository */ - $budgetRepository = \App::make('FireflyIII\Database\Budget\Budget'); - - return $budgetRepository->get(); - - } - - /** - * @return Collection - */ - public function getPiggyBanks() - { - /** @var \FireflyIII\Database\PiggyBank\PiggyBank $piggyRepository */ - $piggyRepository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank'); - - return $piggyRepository->get(); - - - } - - /** - * @return Collection - */ - public function getRepeatedExpenses() - { - /** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repRepository */ - $repRepository = \App::make('FireflyIII\Database\PiggyBank\RepeatedExpense'); - - return $repRepository->get(); - - - } - - -} diff --git a/app/lib/FireflyIII/Helper/TransactionJournal/HelperInterface.php b/app/lib/FireflyIII/Helper/TransactionJournal/HelperInterface.php deleted file mode 100644 index 06bcac0de7..0000000000 --- a/app/lib/FireflyIII/Helper/TransactionJournal/HelperInterface.php +++ /dev/null @@ -1,45 +0,0 @@ -_accounts = $accounts; - $this->_journals = $journals; - $this->_queries = \App::make('FireflyIII\Report\ReportQueryInterface'); - $this->_helper = \App::make('FireflyIII\Report\ReportHelperInterface'); - - - } - - /** - * This methods fails to take in account transfers FROM shared accounts. - * - * @param Carbon $start - * @param Carbon $end - * @param int $limit - * - * @return Collection - */ - public function expensesGroupedByAccount(Carbon $start, Carbon $end, $limit = 15) - { - $result = $this->_queries->journalsByExpenseAccount($start, $end); - $array = $this->_helper->makeArray($result); - $limited = $this->_helper->limitArray($array, $limit); - - return $limited; - - } - - /** - * Gets all the users shared and non-shared accounts combined with various meta-data - * to display the amount of money spent that month compared to what's been spend within - * budgets. - * - * @param Carbon $date - * - * @return Collection - */ - public function getAccountListBudgetOverview(Carbon $date) - { - $start = clone $date; - $start->startOfMonth(); - $end = clone $date; - $end->endOfMonth(); - $start->subDay(); - $accounts = $this->_queries->getAllAccounts($start, $end); - - $accounts->each( - function (\Account $account) use ($start, $end) { - $budgets = $this->_queries->getBudgetSummary($account, $start, $end); - $balancedAmount = $this->_queries->balancedTransactionsSum($account, $start, $end); - $array = []; - foreach ($budgets as $budget) { - $id = intval($budget->id); - $data = $budget->toArray(); - $array[$id] = $data; - } - $account->budgetInformation = $array; - $account->balancedAmount = $balancedAmount; - - } - ); - - return $accounts; - - } - - /** - * @param Carbon $date - * - * @return array - */ - public function getAccountsForMonth(Carbon $date) - { - $start = clone $date; - $start->startOfMonth()->subDay(); - $end = clone $date; - $end->endOfMonth(); - \Log::debug('Monthly report account dates: start:[' . $start->format('Y-m-d') . '] and end:[' . $end->format('Y-m-d') . ']'); - $list = $this->_queries->accountList(); - $accounts = []; - /** @var \Account $account */ - foreach ($list as $account) { - $id = intval($account->id); - /** @noinspection PhpParamsInspection */ - $accounts[$id] = [ - 'name' => $account->name, - 'startBalance' => \Steam::balance($account, $start), - 'endBalance' => \Steam::balance($account, $end) - ]; - - $accounts[$id]['difference'] = $accounts[$id]['endBalance'] - $accounts[$id]['startBalance']; - } - - return $accounts; - } - - /** - * @param Carbon $date - * - * @return Collection - */ - public function getBudgetsForMonth(Carbon $date) - { - $start = clone $date; - $start->startOfMonth(); - $end = clone $date; - $end->endOfMonth(); - // all budgets - $set = $this->_queries->getAllBudgets($date); - $budgets = $this->_helper->makeArray($set); - $amountSet = $this->_queries->journalsByBudget($start, $end); - $amounts = $this->_helper->makeArray($amountSet); - $combined = $this->_helper->mergeArrays($budgets, $amounts); - $combined[0]['spent'] = isset($combined[0]['spent']) ? $combined[0]['spent'] : 0.0; - $combined[0]['amount'] = isset($combined[0]['amount']) ? $combined[0]['amount'] : 0.0; - $combined[0]['name'] = 'No budget'; - - // find transactions to shared expense accounts, which are without a budget by default: - $transfers = $this->_queries->sharedExpenses($start, $end); - foreach ($transfers as $transfer) { - $combined[0]['spent'] += floatval($transfer->amount) * -1; - } - - return $combined; - } - - /** - * @param Carbon $date - * @param int $limit - * - * @return array - */ - public function getCategoriesForMonth(Carbon $date, $limit = 15) - { - $start = clone $date; - $start->startOfMonth(); - $end = clone $date; - $end->endOfMonth(); - // all categories. - $result = $this->_queries->journalsByCategory($start, $end); - $categories = $this->_helper->makeArray($result); - - // all transfers - $result = $this->_queries->sharedExpensesByCategory($start, $end); - $transfers = $this->_helper->makeArray($result); - $merged = $this->_helper->mergeArrays($categories, $transfers); - - // sort. - $sorted = $this->_helper->sortNegativeArray($merged); - - // limit to $limit: - $cut = $this->_helper->limitArray($sorted, $limit); - - return $cut; - } - - /** - * @param Carbon $date - * @param int $limit - * - * @return Collection - */ - public function getExpenseGroupedForMonth(Carbon $date, $limit = 15) - { - $start = clone $date; - $start->startOfMonth(); - $end = clone $date; - $end->endOfMonth(); - - $set = $this->_queries->journalsByExpenseAccount($start, $end); - $expenses = $this->_helper->makeArray($set); - -// $alt = $this->_queries->sharedExpenses($start, $end); -// $transfers = $this->_helper->makeArray($alt); -// -// $expenses[-1] = [ -// 'amount' => 0, -// 'name' => 'Transfers to shared', -// 'spent' => 0 -// ]; -// -// foreach ($transfers as $transfer) { -// $expenses[-1]['amount'] += $transfer['amount']; -// } - - $expenses = $this->_helper->sortArray($expenses); - $limited = $this->_helper->limitArray($expenses, $limit); - - return $limited; - - } - - /** - * This method gets all incomes (journals) in a list. - * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param Carbon $date - * @param bool $shared - * - * @return Collection - */ - public function getIncomeForMonth(Carbon $date, $shared = false) - { - $start = clone $date; - $start->startOfMonth(); - $end = clone $date; - $end->endOfMonth(); - - return $this->_queries->incomeByPeriod($start, $end); - - - } - - /** - * @param Carbon $date - * - * @return Collection - */ - public function getPiggyBanksForMonth(Carbon $date) - { - $start = clone $date; - $start->startOfMonth(); - $end = clone $date; - $end->endOfMonth(); - - \PiggyBank:: - leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') - ->where('accounts.user_id', \Auth::user()->id) - ->where('repeats', 0) - ->where( - function (Builder $query) use ($start, $end) { - $query->whereNull('piggy_banks.deleted_at'); - $query->orWhere( - function (Builder $query) use ($start, $end) { - $query->whereNotNull('piggy_banks.deleted_at'); - $query->where('piggy_banks.deleted_at', '>=', $start->format('Y-m-d 00:00:00')); - $query->where('piggy_banks.deleted_at', '<=', $end->format('Y-m-d 00:00:00')); - } - ); - } - ) - ->get(['piggy_banks.*']); - - - } - - /** - * @param Carbon $start - * - * @return array - */ - public function listOfMonths(Carbon $start) - { - $end = Carbon::now(); - $months = []; - while ($start <= $end) { - $months[] = [ - 'formatted' => $start->format('F Y'), - 'month' => intval($start->format('m')), - 'year' => intval($start->format('Y')), - ]; - $start->addMonth(); - } - - return $months; - } - - /** - * @param Carbon $start - * - * @return array - */ - public function listOfYears(Carbon $start) - { - $end = Carbon::now(); - $years = []; - while ($start <= $end) { - $years[] = $start->format('Y'); - $start->addYear(); - } - - return $years; - } - - /** - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function revenueGroupedByAccount(Carbon $start, Carbon $end) - { - return $this->_queries->journalsByRevenueAccount($start, $end); - - - } - - /** - * @param Carbon $date - * - * @return array - */ - public function yearBalanceReport(Carbon $date) - { - $start = clone $date; - $end = clone $date; - $sharedAccounts = []; - $sharedCollection = \Auth::user()->accounts() - ->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id') - ->where('account_meta.name', '=', 'accountRole') - ->where('account_meta.data', '=', json_encode('sharedExpense')) - ->get(['accounts.id']); - - foreach ($sharedCollection as $account) { - $sharedAccounts[] = $account->id; - } - - $accounts = $this->_accounts->getAccountsByType(['Default account', 'Asset account'])->filter( - function (\Account $account) use ($sharedAccounts) { - if (!in_array($account->id, $sharedAccounts)) { - return $account; - } - - return null; - } - ); - $report = []; - $start->startOfYear()->subDay(); - $end->endOfYear(); - - foreach ($accounts as $account) { - $report[] = [ - 'start' => \Steam::balance($account, $start), - 'end' => \Steam::balance($account, $end), - 'account' => $account, - 'shared' => $account->accountRole == 'sharedExpense' - ]; - } - - return $report; - } - -} diff --git a/app/lib/FireflyIII/Report/ReportHelperInterface.php b/app/lib/FireflyIII/Report/ReportHelperInterface.php deleted file mode 100644 index 828e322603..0000000000 --- a/app/lib/FireflyIII/Report/ReportHelperInterface.php +++ /dev/null @@ -1,64 +0,0 @@ -accounts() - ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') - ->leftJoin( - 'account_meta', function (JoinClause $join) { - $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', "accountRole"); - } - ) - ->whereIn('account_types.type', ['Default account', 'Cash account', 'Asset account']) - ->where('active', 1) - ->where( - function (Builder $query) { - $query->where('account_meta.data', '!=', '"sharedExpense"'); - $query->orWhereNull('account_meta.data'); - } - ) - ->get(['accounts.*']); - } - - /** - * This method will get a list of all expenses in a certain time period that have no budget - * and are balanced by a transfer to make up for it. - * - * @param \Account $account - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function balancedTransactionsList(\Account $account, Carbon $start, Carbon $end) - { - - $set = \TransactionJournal:: - leftJoin('transaction_group_transaction_journal', 'transaction_group_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->leftJoin( - 'transaction_group_transaction_journal as otherFromGroup', function (JoinClause $join) { - $join->on('otherFromGroup.transaction_group_id', '=', 'transaction_group_transaction_journal.transaction_group_id') - ->on('otherFromGroup.transaction_journal_id', '!=', 'transaction_journals.id'); - } - ) - ->leftJoin('transaction_journals as otherJournals', 'otherJournals.id', '=', 'otherFromGroup.transaction_journal_id') - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'otherJournals.transaction_type_id') - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0); - } - ) - ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'otherJournals.id') - ->before($end)->after($start) - ->where('transaction_types.type', 'Withdrawal') - ->where('transaction_journals.user_id', \Auth::user()->id) - ->whereNull('budget_transaction_journal.budget_id')->whereNull('transaction_journals.deleted_at') - ->whereNull('otherJournals.deleted_at') - ->where('transactions.account_id', $account->id) - ->whereNotNull('transaction_group_transaction_journal.transaction_group_id')->groupBy('transaction_journals.id') - ->get( - [ - 'transaction_journals.id as transferId', - 'transaction_journals.description as transferDescription', - 'transaction_group_transaction_journal.transaction_group_id as groupId', - 'otherFromGroup.transaction_journal_id as expenseId', - 'otherJournals.description as expenseDescription', - 'transactions.amount' - ] - ); - - return $set; - } - - /** - * This method will sum up all expenses in a certain time period that have no budget - * and are balanced by a transfer to make up for it. - * - * @param \Account $account - * @param Carbon $start - * @param Carbon $end - * - * @return float - */ - public function balancedTransactionsSum(\Account $account, Carbon $start, Carbon $end) - { - $list = $this->balancedTransactionsList($account, $start, $end); - $sum = 0; - foreach ($list as $entry) { - $sum += floatval($entry->amount); - } - - return $sum; - } - - /** - * Get a users accounts combined with various meta-data related to the start and end date. - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function getAllAccounts(Carbon $start, Carbon $end) - { - $set = \Auth::user()->accounts() - ->accountTypeIn(['Default account', 'Asset account', 'Cash account']) - ->leftJoin( - 'account_meta', function (JoinClause $join) { - $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); - } - ) - ->where( - function (Builder $query) { - $query->where('account_meta.data', '!=', '"sharedExpense"'); - $query->orWhereNull('account_meta.data'); - } - ) - ->get(['accounts.*']); - $set->each( - function (\Account $account) use ($start, $end) { - /** @noinspection PhpParamsInspection */ - $account->startBalance = \Steam::balance($account, $start); - $account->endBalance = \Steam::balance($account, $end); - } - ); - - return $set; - } - - /** - * Gets a list of all budgets and if present, the amount of the current BudgetLimit - * as well - * - * @param Carbon $date - * - * @return Collection - */ - public function getAllBudgets(Carbon $date) - { - return \Auth::user()->budgets() - ->leftJoin( - 'budget_limits', function (JoinClause $join) use ($date) { - $join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d')); - } - ) - ->get(['budgets.*', 'budget_limits.amount as amount']); - } - - /** - * Grabs a summary of all expenses grouped by budget, related to the account. - * - * @param \Account $account - * @param Carbon $start - * @param Carbon $end - * - * @return mixed - */ - public function getBudgetSummary(\Account $account, Carbon $start, Carbon $end) - { - $set = \TransactionJournal:: - leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->leftJoin('budgets', 'budgets.id', '=', 'budget_transaction_journal.budget_id') - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); - } - ) - ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') - ->before($end) - ->after($start) - ->where('accounts.id', $account->id) - ->where('transaction_journals.user_id', \Auth::user()->id) - ->where('transaction_types.type', 'Withdrawal') - ->groupBy('budgets.id') - ->orderBy('budgets.id') - ->get(['budgets.id', 'budgets.name', \DB::Raw('SUM(`transactions`.`amount`) as `amount`')]); - - return $set; - - - } - - /** - * This method returns all "income" journals in a certain period, which are both transfers from a shared account - * and "ordinary" deposits. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does - * not group and returns different fields. - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function incomeByPeriod(Carbon $start, Carbon $end) - { - return \TransactionJournal:: - leftJoin( - 'transactions as t_from', function (JoinClause $join) { - $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); - } - ) - ->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id') - ->leftJoin( - 'account_meta as acm_from', function (JoinClause $join) { - $join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole'); - } - ) - ->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 as ac_to', 't_to.account_id', '=', 'ac_to.id') - ->leftJoin( - 'account_meta as acm_to', function (JoinClause $join) { - $join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole'); - } - ) - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->where( - function ($query) { - $query->where( - function ($q) { - $q->where('transaction_types.type', 'Deposit'); - $q->where('acm_to.data', '!=', '"sharedExpense"'); - } - ); - $query->orWhere( - function ($q) { - $q->where('transaction_types.type', 'Transfer'); - $q->where('acm_from.data', '=', '"sharedExpense"'); - } - ); - } - ) - ->before($end)->after($start) - ->where('transaction_journals.user_id', \Auth::user()->id) - ->groupBy('t_from.account_id')->orderBy('transaction_journals.date') - ->get( - ['transaction_journals.id', - 'transaction_journals.description', - 'transaction_types.type', - 't_to.amount', 'transaction_journals.date', 't_from.account_id as account_id', - 'ac_from.name as name'] - ); - } - - /** - * Gets a list of expenses grouped by the budget they were filed under. - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function journalsByBudget(Carbon $start, Carbon $end) - { - return \Auth::user()->transactionjournals() - ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id') - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0); - } - ) - ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') - ->leftJoin( - 'account_meta', function (JoinClause $join) { - $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); - } - ) - ->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id') - ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) - ->where('account_meta.data', '!=', '"sharedExpense"') - ->where('transaction_types.type', 'Withdrawal') - ->groupBy('budgets.id') - ->orderBy('budgets.name', 'ASC') - ->get(['budgets.id', 'budgets.name', \DB::Raw('SUM(`transactions`.`amount`) AS `spent`')]); - } - - /** - * Gets a list of categories and the expenses therein, grouped by the relevant category. - * This result excludes transfers to shared accounts which are expenses, technically. - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function journalsByCategory(Carbon $start, Carbon $end) - { - return \Auth::user()->transactionjournals() - ->leftJoin( - 'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id' - ) - ->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id') - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0); - } - ) - ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') - ->leftJoin( - 'account_meta', function (JoinClause $join) { - $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); - } - ) - ->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id') - ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) - ->where('account_meta.data', '!=', '"sharedExpense"') - ->where('transaction_types.type', 'Withdrawal') - ->groupBy('categories.id') - ->orderBy('amount') - ->get(['categories.id', 'categories.name', \DB::Raw('SUM(`transactions`.`amount`) AS `amount`')]); - - } - - /** - * Gets a list of expense accounts and the expenses therein, grouped by that expense account. - * This result excludes transfers to shared accounts which are expenses, technically. - * - * So now it will include them! - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function journalsByExpenseAccount(Carbon $start, Carbon $end) - { - return \TransactionJournal:: - leftJoin( - 'transactions as t_from', function (JoinClause $join) { - $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); - } - ) - ->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id') - ->leftJoin( - 'account_meta as acm_from', function (JoinClause $join) { - $join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole'); - } - ) - ->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 as ac_to', 't_to.account_id', '=', 'ac_to.id') - ->leftJoin( - 'account_meta as acm_to', function (JoinClause $join) { - $join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole'); - } - ) - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - - ->where( - function ($query) { - $query->where( - function ($q) { - $q->where('transaction_types.type', 'Withdrawal'); - $q->where('acm_from.data', '!=', '"sharedExpense"'); - } - ); - $query->orWhere( - function ($q) { - $q->where('transaction_types.type', 'Transfer'); - $q->where('acm_to.data', '=', '"sharedExpense"'); - } - ); - } - ) - - - ->before($end) - ->after($start) - ->where('transaction_journals.user_id', \Auth::user()->id) - ->groupBy('t_to.account_id') - ->orderBy('amount', 'DESC') - ->get(['t_to.account_id as id', 'ac_to.name as name', \DB::Raw('SUM(t_to.amount) as `amount`')]); - } - - /** - * This method returns all deposits into asset accounts, grouped by the revenue account, - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function journalsByRevenueAccount(Carbon $start, Carbon $end) - { - return \TransactionJournal:: - leftJoin( - 'transactions as t_from', function (JoinClause $join) { - $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); - } - ) - ->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id') - ->leftJoin( - 'account_meta as acm_from', function (JoinClause $join) { - $join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole'); - } - ) - ->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 as ac_to', 't_to.account_id', '=', 'ac_to.id') - ->leftJoin( - 'account_meta as acm_to', function (JoinClause $join) { - $join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole'); - } - ) - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->where( - function ($query) { - $query->where( - function ($q) { - $q->where('transaction_types.type', 'Deposit'); - $q->where('acm_to.data', '!=', '"sharedExpense"'); - } - ); - $query->orWhere( - function ($q) { - $q->where('transaction_types.type', 'Transfer'); - $q->where('acm_from.data', '=', '"sharedExpense"'); - } - ); - } - ) - ->before($end)->after($start) - ->where('transaction_journals.user_id', \Auth::user()->id) - ->groupBy('t_from.account_id')->orderBy('amount') - ->get(['t_from.account_id as account_id', 'ac_from.name as name', \DB::Raw('SUM(t_from.amount) as `amount`')]); - } - - /** - * With an equally misleading name, this query returns are transfers to shared accounts. These are considered - * expenses. - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function sharedExpenses(Carbon $start, Carbon $end) - { - return \TransactionJournal:: - leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where( - 'transactions.amount', '>', 0 - ); - } - ) - ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') - ->leftJoin( - 'account_meta', function (JoinClause $join) { - $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); - } - ) - ->where('account_meta.data', '"sharedExpense"') - ->after($start) - ->before($end) - ->where('transaction_types.type', 'Transfer') - ->where('transaction_journals.user_id', \Auth::user()->id) - ->get( - ['transaction_journals.id', 'transaction_journals.description', 'transactions.account_id', 'accounts.name', - 'transactions.amount'] - ); - - } - - /** - * With a slightly misleading name, this query returns all transfers to shared accounts - * which are technically expenses, since it won't be just your money that gets spend. - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function sharedExpensesByCategory(Carbon $start, Carbon $end) - { - return \TransactionJournal:: - leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where( - 'transactions.amount', '>', 0 - ); - } - ) - ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') - ->leftJoin( - 'account_meta', function (JoinClause $join) { - $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); - } - ) - ->leftJoin( - 'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id' - ) - ->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id') - ->where('account_meta.data', '"sharedExpense"') - ->after($start) - ->before($end) - ->where('transaction_types.type', 'Transfer') - ->where('transaction_journals.user_id', \Auth::user()->id) - ->groupBy('categories.name') - ->get( - [ - 'categories.id', - 'categories.name as name', - \DB::Raw('SUM(`transactions`.`amount`) * -1 AS `amount`') - ] - ); - } -} diff --git a/app/lib/FireflyIII/Shared/Facade/DateKit.php b/app/lib/FireflyIII/Shared/Facade/DateKit.php deleted file mode 100644 index afe493b866..0000000000 --- a/app/lib/FireflyIII/Shared/Facade/DateKit.php +++ /dev/null @@ -1,24 +0,0 @@ -password = $password; - $user->reset = \Str::random(32); // new one. - $user->forceSave(); - $email = $user->email; - - - $data = ['password' => $password]; - try { - \Mail::send( - ['emails.user.register-html', 'emails.user.register-text'], $data, function (Message $message) use ($email) { - - $message->to($email, $email)->subject('Welcome to Firefly!'); - } - ); - } catch (Swift_RfcComplianceException $e) { - } - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function sendResetVerification(\User $user) - { - $reset = \Str::random(32); - $user->reset = $reset; - $user->forceSave(); - $email = $user->email; - - $data = ['reset' => $reset]; - try { - \Mail::send( - ['emails.user.remindMe-html', 'emails.user.remindMe-text'], $data, function (Message $message) use ($email) { - $message->to($email, $email)->subject('Forgot your password?'); - } - ); - } catch (Swift_RfcComplianceException $e) { - \Log::error($e->getMessage()); - return false; - } catch(Swift_TransportException $e) { - \Log::error($e->getMessage()); - return false; - } catch(\Exception $e) { - \Log::error($e->getMessage()); - return false; - } - return true; - - - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function sendVerificationMail(\User $user) - { - - $reset = \Str::random(32); - $user->reset = $reset; - $user->forceSave(); - $email = $user->email; - $data = ['reset' => $reset]; - - try { - \Mail::send( - ['emails.user.verify-html', 'emails.user.verify-text'], $data, function (Message $message) use ($email) { - - $message->to($email, $email)->subject('Verify your e-mail address.'); - } - ); - } catch (Swift_RfcComplianceException $e) { - \Log::error($e->getMessage()); - return false; - } catch(Swift_TransportException $e) { - \Log::error($e->getMessage()); - return false; - } catch(\Exception $e) { - \Log::error($e->getMessage()); - return false; - } - return true; - } - -} diff --git a/app/lib/FireflyIII/Shared/Mail/RegistrationInterface.php b/app/lib/FireflyIII/Shared/Mail/RegistrationInterface.php deleted file mode 100644 index df104cc50a..0000000000 --- a/app/lib/FireflyIII/Shared/Mail/RegistrationInterface.php +++ /dev/null @@ -1,34 +0,0 @@ -getCurrencySymbol(); - - return $this->formatWithSymbol($currencySymbol, $amount, $coloured); - - - } - - /** - * @return string - */ - public function getCurrencySymbol() - { - if (defined('FFCURRENCYSYMBOL')) { - return FFCURRENCYSYMBOL; - } - if (\Cache::has('FFCURRENCYSYMBOL')) { - define('FFCURRENCYSYMBOL', \Cache::get('FFCURRENCYSYMBOL')); - - return FFCURRENCYSYMBOL; - } - - /** @var \FireflyIII\Database\TransactionCurrency\TransactionCurrency $currencies */ - $currencies = \App::make('FireflyIII\Database\TransactionCurrency\TransactionCurrency'); - - /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ - $preferences = \App::make('FireflyIII\Shared\Preferences\Preferences'); - - $currencyPreference = $preferences->get('currencyPreference', 'EUR'); - $currency = $currencies->findByCode($currencyPreference->data); - - \Cache::forever('FFCURRENCYSYMBOL', $currency->symbol); - - define('FFCURRENCYSYMBOL', $currency->symbol); - - return $currency->symbol; - } - - /** - * @param string $symbol - * @param float $amount - * @param bool $coloured - * - * @return string - */ - protected function formatWithSymbol($symbol, $amount, $coloured = true) - { - $amount = floatval($amount); - $amount = round($amount, 2); - $string = number_format($amount, 2, ',', '.'); - - if ($coloured === true) { - if ($amount === 0.0) { - return '' . $symbol . ' ' . $string . ''; - } - if ($amount > 0) { - return '' . $symbol . ' ' . $string . ''; - } - - return '' . $symbol . ' ' . $string . ''; - } - - // € - return $symbol . ' ' . $string; - } - - /** - * @param \TransactionJournal $journal - * @param float $amount - * @param bool $coloured - * - * @return string - */ - public function formatJournal(\TransactionJournal $journal, $amount, $coloured = true) - { - $symbol = $journal->transactionCurrency->symbol; - - return $this->formatWithSymbol($symbol, $amount, $coloured); - - - } - - /** - * @param \Transaction $transaction - * @param bool $coloured - * - * @return string - */ - public function formatTransaction(\Transaction $transaction, $coloured = true) - { - $symbol = $transaction->transactionJournal->transactionCurrency->symbol; - $amount = floatval($transaction->amount); - - return $this->formatWithSymbol($symbol, $amount, $coloured); - - - } - - /** - * @return string - */ - public function getCurrencyCode() - { - if (defined('FFCURRENCYCODE')) { - return FFCURRENCYCODE; - } - if (\Cache::has('FFCURRENCYCODE')) { - define('FFCURRENCYCODE', \Cache::get('FFCURRENCYCODE')); - - return FFCURRENCYCODE; - } - - /** @var \FireflyIII\Database\TransactionCurrency\TransactionCurrency $currencies */ - $currencies = \App::make('FireflyIII\Database\TransactionCurrency\TransactionCurrency'); - - /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ - $preferences = \App::make('FireflyIII\Shared\Preferences\Preferences'); - - $currencyPreference = $preferences->get('currencyPreference', 'EUR'); - $currency = $currencies->findByCode($currencyPreference->data); - - \Cache::forever('FFCURRENCYCODE', $currency->code); - - define('FFCURRENCYCODE', $currency->code); - - return $currency->code; - } - - /** - * @return string - */ - public function getDefaultCurrency() - { - /** @var \FireflyIII\Database\TransactionCurrency\TransactionCurrency $currencies */ - $currencies = \App::make('FireflyIII\Database\TransactionCurrency\TransactionCurrency'); - - /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ - $preferences = \App::make('FireflyIII\Shared\Preferences\Preferences'); - - $currencyPreference = $preferences->get('currencyPreference', 'EUR'); - $currency = $currencies->findByCode($currencyPreference->data); - - return $currency; - } - -} diff --git a/app/lib/FireflyIII/Shared/Toolkit/Filter.php b/app/lib/FireflyIII/Shared/Toolkit/Filter.php deleted file mode 100644 index 0602b72624..0000000000 --- a/app/lib/FireflyIII/Shared/Toolkit/Filter.php +++ /dev/null @@ -1,253 +0,0 @@ -setSessionRangeValue(); - $start = \Session::has('start') ? \Session::get('start') : new Carbon; - $start = $this->updateStartDate($range, $start); - $end = $this->updateEndDate($range, $start); - $period = $this->periodName($range, $start); - $prev = $this->previous($range, clone $start); - $next = $this->next($range, clone $start); - - \Session::put('start', $start); - \Session::put('end', $end); - \Session::put('range', $range); - \Session::put('period', $period); - \Session::put('prev', $this->periodName($range, $prev)); - \Session::put('next', $this->periodName($range, $next)); - - return null; - - } - - /** - * Checks and sets the currently set 'range' or defaults to a session - * and if that fails, defaults to 1M. Always returns the final value. - * - * @return string - */ - public function setSessionRangeValue() - { - if (!is_null(\Session::get('range'))) { - // @codeCoverageIgnoreStart - $range = \Session::get('range'); - // @codeCoverageIgnoreEnd - } else { - /** @var \FireflyIII\Shared\Preferences\PreferencesInterface $preferences */ - $preferences = \App::make('FireflyIII\Shared\Preferences\PreferencesInterface'); - $viewRange = $preferences->get('viewRange', '1M'); - - // default range: - $range = $viewRange->data; - \Session::put('range', $range); - } - - return $range; - - } - - /** - * @param $range - * @param Carbon $start - * - * @return Carbon - * @throws FireflyException - * @codeCoverageIgnore - */ - protected function updateStartDate($range, Carbon $start) - { - $functionMap = [ - '1D' => 'startOfDay', - '1W' => 'startOfWeek', - '1M' => 'startOfMonth', - '3M' => 'firstOfQuarter', - '1Y' => 'startOfYear', - ]; - if (isset($functionMap[$range])) { - $function = $functionMap[$range]; - $start->$function(); - - return $start; - } - if ($range == '6M') { - if (intval($start->format('m')) >= 7) { - $start->startOfYear()->addMonths(6); - } else { - $start->startOfYear(); - } - - return $start; - } - throw new FireflyException('updateStartDate cannot handle $range ' . $range); - } - - /** - * @param $range - * @param Carbon $start - * - * @return Carbon - * @throws FireflyException - * @codeCoverageIgnore - */ - protected function updateEndDate($range, Carbon $start) - { - $functionMap = [ - '1D' => 'endOfDay', - '1W' => 'endOfWeek', - '1M' => 'endOfMonth', - '3M' => 'lastOfQuarter', - '1Y' => 'endOfYear', - ]; - $end = clone $start; - - if (isset($functionMap[$range])) { - $function = $functionMap[$range]; - $end->$function(); - - return $end; - } - if ($range == '6M') { - if (intval($start->format('m')) >= 7) { - $end->endOfYear(); - } else { - $end->startOfYear()->addMonths(6); - } - - return $end; - } - throw new FireflyException('updateEndDate cannot handle $range ' . $range); - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - * - * @param $range - * @param Carbon $date - * - * @return string - * @throws FireflyException - * @codeCoverageIgnore - */ - protected function periodName($range, Carbon $date) - { - $formatMap = [ - '1D' => 'jS F Y', - '1W' => '\w\e\ek W, Y', - '1M' => 'F Y', - '1Y' => 'Y', - ]; - if (isset($formatMap[$range])) { - return $date->format($formatMap[$range]); - } - if ($range == '3M') { - $month = intval($date->format('m')); - - return 'Q' . ceil(($month / 12) * 4) . ' ' . $date->format('Y'); - } - if ($range == '6M') { - $month = intval($date->format('m')); - $half = ceil(($month / 12) * 2); - $halfName = $half == 1 ? 'first' : 'second'; - - return $halfName . ' half of ' . $date->format('d-m-Y'); - } - throw new FireflyException('No _periodName() for range "' . $range . '"'); - } - - /** - * @param $range - * @param Carbon $date - * - * @return Carbon - * @throws FireflyException - */ - public function previous($range, Carbon $date) - { - $functionMap = [ - '1D' => 'Day', - '1W' => 'Week', - '1M' => 'Month', - '1Y' => 'Year' - ]; - - if (isset($functionMap[$range])) { - $startFunction = 'startOf' . $functionMap[$range]; - $subFunction = 'sub' . $functionMap[$range]; - $date->$startFunction()->$subFunction(); - - return $date; - } - if ($range == '3M') { - $date->firstOfQuarter()->subMonths(3)->firstOfQuarter(); - - return $date; - } - if ($range == '6M') { - $month = intval($date->format('m')); - $date->startOfYear(); - if ($month <= 6) { - $date->subMonths(6); - } - - return $date; - } - throw new FireflyException('Cannot do _previous() on ' . $range); - } - - /** - * @param $range - * @param Carbon $date - * - * @return Carbon - * @throws FireflyException - */ - public function next($range, Carbon $date) - { - switch ($range) { - case '1D': - $date->endOfDay()->addDay(); - break; - case '1W': - $date->endOfWeek()->addDay()->startOfWeek(); - break; - case '1M': - $date->endOfMonth()->addDay()->startOfMonth(); - break; - case '3M': - $date->lastOfQuarter()->addDay(); - break; - case '6M': - if (intval($date->format('m')) >= 7) { - $date->startOfYear()->addYear(); - } else { - $date->startOfYear()->addMonths(6); - } - break; - case '1Y': - $date->startOfYear()->addYear(); - break; - default: - throw new FireflyException('Cannot do _next() on ' . $range); - break; - } - - return $date; - } -} diff --git a/app/lib/FireflyIII/Shared/Toolkit/Form.php b/app/lib/FireflyIII/Shared/Toolkit/Form.php deleted file mode 100644 index 1f51fe357a..0000000000 --- a/app/lib/FireflyIII/Shared/Toolkit/Form.php +++ /dev/null @@ -1,47 +0,0 @@ -id); - $title = null; - - foreach ($fields as $field) { - if (isset($entry->$field)) { - $title = $entry->$field; - } - } - $selectList[$id] = $title; - } - - - return $selectList; - } -} diff --git a/app/lib/FireflyIII/Shared/Toolkit/Navigation.php b/app/lib/FireflyIII/Shared/Toolkit/Navigation.php deleted file mode 100644 index ce99351190..0000000000 --- a/app/lib/FireflyIII/Shared/Toolkit/Navigation.php +++ /dev/null @@ -1,69 +0,0 @@ -setSessionRangeValue(); - $start = \Session::get('start', Carbon::now()->startOfMonth()); - - /* - * Add some period to $start. - */ - $next = $filter->next($range, clone $start); - - /* - * Save in session: - */ - \Session::put('start', $next); - - return true; - } - - /** - * @return bool - * @throws FireflyException - */ - public function prev() - { - /* - * Get the start date and the range from the session - */ - $filter = new Filter; - - $range = $filter->setSessionRangeValue(); - $start = \Session::get('start', Carbon::now()->startOfMonth()); - - /* - * Subtract some period to $start. - */ - $prev = $filter->previous($range, clone $start); - - /* - * Save in session: - */ - \Session::put('start', $prev); - - return true; - } -} diff --git a/app/lib/FireflyIII/Shared/Toolkit/Reminders.php b/app/lib/FireflyIII/Shared/Toolkit/Reminders.php deleted file mode 100644 index 11b75259e1..0000000000 --- a/app/lib/FireflyIII/Shared/Toolkit/Reminders.php +++ /dev/null @@ -1,106 +0,0 @@ -remindersable)) { - - case 'PiggyBank': - $start = new Carbon; - $end = !is_null($reminder->remindersable->targetdate) ? clone $reminder->remindersable->targetdate : new Carbon; - $reminders = 0; - while ($start <= $end) { - $reminders++; - $start = \DateKit::addPeriod($start, $reminder->remindersable->reminder, $reminder->remindersable->reminder_skip); - } - /* - * Now find amount yet to save. - */ - $repetition = $reminder->remindersable->currentRelevantRep(); - $leftToSave = floatval($reminder->remindersable->targetamount) - floatval($repetition->currentamount); - $reminders = $reminders == 0 ? 1 : $reminders; - - return $leftToSave / $reminders; - break; - default: - throw new FireflyException('Cannot handle class ' . get_class($reminder->remindersable) . ' in amountForReminder.'); - break; - } - } - - /** - * - */ - public function getReminders() - { - $reminders = \Auth::user()->reminders() - ->where('active', 1) - ->where('startdate', '<=', Carbon::now()->format('Y-m-d')) - ->where('enddate', '>=', Carbon::now()->format('Y-m-d')) - ->get(); - - return $reminders; - } - - /** - * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. - */ - public function updateReminders() - { - /** @var Collection $set */ - $set = \PiggyBank::leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') - ->where('accounts.user_id', \Auth::user()->id) - ->whereNotNull('reminder')->get(['piggy_banks.*']); - - - $today = Carbon::now(); - - /** @var \PiggyBank $piggyBank */ - foreach ($set as $piggyBank) { - /** @var \PiggyBankRepetition $repetition */ - $repetition = $piggyBank->currentRelevantRep(); - $start = \DateKit::startOfPeriod($today, $piggyBank->reminder); - if ($repetition->targetdate && $repetition->targetdate <= $today) { - // break when no longer relevant: - continue; - } - $end = \DateKit::endOfPeriod(clone $start, $piggyBank->reminder); - // should have a reminder for this period: - /** @var Collection $reminders */ - $reminders = $piggyBank->reminders()->dateIs($start, $end)->get(); - if ($reminders->count() == 0) { - // create new! - $reminder = new \Reminder; - $reminder->startdate = $start; - $reminder->enddate = $end; - $reminder->active = 1; - $reminder->user()->associate(\Auth::getUser()); - $reminder->remindersable_id = $piggyBank->id; - $reminder->remindersable_type = 'PiggyBank'; - $reminder->save(); - } - } - } -} diff --git a/app/lib/FireflyIII/Shared/Toolkit/Steam.php b/app/lib/FireflyIII/Shared/Toolkit/Steam.php deleted file mode 100644 index 584fa13ee8..0000000000 --- a/app/lib/FireflyIII/Shared/Toolkit/Steam.php +++ /dev/null @@ -1,85 +0,0 @@ -transactions()->leftJoin( - 'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id' - )->where('transaction_journals.date', '<=', $date->format('Y-m-d'))->sum('transactions.amount') - ); - - return $balance; - } - - /** - * @codeCoverageIgnore - * @param $boolean - * - * @return string - */ - public function boolString($boolean) - { - if ($boolean === true) { - return 'BOOLEAN TRUE'; - } - if ($boolean === false) { - return 'BOOLEAN FALSE'; - } - - return 'NO BOOLEAN: ' . $boolean; - } - - /** - * @param \PiggyBank $piggyBank - * @param \PiggyBankRepetition $repetition - * - * @return int - */ - public function percentage(\PiggyBank $piggyBank, \PiggyBankRepetition $repetition) - { - $pct = $repetition->currentamount / $piggyBank->targetamount * 100; - if ($pct > 100) { - // @codeCoverageIgnoreStart - return 100; - // @codeCoverageIgnoreEnd - } else { - return floor($pct); - } - } - - /** - * @codeCoverageIgnore - * @throws \Exception - */ - public function removeEmptyBudgetLimits() - { - $user = \Auth::user(); - if ($user) { - \BudgetLimit::where('amount', 0)->delete(); - } - } - -} diff --git a/app/lib/FireflyIII/Shared/Validation/FireflyValidator.php b/app/lib/FireflyIII/Shared/Validation/FireflyValidator.php deleted file mode 100644 index 33795d563b..0000000000 --- a/app/lib/FireflyIII/Shared/Validation/FireflyValidator.php +++ /dev/null @@ -1,31 +0,0 @@ -app->validator->resolver( - function ($translator, $data, $rules, $messages) { - return new FireflyValidator($translator, $data, $rules, $messages); - } - ); - } - - public function register() - { - } -} diff --git a/app/models/Account.php b/app/models/Account.php deleted file mode 100644 index 9bf3bbe4a9..0000000000 --- a/app/models/Account.php +++ /dev/null @@ -1,156 +0,0 @@ - [ - 'name' => 'required|between:1,100', - 'user_id' => 'required|exists:users,id', - 'account_type_id' => 'required|exists:account_types,id', - 'active' => 'required|boolean' - ], - 'form_input' => [ - 'name' => 'required|between:1,100', - 'active' => 'required|boolean', - ] - ]; - - /** - * Account type. - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function accountType() - { - return $this->belongsTo('AccountType'); - } - - /** - * - * @param $fieldName - * - * @return mixed - */ - public function getMeta($fieldName) - { - foreach ($this->accountMeta as $meta) { - if ($meta->name == $fieldName) { - return $meta->data; - } - } - - return null; - - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function piggyBanks() - { - return $this->hasMany('PiggyBank'); - } - - /** - * - * @param EloquentBuilder $query - * @param array $types - */ - public function scopeAccountTypeIn(EloquentBuilder $query, array $types) - { - if (is_null($this->joinedAccountTypes)) { - $query->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id'); - $this->joinedAccountTypes = true; - } - $query->whereIn('account_types.type', $types); - } - - /** - * - * @param EloquentBuilder $query - * @param string $field - */ - public function scopeWithMeta(EloquentBuilder $query, $field = 'accountRole') - { - $query->leftJoin( - 'account_meta', function (JoinClause $join) use ($field) { - $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', $field); - } - ); - } - - /** - * Transactions. - * - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function transactions() - { - return $this->hasMany('Transaction'); - } - - /** - * @param $fieldName - * @param $fieldValue - * - * @return AccountMeta - */ - public function updateMeta($fieldName, $fieldValue) - { - $meta = $this->accountMeta()->get(); - /** @var AccountMeta $entry */ - foreach ($meta as $entry) { - if ($entry->name == $fieldName) { - $entry->data = $fieldValue; - $entry->save(); - - return $entry; - } - } - $meta = new AccountMeta; - $meta->account()->associate($this); - $meta->name = $fieldName; - $meta->data = $fieldValue; - $meta->save(); - - return $meta; - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function accountMeta() - { - return $this->hasMany('AccountMeta'); - } - - /** - * User - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function user() - { - return $this->belongsTo('User'); - } - - -} diff --git a/app/models/AccountType.php b/app/models/AccountType.php deleted file mode 100644 index eb3f495e87..0000000000 --- a/app/models/AccountType.php +++ /dev/null @@ -1,25 +0,0 @@ - ['required', 'between:1,50', 'alphabasic'], - 'editable' => 'required|boolean', - - ]; - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function accounts() - { - return $this->hasMany('Account'); - } -} diff --git a/app/models/Bill.php b/app/models/Bill.php deleted file mode 100644 index bc5500ebe2..0000000000 --- a/app/models/Bill.php +++ /dev/null @@ -1,49 +0,0 @@ - 'required|exists:users,id', - 'name' => 'required|between:1,255|min:1', - 'match' => 'required', - 'amount_max' => 'required|between:0,65536', - 'amount_min' => 'required|between:0,65536', - 'date' => 'required|date', - 'active' => 'between:0,1', - 'automatch' => 'between:0,1', - 'repeat_freq' => 'required|in:daily,weekly,monthly,quarterly,half-year,yearly', - 'skip' => 'required|between:0,31',]; - protected $fillable = ['user_id', 'name', 'match', 'amount_min', 'amount_max', 'date', 'repeat_freq', 'skip', 'active', 'automatch']; - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'date']; - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function transactionjournals() - { - return $this->hasMany('TransactionJournal'); - } - - - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function user() - { - return $this->belongsTo('User'); - } -} diff --git a/app/models/Budget.php b/app/models/Budget.php deleted file mode 100644 index 83368d9143..0000000000 --- a/app/models/Budget.php +++ /dev/null @@ -1,50 +0,0 @@ - 'exists:users,id|required', - 'name' => 'required|between:1,100|alphabasic', - ]; - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough - */ - public function limitrepetitions() - { - return $this->hasManyThrough('LimitRepetition', 'BudgetLimit', 'budget_id'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function budgetlimits() - { - return $this->hasMany('BudgetLimit'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany - */ - public function transactionjournals() - { - return $this->belongsToMany('TransactionJournal', 'budget_transaction_journal', 'budget_id'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function user() - { - return $this->belongsTo('User'); - } - -} diff --git a/app/models/BudgetLimit.php b/app/models/BudgetLimit.php deleted file mode 100644 index 192639fda8..0000000000 --- a/app/models/BudgetLimit.php +++ /dev/null @@ -1,49 +0,0 @@ - 'required|exists:budgets,id', - 'startdate' => 'required|date', - 'amount' => 'numeric|required|min:0.01', - 'repeats' => 'required|boolean', - 'repeat_freq' => 'required|in:daily,weekly,monthly,quarterly,half-year,yearly' - - ]; - - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function budget() - { - return $this->belongsTo('Budget'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function limitrepetitions() - { - return $this->hasMany('LimitRepetition'); - } - - - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'startdate', 'enddate']; - } - - -} diff --git a/app/models/Category.php b/app/models/Category.php deleted file mode 100644 index dab2639a0b..0000000000 --- a/app/models/Category.php +++ /dev/null @@ -1,49 +0,0 @@ - 'exists:users,id|required', - 'name' => 'required|between:1,100|alphabasic', - ]; - - /** - * remove this method in favour of something in the FireflyIII libraries. - * - * @return Carbon - */ - public function lastActionDate() - { - $transaction = $this->transactionjournals()->orderBy('updated_at', 'DESC')->first(); - if (is_null($transaction)) { - return null; - } - - return $transaction->date; - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany - */ - public function transactionjournals() - { - return $this->belongsToMany('TransactionJournal', 'category_transaction_journal', 'category_id'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function user() - { - return $this->belongsTo('User'); - } -} diff --git a/app/models/Component.php b/app/models/Component.php deleted file mode 100644 index e09edbe19b..0000000000 --- a/app/models/Component.php +++ /dev/null @@ -1,20 +0,0 @@ - 'exists:users,id|required', - 'name' => 'required|between:1,100|alphabasic', - 'class' => 'required', - ]; - protected $dates = ['deleted_at', 'created_at', 'updated_at']; - protected $fillable = ['name', 'user_id','class']; - protected $table = 'components'; - use ValidatingTrait; -} diff --git a/app/models/LimitRepetition.php b/app/models/LimitRepetition.php deleted file mode 100644 index afb0b3c439..0000000000 --- a/app/models/LimitRepetition.php +++ /dev/null @@ -1,54 +0,0 @@ - 'required|exists:budgetlimits,id', - 'startdate' => 'required|date', - 'enddate' => 'required|date', - 'amount' => 'numeric|required|min:0.01', - ]; - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function budgetLimit() - { - return $this->belongsTo('BudgetLimit'); - } - - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'startdate', 'enddate']; - } - - /** - * - * @return float - */ - public function spentInRepetition() - { - $sum = \DB::table('transactions') - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budget_transaction_journal.budget_id') - ->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') - ->where('transaction_journals.date', '>=', $this->startdate->format('Y-m-d')) - ->where('transaction_journals.date', '<=', $this->enddate->format('Y-m-d')) - ->where('transactions.amount', '>', 0) - ->where('limit_repetitions.id', '=', $this->id) - ->sum('transactions.amount'); - - return floatval($sum); - } -} diff --git a/app/models/PiggybankEvent.php b/app/models/PiggybankEvent.php deleted file mode 100644 index 1861c45319..0000000000 --- a/app/models/PiggybankEvent.php +++ /dev/null @@ -1,42 +0,0 @@ - 'required|exists:piggy_banks,id', - 'date' => 'required|date', - 'amount' => 'required|numeric' - ]; - use ValidatingTrait; - - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'date']; - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function piggyBank() - { - return $this->belongsTo('PiggyBank'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function transactionJournal() - { - return $this->belongsTo('TransactionJournal'); - } - -} diff --git a/app/models/PiggybankRepetition.php b/app/models/PiggybankRepetition.php deleted file mode 100644 index e38eabd4b4..0000000000 --- a/app/models/PiggybankRepetition.php +++ /dev/null @@ -1,54 +0,0 @@ - 'required|exists:piggy_banks,id', - 'targetdate' => 'date', - 'startdate' => 'date', - 'currentamount' => 'required|numeric']; - - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'targetdate', 'startdate']; - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function piggyBank() - { - return $this->belongsTo('PiggyBank'); - } - - /** - * @param EloquentBuilder $query - * @param Carbon $date - */ - public function scopeStarts(EloquentBuilder $query, Carbon $date) - { - $query->where('startdate', $date->format('Y-m-d 00:00:00')); - } - - /** - * @param EloquentBuilder $query - * @param Carbon $date - */ - public function scopeTargets(EloquentBuilder $query, Carbon $date) - { - $query->where('targetdate', $date->format('Y-m-d 00:00:00')); - } - - -} diff --git a/app/models/Reminder.php b/app/models/Reminder.php deleted file mode 100644 index b9c7b326b8..0000000000 --- a/app/models/Reminder.php +++ /dev/null @@ -1,58 +0,0 @@ -morphTo(); - } - - /** - * @param EloquentBuilder $query - * @param Carbon $start - * @param Carbon $end - * - * @return mixed - */ - public function scopeDateIs(EloquentBuilder $query, Carbon $start, Carbon $end) - { - return $query->where('startdate', $start->format('Y-m-d 00:00:00'))->where('enddate', $end->format('Y-m-d 00:00:00')); - } - - /** - * User - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function user() - { - return $this->belongsTo('User'); - } - - -} diff --git a/app/models/Transaction.php b/app/models/Transaction.php deleted file mode 100644 index bb5c423bec..0000000000 --- a/app/models/Transaction.php +++ /dev/null @@ -1,114 +0,0 @@ - 'numeric|required|exists:accounts,id', - 'transaction_journal_id' => 'numeric|required|exists:transaction_journals,id', - 'description' => 'between:1,255', - 'amount' => 'required|between:-65536,65536|not_in:0,0.00',]; - - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function account() - { - return $this->belongsTo('Account'); - } - - /** - * @param EloquentBuilder $query - * @param Account $account - */ - public function scopeAccountIs(EloquentBuilder $query, Account $account) - { - $query->where('transactions.account_id', $account->id); - } - - /** - * @param EloquentBuilder $query - * @param Carbon $date - */ - public function scopeAfter(EloquentBuilder $query, Carbon $date) - { - if (is_null($this->joinedJournals)) { - $query->leftJoin( - 'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id' - ); - $this->joinedJournals = true; - } - $query->where('transaction_journals.date', '>=', $date->format('Y-m-d')); - } - - /** - * @param EloquentBuilder $query - * @param Carbon $date - */ - public function scopeBefore(EloquentBuilder $query, Carbon $date) - { - if (is_null($this->joinedJournals)) { - $query->leftJoin( - 'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id' - ); - $this->joinedJournals = true; - } - $query->where('transaction_journals.date', '<=', $date->format('Y-m-d')); - } - - /** - * @param EloquentBuilder $query - * @param $amount - */ - public function scopeLessThan(EloquentBuilder $query, $amount) - { - $query->where('amount', '<', $amount); - } - - /** - * @param EloquentBuilder $query - * @param $amount - */ - public function scopeMoreThan(EloquentBuilder $query, $amount) - { - $query->where('amount', '>', $amount); - } - - /** - * @param EloquentBuilder $query - * @param array $types - */ - public function scopeTransactionTypes(EloquentBuilder $query, array $types) - { - if (is_null($this->joinedJournals)) { - $query->leftJoin( - 'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id' - ); - $this->joinedJournals = true; - } - if (is_null($this->joinedTransactionTypes)) { - $query->leftJoin( - 'transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id' - ); - $this->joinedTransactionTypes = true; - } - $query->whereIn('transaction_types.type', $types); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function transactionJournal() - { - return $this->belongsTo('TransactionJournal'); - } -} diff --git a/app/models/TransactionCurrency.php b/app/models/TransactionCurrency.php deleted file mode 100644 index a72d8168df..0000000000 --- a/app/models/TransactionCurrency.php +++ /dev/null @@ -1,29 +0,0 @@ - 'required|alpha|between:3,3|min:3|max:3', - 'name' => 'required|between:3,48|min:3|max:48', - 'symbol' => 'required|between:1,8|min:1|max:8', - ]; - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function transactionJournals() - { - return $this->hasMany('TransactionJournal'); - } - -} diff --git a/app/models/TransactionGroup.php b/app/models/TransactionGroup.php deleted file mode 100644 index dea100af17..0000000000 --- a/app/models/TransactionGroup.php +++ /dev/null @@ -1,45 +0,0 @@ - 'required|in:balance' - ]; - - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at']; - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function transactionjournals() - { - return $this->belongsToMany('TransactionJournal'); - } - - /** - * User - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function user() - { - return $this->belongsTo('User'); - } - - -} diff --git a/app/models/TransactionRelation.php b/app/models/TransactionRelation.php deleted file mode 100644 index cd34f354e9..0000000000 --- a/app/models/TransactionRelation.php +++ /dev/null @@ -1,10 +0,0 @@ -hasMany('TransactionJournal'); - } - -} diff --git a/app/models/User.php b/app/models/User.php deleted file mode 100644 index a3dc1a47ce..0000000000 --- a/app/models/User.php +++ /dev/null @@ -1,102 +0,0 @@ - 'required|email|unique:users,email', - 'password' => 'required|between:60,60', - 'reset' => 'between:32,32', - ]; - protected $table = 'users'; - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function accounts() - { - return $this->hasMany('Account'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function bills() - { - return $this->hasMany('Bill'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function budgets() - { - return $this->hasMany('Budget'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function categories() - { - return $this->hasMany('Category'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough - */ - public function piggyBanks() - { - return $this->hasManyThrough('PiggyBank', 'Account'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function preferences() - { - return $this->hasMany('Preference'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function reminders() - { - return $this->hasMany('Reminder'); - } - - /** - * @param $value - */ - public function setPasswordAttribute($value) - { - $this->attributes['password'] = Hash::make($value); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function transactionjournals() - { - return $this->hasMany('TransactionJournal'); - } - - -} diff --git a/app/start/artisan.php b/app/start/artisan.php deleted file mode 100644 index 8e36314924..0000000000 --- a/app/start/artisan.php +++ /dev/null @@ -1,14 +0,0 @@ -prepareForTests(); - - } - - static public function setupBeforeClass() - { - f::loadFactories(__DIR__ . '/factories'); - } - - public function tearDown() - { - //m::close(); - } - - /** - * Migrates the database and set the mailer to 'pretend'. - * This will cause the tests to run quickly. - * - */ - private function prepareForTests() - { - Artisan::call('migrate'); - Mail::pretend(true); - } -} diff --git a/app/tests/factories/Account.php b/app/tests/factories/Account.php deleted file mode 100644 index 3d4032b4d1..0000000000 --- a/app/tests/factories/Account.php +++ /dev/null @@ -1,10 +0,0 @@ - 'factory|User', - 'account_type_id' => 'factory|AccountType', - 'name' => 'word', - 'active' => 'boolean', - ] -); diff --git a/app/tests/factories/AccountMeta.php b/app/tests/factories/AccountMeta.php deleted file mode 100644 index a282aa9748..0000000000 --- a/app/tests/factories/AccountMeta.php +++ /dev/null @@ -1,9 +0,0 @@ - 'factory|Account', - 'name' => 'word', - 'data' => 'text' - ] -); diff --git a/app/tests/factories/AccountType.php b/app/tests/factories/AccountType.php deleted file mode 100644 index e893ea89af..0000000000 --- a/app/tests/factories/AccountType.php +++ /dev/null @@ -1,8 +0,0 @@ - 'word', - 'editable' => 'boolean' - ] -); diff --git a/app/tests/factories/Budget.php b/app/tests/factories/Budget.php deleted file mode 100644 index 1975cf53b0..0000000000 --- a/app/tests/factories/Budget.php +++ /dev/null @@ -1,8 +0,0 @@ - 'word', - 'user_id' => 'factory|User' - ] -); diff --git a/app/tests/factories/PiggyBank.php b/app/tests/factories/PiggyBank.php deleted file mode 100644 index aaab88cd71..0000000000 --- a/app/tests/factories/PiggyBank.php +++ /dev/null @@ -1,38 +0,0 @@ - 'factory|Account', - 'name' => 'word', - 'targetamount' => function () { - return rand(1, 400); - }, - 'startdate' => 'date|Y-m-d', - 'targetdate' => 'date|Y-m-d', - 'repeats' => 'boolean', - 'rep_length' => function () { - $set = ['day', 'week', 'quarter', 'month', 'year']; - - return $set[rand(0, count($set) - 1)]; - }, - 'rep_every' => function () { - return rand(0, 3); - }, - 'rep_times' => function () { - return rand(0, 3); - }, - 'reminder' => function () { - $set = ['day', 'week', 'quarter', 'month', 'year']; - - return $set[rand(0, count($set) - 1)]; - }, - 'reminder_skip' => function () { - return rand(0, 3); - }, - 'remind_me' => 'boolean', - 'order' => function () { - return rand(0, 10); - }, - - ] -); diff --git a/app/tests/factories/PiggyBankRepetition.php b/app/tests/factories/PiggyBankRepetition.php deleted file mode 100644 index a266af2283..0000000000 --- a/app/tests/factories/PiggyBankRepetition.php +++ /dev/null @@ -1,13 +0,0 @@ - 'factory|PiggyBank', - 'startdate' => 'date|Y-m-d', - 'targetdate' => 'date|Y-m-d', - 'currentamount' => function () { - return rand(0, 100); - }, - - ] -); diff --git a/app/tests/factories/Preference.php b/app/tests/factories/Preference.php deleted file mode 100644 index 89a26f5812..0000000000 --- a/app/tests/factories/Preference.php +++ /dev/null @@ -1,9 +0,0 @@ - 'factory|User', - 'name' => 'word', - 'data' => 'sentence', - ] -); diff --git a/app/tests/factories/Reminder.php b/app/tests/factories/Reminder.php deleted file mode 100644 index 62f2a3d513..0000000000 --- a/app/tests/factories/Reminder.php +++ /dev/null @@ -1,13 +0,0 @@ - 'factory|User', - 'startdate' => 'date|Y-m-d', - 'enddate' => 'date|Y-m-d', - 'active' => 'boolean', - 'notnow' => 'boolean', - 'remindersable_id' => 0, - 'remindersable_type' => '', - ] -); diff --git a/app/tests/factories/Transaction.php b/app/tests/factories/Transaction.php deleted file mode 100644 index 39f50f7ca5..0000000000 --- a/app/tests/factories/Transaction.php +++ /dev/null @@ -1,12 +0,0 @@ - 'factory|Account', - 'transaction_journal_id' => 'factory|TransactionJournal', - 'description' => 'sentence', - 'amount' => function () { - return round(rand(100, 10000) / 100, 2); - } - ] -); diff --git a/app/tests/factories/TransactionCurrency.php b/app/tests/factories/TransactionCurrency.php deleted file mode 100644 index cfb3b685b0..0000000000 --- a/app/tests/factories/TransactionCurrency.php +++ /dev/null @@ -1,30 +0,0 @@ - function () { - $code = ''; - for ($i = 0; $i < 3; $i++) { - $code .= chr(rand(65, 90)); - } - - return $code; - }, - 'name' => function () { - $code = ''; - for ($i = 0; $i < 8; $i++) { - $code .= chr(rand(65, 90)); - } - - return $code; - }, - 'symbol' => function () { - $code = ''; - for ($i = 0; $i < 2; $i++) { - $code .= chr(rand(65, 90)); - } - - return $code; - } - ] -); diff --git a/app/tests/factories/TransactionGroup.php b/app/tests/factories/TransactionGroup.php deleted file mode 100644 index 74e917a8ae..0000000000 --- a/app/tests/factories/TransactionGroup.php +++ /dev/null @@ -1,8 +0,0 @@ - 'factory|User', - 'relation' => 'balance', - ] -); diff --git a/app/tests/factories/TransactionJournal.php b/app/tests/factories/TransactionJournal.php deleted file mode 100644 index 58fd89d200..0000000000 --- a/app/tests/factories/TransactionJournal.php +++ /dev/null @@ -1,12 +0,0 @@ - 'factory|TransactionType', - 'transaction_currency_id' => 'factory|TransactionCurrency', - 'description' => 'text', - 'date' => 'date|Y-m-d', - 'completed' => 'boolean', - 'user_id' => 'factory|User' - ] -); diff --git a/app/tests/factories/TransactionType.php b/app/tests/factories/TransactionType.php deleted file mode 100644 index 0876277d2c..0000000000 --- a/app/tests/factories/TransactionType.php +++ /dev/null @@ -1,7 +0,0 @@ - 'word', - ] -); diff --git a/app/tests/factories/User.php b/app/tests/factories/User.php deleted file mode 100644 index 92efe04843..0000000000 --- a/app/tests/factories/User.php +++ /dev/null @@ -1,7 +0,0 @@ - 'email', - 'password' => 'empty' - ] -); diff --git a/app/views/budgets/edit.blade.php b/app/views/budgets/edit.blade.php deleted file mode 100644 index 94061cd926..0000000000 --- a/app/views/budgets/edit.blade.php +++ /dev/null @@ -1,42 +0,0 @@ -@extends('layouts.default') -@section('content') -{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $budget) }} -
-
-

Use budgets to organize and limit your expenses.

-
-
- -{{Form::model($budget, ['class' => 'form-horizontal','id' => 'update','url' => route('budgets.update',$budget->id)])}} -
-
-
-
- Mandatory fields -
-
- {{Form::ffText('name')}} -
-
-

- -

-
-
- -
-
- Options -
-
- {{Form::ffOptionsList('update','budget')}} -
-
-
-
-{{Form::close()}} - - -@stop diff --git a/app/views/currency/index.blade.php b/app/views/currency/index.blade.php deleted file mode 100644 index be3662c948..0000000000 --- a/app/views/currency/index.blade.php +++ /dev/null @@ -1,53 +0,0 @@ -@extends('layouts.default') -@section('content') - {{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) }} - -
-
-
-
- Currencies -
-
-

- Firefly III supports various currencies which you can set and enable here. -

-
    - @if(count($currencies) > 0) - @foreach($currencies as $currency) -
  • - - - {{{$currency->name}}} ({{{$currency->code}}}) ({{{$currency->symbol}}}) - @if($currency->id == $defaultCurrency->id) - default - @else - make default - - @endif -
  • - @endforeach - @endif -
  • Add another currency
  • -
-
-
-
-
-
-
- Supported -
-
-
    -
  • Set the default currency display;
  • -
  • Set the default currency for new transactions;
  • -
  • Add, modify and remove supported currencies.
  • -
  • Display the actual currency of a transaction
  • -
  • Update a transaction's currency.
  • -
-
-
-
-
-@stop diff --git a/app/views/emails/user/register-html.blade.php b/app/views/emails/user/register-html.blade.php deleted file mode 100644 index e81ca6d95e..0000000000 --- a/app/views/emails/user/register-html.blade.php +++ /dev/null @@ -1,19 +0,0 @@ - - - - - -

- Hi! -

-

- Here's the password you need to login at Firefly: {{$password}} -

-

- Cya! -

- - - diff --git a/app/views/emails/user/register-text.blade.php b/app/views/emails/user/register-text.blade.php deleted file mode 100644 index 0993031a88..0000000000 --- a/app/views/emails/user/register-text.blade.php +++ /dev/null @@ -1,5 +0,0 @@ -Hi! - -Here's the password you need to login at Firefly: {{$password}} - -Cya! diff --git a/app/views/emails/user/verify-html.blade.php b/app/views/emails/user/verify-html.blade.php deleted file mode 100644 index 90b477e351..0000000000 --- a/app/views/emails/user/verify-html.blade.php +++ /dev/null @@ -1,19 +0,0 @@ - - - - - -

- Hi! -

-

- To verify your registration, please verify your e-mail address. -

-

- Cya! -

- - - diff --git a/app/views/emails/user/verify-text.blade.php b/app/views/emails/user/verify-text.blade.php deleted file mode 100644 index 27f1d553a0..0000000000 --- a/app/views/emails/user/verify-text.blade.php +++ /dev/null @@ -1,7 +0,0 @@ -Hi! - -To verify your registration, please verify your e-mail address: - -{{route('reset',$reset)}} - -Cya! diff --git a/app/views/help/show.blade.php b/app/views/help/show.blade.php deleted file mode 100644 index e864585fd5..0000000000 --- a/app/views/help/show.blade.php +++ /dev/null @@ -1,14 +0,0 @@ - diff --git a/app/views/list/journals-small.blade.php b/app/views/list/journals-small.blade.php deleted file mode 100644 index b1ba57dacf..0000000000 --- a/app/views/list/journals-small.blade.php +++ /dev/null @@ -1,44 +0,0 @@ - - - @foreach($journals as $journal) - - - - - - - - @endforeach - @if(isset($displaySum) && $displaySum === true) - - - - - - @endif -
- {{{$journal->description}}} - - transactions[1]->amount);?> - @if($journal->transactiontype->type == 'Withdrawal') - {{Amount::formatTransaction($journal->transactions[1],false)}} - @endif - @if($journal->transactiontype->type == 'Deposit') - {{Amount::formatTransaction($journal->transactions[1],false)}} - @endif - @if($journal->transactiontype->type == 'Transfer') - {{Amount::formatTransaction($journal->transactions[1],false)}} - @endif - - {{$journal->date->format('j F Y')}} - - @foreach($journal->transactions as $t) - @if(floatval($t->amount < 0)) - @if($t->account->accounttype->description == 'Cash account') - (cash) - @else - {{{$t->account->name}}} - @endif - @endif - @endforeach -
Sum{{Amount::format($tableSum)}}
diff --git a/app/views/piggy_banks/create.blade.php b/app/views/piggy_banks/create.blade.php deleted file mode 100644 index dea0c3573f..0000000000 --- a/app/views/piggy_banks/create.blade.php +++ /dev/null @@ -1,94 +0,0 @@ -@extends('layouts.default') -@section('content') -{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) }} -{{Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('piggy_banks.store')])}} - -
-
-
-
- Mandatory fields -
-
- {{Form::ffText('name')}} - {{Form::ffSelect('account_id',$accounts,null,['label' => 'Save on account'])}} - {{Form::ffAmount('targetamount')}} - -
-
-

- -

-
-
- -
-
- Optional fields -
-
- {{Form::ffDate('targetdate')}} - {{Form::ffCheckbox('remind_me','1',false,['label' => 'Remind me'])}} - {{Form::ffSelect('reminder',$periods,'month',['label' => 'Remind every'])}} -
-
- - -
-
- Options -
-
- {{Form::ffOptionsList('create','piggy bank')}} -
-
- -
-
-{{-- - -

Mandatory fields

- -

Optional fields

- - -
- {{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}} -
- - - - @if($errors->has('reminder')) -

{{$errors->first('reminder')}}

- @else - Enter a number and a period and Firefly will remind you to add money - to this piggy bank every now and then. - @endif -
-
- - - - - -
-
- -
-
- -
-
-
-
---}} - -{{Form::close()}} -@stop diff --git a/app/views/piggy_banks/edit.blade.php b/app/views/piggy_banks/edit.blade.php deleted file mode 100644 index 6532a61a27..0000000000 --- a/app/views/piggy_banks/edit.blade.php +++ /dev/null @@ -1,94 +0,0 @@ -@extends('layouts.default') -@section('content') -{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $piggyBank) }} -{{Form::model($piggyBank, ['class' => 'form-horizontal','id' => 'update','url' => route('piggy_banks.update',$piggyBank->id)])}} - -
-
-
-
- Mandatory fields -
-
- {{Form::ffText('name')}} - {{Form::ffSelect('account_id',$accounts,null,['label' => 'Save on account'])}} - {{Form::ffAmount('targetamount')}} - -
-
-

- -

-
-
- -
-
- Optional fields -
-
- {{Form::ffDate('targetdate')}} - {{Form::ffCheckbox('remind_me','1',$preFilled['remind_me'],['label' => 'Remind me'])}} - {{Form::ffSelect('reminder',$periods,$preFilled['reminder'],['label' => 'Remind every'])}} -
-
- - -
-
- Options -
-
- {{Form::ffOptionsList('update','piggy bank')}} -
-
- -
-
-{{-- - -

Mandatory fields

- -

Optional fields

- - -
- {{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}} -
- - - - @if($errors->has('reminder')) -

{{$errors->first('reminder')}}

- @else - Enter a number and a period and Firefly will remind you to add money - to this piggy bank every now and then. - @endif -
-
- - - - - -
-
- -
-
- -
-
-
-
---}} - -{{Form::close()}} -@stop diff --git a/app/views/reminders/show.blade.php b/app/views/reminders/show.blade.php deleted file mode 100644 index d0fcd29f7a..0000000000 --- a/app/views/reminders/show.blade.php +++ /dev/null @@ -1,32 +0,0 @@ -@extends('layouts.default') -@section('content') -{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $reminder) }} -
-
-
-
- A reminder about - @if(get_class($reminder->remindersable) == 'PiggyBank') - your piggy bank labelled "{{{$reminder->remindersable->name}}}" - @endif -
-
-

- @if(get_class($reminder->remindersable) == 'Piggybank') - Somewhere between {{$reminder->startdate->format('j F Y')}} and {{$reminder->enddate->format('j F Y')}} you - should deposit {{Amount::format($amount)}} in piggy bank {{{$reminder->remindersable->name}}} - in order to make your goal of saving {{Amount::format($reminder->remindersable->targetamount)}} on {{$reminder->remindersable->targetdate->format('j F Y')}} - - @endif -

-

- I want to do this - I already did this - Not this time - -

-
-
-
-
-@stop diff --git a/app/views/repeatedExpense/create.blade.php b/app/views/repeatedExpense/create.blade.php deleted file mode 100644 index 374579360d..0000000000 --- a/app/views/repeatedExpense/create.blade.php +++ /dev/null @@ -1,97 +0,0 @@ -@extends('layouts.default') -@section('content') -{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) }} -{{Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('repeated.store')])}} - -
-
-
-
- Mandatory fields -
-
- {{Form::ffText('name')}} - {{Form::ffSelect('account_id',$accounts,null,['label' => 'Save on account'])}} - {{Form::ffAmount('targetamount')}} - {{Form::ffDate('targetdate',null,['label' => 'First target date'])}} - {{Form::ffSelect('rep_length',$periods,'month',['label' => 'Repeats every'])}} - {{Form::ffInteger('rep_every',0,['label' => 'Skip period'])}} - {{Form::ffInteger('rep_times',0,['label' => 'Repeat times'])}} -
-
-

- -

-
-
- -
-
- Optional fields -
-
- - {{Form::ffCheckbox('remind_me','1',false,['label' => 'Remind me'])}} - {{Form::ffSelect('reminder',$periods,'month',['label' => 'Remind every'])}} -
-
- - -
-
- Options -
-
- {{Form::ffOptionsList('create','repeated expense')}} -
-
- -
-
-{{-- - -

Mandatory fields

- -

Optional fields

- - -
- {{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}} -
- - - - @if($errors->has('reminder')) -

{{$errors->first('reminder')}}

- @else - Enter a number and a period and Firefly will remind you to add money - to this piggy bank every now and then. - @endif -
-
- - - - - -
-
- -
-
- -
-
-
-
---}} - -{{Form::close()}} -@stop diff --git a/app/views/repeatedExpense/edit.blade.php b/app/views/repeatedExpense/edit.blade.php deleted file mode 100644 index 8464cf0866..0000000000 --- a/app/views/repeatedExpense/edit.blade.php +++ /dev/null @@ -1,97 +0,0 @@ -@extends('layouts.default') -@section('content') -{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $repeatedExpense) }} -{{Form::model($repeatedExpense, ['class' => 'form-horizontal','id' => 'update','url' => route('repeated.update',$repeatedExpense->id)])}} - -
-
-
-
- Mandatory fields -
-
- {{Form::ffText('name')}} - {{Form::ffSelect('account_id',$accounts,null,['label' => 'Save on account'])}} - {{Form::ffAmount('targetamount')}} - {{Form::ffDate('targetdate',null,['label' => 'First target date'])}} - {{Form::ffSelect('rep_length',$periods,null,['label' => 'Repeats every'])}} - {{Form::ffInteger('rep_every',null,['label' => 'Skip period'])}} - {{Form::ffInteger('rep_times',null,['label' => 'Repeat times'])}} - -
-
-

- -

-
-
- -
-
- Optional fields -
-
- {{Form::ffCheckbox('remind_me','1',$preFilled['remind_me'],['label' => 'Remind me'])}} - {{Form::ffSelect('reminder',$periods,$preFilled['reminder'],['label' => 'Remind every'])}} -
-
- - -
-
- Options -
-
- {{Form::ffOptionsList('update','piggy bank')}} -
-
- -
-
-{{-- - -

Mandatory fields

- -

Optional fields

- - -
- {{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}} -
- - - - @if($errors->has('reminder')) -

{{$errors->first('reminder')}}

- @else - Enter a number and a period and Firefly will remind you to add money - to this piggy bank every now and then. - @endif -
-
- - - - - -
-
- -
-
- -
-
-
-
---}} - -{{Form::close()}} -@stop diff --git a/app/views/user/login.blade.php b/app/views/user/login.blade.php deleted file mode 100644 index a2efbcfa9e..0000000000 --- a/app/views/user/login.blade.php +++ /dev/null @@ -1,39 +0,0 @@ -@extends('layouts.guest') -@section('content') -
-
- -
-
-@stop diff --git a/app/views/user/register.blade.php b/app/views/user/register.blade.php deleted file mode 100644 index a7a11f07fc..0000000000 --- a/app/views/user/register.blade.php +++ /dev/null @@ -1,33 +0,0 @@ -@extends('layouts.guest') -@section('content') -
-
- -
-
-@stop diff --git a/app/views/user/registered.blade.php b/app/views/user/registered.blade.php deleted file mode 100644 index ce4e3e056e..0000000000 --- a/app/views/user/registered.blade.php +++ /dev/null @@ -1,19 +0,0 @@ -@extends('layouts.guest') -@section('content') -
-
-

Firefly
- Password sent! -

-
-
- -
-
-

- You're about to get an e-mail. Use the contents to log in. -

-
-
- -@stop diff --git a/app/views/user/remindMe-html.blade.php b/app/views/user/remindMe-html.blade.php deleted file mode 100644 index 16f09cc04d..0000000000 --- a/app/views/user/remindMe-html.blade.php +++ /dev/null @@ -1,19 +0,0 @@ - - - - - -

- Hi! -

-

- To get a new password, please verify your e-mail address. -

-

- Cya! -

- - - diff --git a/app/views/user/remindMe-text.blade.php b/app/views/user/remindMe-text.blade.php deleted file mode 100644 index 8d1980a3e4..0000000000 --- a/app/views/user/remindMe-text.blade.php +++ /dev/null @@ -1,5 +0,0 @@ -Hi! - -To get a new password, please verify your e-mail address: {{route('reset',$reset)}} - -Cya! diff --git a/app/views/user/remindMe.blade.php b/app/views/user/remindMe.blade.php deleted file mode 100644 index 18b48954ac..0000000000 --- a/app/views/user/remindMe.blade.php +++ /dev/null @@ -1,27 +0,0 @@ -@extends('layouts.guest') -@section('content') -
-
- -
-
-@stop diff --git a/app/views/user/verification-pending.blade.php b/app/views/user/verification-pending.blade.php deleted file mode 100644 index a10b2d53da..0000000000 --- a/app/views/user/verification-pending.blade.php +++ /dev/null @@ -1,19 +0,0 @@ -@extends('layouts.guest') -@section('content') -
-
-

Firefly
- Verification pending -

-
-
- -
-
-

- You're about to get an e-mail. Please follow its instructions. -

-
-
- -@stop diff --git a/artisan b/artisan old mode 100755 new mode 100644 index 5c408ad80d..eb5e2bb62d --- a/artisan +++ b/artisan @@ -15,35 +15,7 @@ require __DIR__.'/bootstrap/autoload.php'; -/* -|-------------------------------------------------------------------------- -| Turn On The Lights -|-------------------------------------------------------------------------- -| -| We need to illuminate PHP development, so let's turn on the lights. -| This bootstraps the framework and gets it ready for and then it -| will load up this application so that we can run it and send -| the responses back to the browser and delight these users. -| -*/ - -$app = require_once __DIR__.'/bootstrap/start.php'; - -/* -|-------------------------------------------------------------------------- -| Load The Artisan Console Application -|-------------------------------------------------------------------------- -| -| We'll need to run the script to load and return the Artisan console -| application. We keep this in its own script so that we will load -| the console application independent of running commands which -| will allow us to fire commands from Routes when we want to. -| -*/ - -$app->setRequestForConsoleEnvironment(); - -$artisan = Illuminate\Console\Application::start($app); +$app = require_once __DIR__.'/bootstrap/app.php'; /* |-------------------------------------------------------------------------- @@ -56,7 +28,12 @@ $artisan = Illuminate\Console\Application::start($app); | */ -$status = $artisan->run(); +$kernel = $app->make('Illuminate\Contracts\Console\Kernel'); + +$status = $kernel->handle( + $input = new Symfony\Component\Console\Input\ArgvInput, + new Symfony\Component\Console\Output\ConsoleOutput +); /* |-------------------------------------------------------------------------- @@ -69,6 +46,6 @@ $status = $artisan->run(); | */ -$app->shutdown(); +$kernel->terminate($input, $status); exit($status); diff --git a/bootstrap/app.php b/bootstrap/app.php new file mode 100644 index 0000000000..e3697dc4ad --- /dev/null +++ b/bootstrap/app.php @@ -0,0 +1,57 @@ +singleton( + 'Illuminate\Contracts\Http\Kernel', + 'FireflyIII\Http\Kernel' +); + +$app->singleton( + 'Illuminate\Contracts\Console\Kernel', + 'FireflyIII\Console\Kernel' +); + +$app->singleton( + 'Illuminate\Contracts\Debug\ExceptionHandler', + 'FireflyIII\Exceptions\Handler' +); + +/* +|-------------------------------------------------------------------------- +| Return The Application +|-------------------------------------------------------------------------- +| +| This script returns the application instance. The instance is given to +| the calling script so we can separate the building of the instances +| from the actual running of the application and sending responses. +| +*/ + +return $app; diff --git a/bootstrap/autoload.php b/bootstrap/autoload.php index ce1373c696..f2a9d5675d 100644 --- 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,48 +27,9 @@ require __DIR__ . '/../vendor/autoload.php'; | */ -if (file_exists($compiled = __DIR__ . '/compiled.php')) { - /** @noinspection PhpIncludeInspection */ - require $compiled; -} - -/* -|-------------------------------------------------------------------------- -| Setup Patchwork UTF-8 Handling -|-------------------------------------------------------------------------- -| -| The Patchwork library provides solid handling of UTF-8 strings as well -| as provides replacements for all mb_* and iconv type functions that -| are not available by default in PHP. We'll setup this stuff here. -| -*/ - -Patchwork\Utf8\Bootup::initMbstring(); - -/* -|-------------------------------------------------------------------------- -| Register The Laravel Auto Loader -|-------------------------------------------------------------------------- -| -| We register an auto-loader "behind" the Composer loader that can load -| model classes on the fly, even if the autoload files have not been -| regenerated for the application. We'll add it to the stack here. -| -*/ - -Illuminate\Support\ClassLoader::register(); - -/* -|-------------------------------------------------------------------------- -| Register The Workbench Loaders -|-------------------------------------------------------------------------- -| -| The Laravel workbench provides a convenient place to develop packages -| when working locally. However we will need to load in the Composer -| auto-load files for the packages so that these can be used here. -| -*/ - -if (is_dir($workbench = __DIR__ . '/../workbench')) { - Illuminate\Workbench\Starter::start($workbench); +$compiledPath = __DIR__.'/../storage/framework/compiled.php'; + +if (file_exists($compiledPath)) +{ + require $compiledPath; } diff --git a/bootstrap/functions.php b/bootstrap/functions.php deleted file mode 100644 index b3d9bbc7f3..0000000000 --- a/bootstrap/functions.php +++ /dev/null @@ -1 +0,0 @@ - __DIR__ . '/../app', - - /* - |-------------------------------------------------------------------------- - | Public Path - |-------------------------------------------------------------------------- - | - | The public path contains the assets for your web application, such as - | your JavaScript and CSS files, and also contains the primary entry - | point for web requests into these applications from the outside. - | - */ - - 'public' => __DIR__ . '/../public', - - /* - |-------------------------------------------------------------------------- - | Base Path - |-------------------------------------------------------------------------- - | - | The base path is the root of the Laravel installation. Most likely you - | will not need to change this value. But, if for some wild reason it - | is necessary you will do so here, just proceed with some caution. - | - */ - - 'base' => __DIR__ . '/..', - - /* - |-------------------------------------------------------------------------- - | Storage Path - |-------------------------------------------------------------------------- - | - | The storage path is used by Laravel to store cached Blade views, logs - | and other pieces of information. You may modify the path here when - | you want to change the location of this directory for your apps. - | - */ - - 'storage' => __DIR__ . '/../app/storage', - -]; diff --git a/bootstrap/start.php b/bootstrap/start.php deleted file mode 100644 index 30dc7625b0..0000000000 --- a/bootstrap/start.php +++ /dev/null @@ -1,101 +0,0 @@ -detectEnvironment( - ['local' => ['SMJD*'], 'homestead' => ['homestead']] -); - - -/* -|-------------------------------------------------------------------------- -| Bind Paths -|-------------------------------------------------------------------------- -| -| Here we are binding the paths configured in paths.php to the app. You -| should not be changing these here. If you need to change these you -| may do so within the paths.php file and they will be bound here. -| -*/ - -$app->bindInstallPaths(require __DIR__ . '/paths.php'); - -/* -|-------------------------------------------------------------------------- -| Load The Application -|-------------------------------------------------------------------------- -| -| Here we will load this Illuminate application. We will keep this in a -| separate location so we can isolate the creation of an application -| from the actual running of the application with a given request. -| -*/ - -$framework = $app['path.base'] . '/vendor/laravel/framework/src'; - -/** @noinspection PhpIncludeInspection */ -require $framework . '/Illuminate/Foundation/start.php'; - - -/* -|-------------------------------------------------------------------------- -| Return The Application -|-------------------------------------------------------------------------- -| -| This script returns the application instance. The instance is given to -| the calling script so we can separate the building of the instances -| from the actual running of the application and sending responses. -| -*/ - -// do something with events: - -Event::subscribe('FireflyIII\Event\Account'); -Event::subscribe('FireflyIII\Event\Budget'); -Event::subscribe('FireflyIII\Event\Event'); -Event::subscribe('FireflyIII\Event\Piggybank'); -Event::subscribe('FireflyIII\Event\Transaction'); -Event::subscribe('FireflyIII\Event\TransactionJournal'); - - -// event that creates a relationship between transaction journals and recurring events when created. -// event that updates the relationship between transaction journals and recurring events when edited. -// event that creates a LimitRepetition when a Limit is created. -// event for when a transfer gets created and set an associated piggy bank; save as Piggy bank event. -// when this transfer gets edited, retro-actively edit the event and THUS also the piggy bank. -// event for when a transfer gets deleted; also delete related piggy bank event. -// event to create the first repetition (for non-repeating piggy banks) when the piggy bank is created. -// event for when the non-repeating piggy bank is updated because the single repetition must also be changed. -// (also make piggy bank events "invalid" when they start falling outside of the date-scope of the piggy bank, -// although this not changes the amount in the piggy bank). -// check if recurring transactions are being updated when journals are updated (aka no longer fitting, thus removed). -// think about reminders. -// an event that triggers and creates a limit + limit repetition when a budget is created, or something? -// has many through needs to be added wherever relevant. Account > journals, etc. -// check all models for "external" methods once more. -// Auth::user() should be used very sparsely. -// direct calls to models are BAD -// cleanup everything related to reminders because it still feels a bit sloppy. -// use a Database\Reminder thing instead of self-made ORM. -// create static calls instead of all the App::make() things. -// see if the various has-many-throughs actually get used. -// set very tight rules on all models -// create custom uniquely rules. -// add "Create new X" button to any list there is: categories, accounts, piggies, etc. -// Install PHP5 and code thing and create very small methods. -return $app; diff --git a/build/logs/.gitignore b/build/logs/.gitignore deleted file mode 100644 index b81c7954b7..0000000000 --- a/build/logs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.xml \ No newline at end of file diff --git a/codeception.yml b/codeception.yml index 1c64b071f9..3284792656 100644 --- a/codeception.yml +++ b/codeception.yml @@ -9,14 +9,10 @@ settings: colors: true memory_limit: 1024M modules: - config: + config: coverage: - enabled: true - remote: false - whitelist: - include: - - app/controllers/* - - app/models/* - - app/lib/FireflyIII/* - exclude: - - app/controllers/BaseController.php + enabled: true + remote: false + whitelist: + include: + - app/* \ No newline at end of file diff --git a/composer.json b/composer.json index f06c862101..59a4fbdd9c 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,8 @@ { "name": "grumpydictator/firefly-iii", "description": "A web-application to manage your finances. This version will replace grumpydictator/firefly when it's finished.", - "license": "MIT", "keywords": ["finance", "finances", "manager", "euro", "laravel", "money", "financials", "budgets", "transactions", "transfers", "management"], + "license": "MIT", "homepage": "https://github.com/JC5/firefly-iii", "type": "project", "authors": [ @@ -20,50 +20,49 @@ }, "require": { - "laravel/framework": "4.2.*", - "davejamesmiller/laravel-breadcrumbs": "2.*", - "grumpydictator/gchart": "1.*", - "michelf/php-markdown": "1.*", - "watson/validating": "0.10.*", - "doctrine/dbal": "~2.3" + "laravel/framework": "5.0.*", + "davejamesmiller/laravel-breadcrumbs": "~3.0", + "grumpydictator/gchart": "dev-master", + "watson/validating": "dev-master", + "doctrine/dbal": "~2.5", + "illuminate/html": "~5.0", + "barryvdh/laravel-ide-helper": "~2.0", + "league/commonmark": "0.7.*" }, "require-dev": { "barryvdh/laravel-debugbar": "@stable", - "barryvdh/laravel-ide-helper": "@stable", - "satooshi/php-coveralls": "*", - "mockery/mockery": "@stable", + "phpunit/phpunit": "~4.0", + "phpspec/phpspec": "~2.1", + "codeception/codeception": "@stable", + "codeception/c3": "@stable", "league/factory-muffin": "~2.1", - "codeception/codeception": "*", - "codeception/c3": "2.*", - "sebastian/phpcpd": "*", - "sebastian/phpdcd": "*", "codeception/phpbuiltinserver": "*", "codeception/specify": "*", "codeception/verify": "*", "fzaninotto/faker": "1.*", "codeclimate/php-test-reporter": "dev-master" - }, "autoload": { "classmap": [ - "app/commands", - "app/controllers", - "app/models", - "app/database/migrations", - "app/database/seeds", - "app/tests/TestCase.php" + "database" ], - "psr-0": { - "Firefly": "app/lib/" + "psr-4": { + "FireflyIII\\": "app/" } }, + "autoload-dev": { + "classmap": [ + "tests/TestCase.php" + ] + }, "scripts": { "post-install-cmd": [ "php artisan clear-compiled", "php artisan optimize", "Codeception\\c3\\Installer::copyC3ToRoot" + ], "post-update-cmd": [ "php artisan clear-compiled", @@ -71,6 +70,7 @@ "Codeception\\c3\\Installer::copyC3ToRoot" ], "post-create-project-cmd": [ + "php -r \"copy('.env.example', '.env');\"", "php artisan key:generate" ] }, diff --git a/composer.lock b/composer.lock index 821c430ce2..95b03522ad 100644 --- a/composer.lock +++ b/composer.lock @@ -4,117 +4,216 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "937df9084a824cbdc9e2612df4e3e8cd", + "hash": "d78d46376975c1bfab9823b66a30ed5f", "packages": [ { - "name": "classpreloader/classpreloader", - "version": "1.0.2", + "name": "barryvdh/laravel-ide-helper", + "version": "v2.0.1", "source": { "type": "git", - "url": "https://github.com/ClassPreloader/ClassPreloader.git", - "reference": "2c9f3bcbab329570c57339895bd11b5dd3b00877" + "url": "https://github.com/barryvdh/laravel-ide-helper.git", + "reference": "81b7febfc64168ea1af57261aa4dfc9acefd5429" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/2c9f3bcbab329570c57339895bd11b5dd3b00877", - "reference": "2c9f3bcbab329570c57339895bd11b5dd3b00877", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/81b7febfc64168ea1af57261aa4dfc9acefd5429", + "reference": "81b7febfc64168ea1af57261aa4dfc9acefd5429", "shasum": "" }, "require": { - "nikic/php-parser": "~0.9", + "illuminate/console": "5.0.x", + "illuminate/filesystem": "5.0.x", + "illuminate/support": "5.0.x", + "php": ">=5.4.0", + "phpdocumentor/reflection-docblock": "2.0.x", + "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.0-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-02-23 15:55:54" + }, + { + "name": "classpreloader/classpreloader", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/ClassPreloader/ClassPreloader.git", + "reference": "f0bfbf71fb3335c9473f695d4d966ba2fb879a9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/f0bfbf71fb3335c9473f695d4d966ba2fb879a9f", + "reference": "f0bfbf71fb3335c9473f695d4d966ba2fb879a9f", + "shasum": "" + }, + "require": { + "nikic/php-parser": "~1.0", "php": ">=5.3.3", "symfony/console": "~2.1", "symfony/filesystem": "~2.1", "symfony/finder": "~2.1" }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, "bin": [ "classpreloader.php" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.2-dev" } }, "autoload": { - "psr-0": { - "ClassPreloader": "src/" + "psr-4": { + "ClassPreloader\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], + "authors": [ + { + "name": "Graham Campbell", + "email": "graham@mineuk.com" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com" + } + ], "description": "Helps class loading performance by generating a single PHP file containing all of the autoloaded files for a specific use case", "keywords": [ "autoload", "class", "preload" ], - "time": "2014-03-12 00:05:31" + "time": "2015-01-26 22:06:19" }, { - "name": "d11wtq/boris", - "version": "v1.0.8", + "name": "danielstjules/stringy", + "version": "1.9.0", "source": { "type": "git", - "url": "https://github.com/d11wtq/boris.git", - "reference": "125dd4e5752639af7678a22ea597115646d89c6e" + "url": "https://github.com/danielstjules/Stringy.git", + "reference": "3cf18e9e424a6dedc38b7eb7ef580edb0929461b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/d11wtq/boris/zipball/125dd4e5752639af7678a22ea597115646d89c6e", - "reference": "125dd4e5752639af7678a22ea597115646d89c6e", + "url": "https://api.github.com/repos/danielstjules/Stringy/zipball/3cf18e9e424a6dedc38b7eb7ef580edb0929461b", + "reference": "3cf18e9e424a6dedc38b7eb7ef580edb0929461b", "shasum": "" }, "require": { - "php": ">=5.3.0" - }, - "suggest": { - "ext-pcntl": "*", - "ext-posix": "*", - "ext-readline": "*" - }, - "bin": [ - "bin/boris" - ], - "type": "library", - "autoload": { - "psr-0": { - "Boris": "lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "time": "2014-01-17 12:21:18" - }, - { - "name": "davejamesmiller/laravel-breadcrumbs", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/davejamesmiller/laravel-breadcrumbs.git", - "reference": "cfcdc58ceaa8bbafa403828b8d1279d65f62799f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/davejamesmiller/laravel-breadcrumbs/zipball/cfcdc58ceaa8bbafa403828b8d1279d65f62799f", - "reference": "cfcdc58ceaa8bbafa403828b8d1279d65f62799f", - "shasum": "" - }, - "require": { - "illuminate/support": "4.*|5.*", - "illuminate/view": "4.*|5.*", + "ext-mbstring": "*", "php": ">=5.3.0" }, "require-dev": { - "mockery/mockery": "~0.9.0", - "phpunit/phpunit": "4.0.*", - "satooshi/php-coveralls": "~0.6.0" + "phpunit/phpunit": "~4.0" }, "type": "library", "autoload": { - "psr-0": { - "DaveJamesMiller\\Breadcrumbs": "src/" + "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-02-10 06:19:18" + }, + { + "name": "davejamesmiller/laravel-breadcrumbs", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/davejamesmiller/laravel-breadcrumbs.git", + "reference": "5a5d5d1b1f5780359604f7fde11bbf810ff3e9e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/davejamesmiller/laravel-breadcrumbs/zipball/5a5d5d1b1f5780359604f7fde11bbf810ff3e9e4", + "reference": "5a5d5d1b1f5780359604f7fde11bbf810ff3e9e4", + "shasum": "" + }, + "require": { + "illuminate/support": "5.*", + "illuminate/view": "5.*", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "orchestra/testbench": "3.0.*", + "phpunit/phpunit": "4.*", + "satooshi/php-coveralls": "0.6.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "DaveJamesMiller\\Breadcrumbs\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -133,7 +232,40 @@ "keywords": [ "laravel" ], - "time": "2014-10-26 22:36:05" + "time": "2015-02-08 21:44:39" + }, + { + "name": "dnoegel/php-xdg-base-dir", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "@stable" + }, + "type": "project", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "time": "2014-10-24 07:27:01" }, { "name": "doctrine/annotations", @@ -611,80 +743,21 @@ ], "time": "2014-09-09 13:34:57" }, - { - "name": "filp/whoops", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/filp/whoops.git", - "reference": "a85fab9a98f1f9b8ebcdbe71733f0d910e5b9adf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/a85fab9a98f1f9b8ebcdbe71733f0d910e5b9adf", - "reference": "a85fab9a98f1f9b8ebcdbe71733f0d910e5b9adf", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "mockery/mockery": "0.9.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "autoload": { - "psr-0": { - "Whoops": "src/" - }, - "classmap": [ - "src/deprecated" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Filipe Dobreira", - "homepage": "https://github.com/filp", - "role": "Developer" - } - ], - "description": "php error handling for cool kids", - "homepage": "https://github.com/filp/whoops", - "keywords": [ - "error", - "exception", - "handling", - "library", - "silex-provider", - "whoops", - "zf2" - ], - "time": "2014-10-26 09:05:09" - }, { "name": "grumpydictator/gchart", - "version": "1.0.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/JC5/gchart.git", - "reference": "f56d503e18d823393a39971bd861580e20833799" + "reference": "24d06101cfda7ff336ecb10f7f0cb0d6004cb83c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/JC5/gchart/zipball/f56d503e18d823393a39971bd861580e20833799", - "reference": "f56d503e18d823393a39971bd861580e20833799", + "url": "https://api.github.com/repos/JC5/gchart/zipball/24d06101cfda7ff336ecb10f7f0cb0d6004cb83c", + "reference": "24d06101cfda7ff336ecb10f7f0cb0d6004cb83c", "shasum": "" }, "require": { - "illuminate/support": "4.x", "php": ">=5.3.0" }, "type": "library", @@ -704,7 +777,53 @@ } ], "description": "GChart is a small package that allows you to easily generate data for the Google Charts API.", - "time": "2014-05-02 12:26:09" + "time": "2015-02-20 20:07:26" + }, + { + "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": "ircmaxell/password-compat", @@ -749,30 +868,76 @@ "time": "2014-11-20 16:49:30" }, { - "name": "jeremeamia/SuperClosure", - "version": "1.0.2", + "name": "jakub-onderka/php-console-color", + "version": "0.1", "source": { "type": "git", - "url": "https://github.com/jeremeamia/super_closure.git", - "reference": "4d89ca74994feab128ea46d5b3add92e6cb84554" + "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", + "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/4d89ca74994feab128ea46d5b3add92e6cb84554", - "reference": "4d89ca74994feab128ea46d5b3add92e6cb84554", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/e0b393dacf7703fc36a4efc3df1435485197e6c1", + "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1", "shasum": "" }, "require": { - "nikic/php-parser": "~0.9", - "php": ">=5.3.3" + "php": ">=5.3.2" }, "require-dev": { - "phpunit/phpunit": "~3.7" + "jakub-onderka/php-code-style": "1.0", + "jakub-onderka/php-parallel-lint": "0.*", + "jakub-onderka/php-var-dump-check": "0.*", + "phpunit/phpunit": "3.7.*", + "squizlabs/php_codesniffer": "1.*" }, "type": "library", "autoload": { "psr-0": { - "Jeremeamia\\SuperClosure": "src/" + "JakubOnderka\\PhpConsoleColor": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "jakub.onderka@gmail.com", + "homepage": "http://www.acci.cz" + } + ], + "time": "2014-04-08 15:00:19" + }, + { + "name": "jakub-onderka/php-console-highlighter", + "version": "v0.3.1", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", + "reference": "05bce997da20acf873e6bf396276798f3cd2c76a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/05bce997da20acf873e6bf396276798f3cd2c76a", + "reference": "05bce997da20acf873e6bf396276798f3cd2c76a", + "shasum": "" + }, + "require": { + "jakub-onderka/php-console-color": "~0.1", + "php": ">=5.3.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "~1.0", + "jakub-onderka/php-parallel-lint": "~0.5", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JakubOnderka\\PhpConsoleHighlighter": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -781,68 +946,121 @@ ], "authors": [ { - "name": "Jeremy Lindblom" + "name": "Jakub Onderka", + "email": "acci@acci.cz", + "homepage": "http://www.acci.cz/" } ], - "description": "Doing interesting things with closures like serialization.", + "time": "2014-07-14 20:59:35" + }, + { + "name": "jeremeamia/SuperClosure", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/jeremeamia/super_closure.git", + "reference": "ac4394c7e21777ac48543190fb0872b2fc7f17af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/ac4394c7e21777ac48543190fb0872b2fc7f17af", + "reference": "ac4394c7e21777ac48543190fb0872b2fc7f17af", + "shasum": "" + }, + "require": { + "nikic/php-parser": "~1.0", + "php": ">=5.4" + }, + "require-dev": { + "codeclimate/php-test-reporter": "~0.1.2", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "SuperClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia", + "role": "Developer" + } + ], + "description": "Serialize Closure objects, including their context and binding", "homepage": "https://github.com/jeremeamia/super_closure", "keywords": [ "closure", "function", + "lambda", "parser", "serializable", "serialize", "tokenizer" ], - "time": "2015-01-10 01:09:28" + "time": "2015-01-26 23:07:39" }, { "name": "laravel/framework", - "version": "v4.2.16", + "version": "v5.0.13", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "31fe6a5747bbe3c2df21dc4cc8f291e75ab6144f" + "reference": "c263240daa383e6b9bd979600dc61dcb2c436d53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/31fe6a5747bbe3c2df21dc4cc8f291e75ab6144f", - "reference": "31fe6a5747bbe3c2df21dc4cc8f291e75ab6144f", + "url": "https://api.github.com/repos/laravel/framework/zipball/c263240daa383e6b9bd979600dc61dcb2c436d53", + "reference": "c263240daa383e6b9bd979600dc61dcb2c436d53", "shasum": "" }, "require": { - "classpreloader/classpreloader": "~1.0.2", - "d11wtq/boris": "~1.0", - "filp/whoops": "1.1.*", + "classpreloader/classpreloader": "~1.2", + "danielstjules/stringy": "~1.8", + "doctrine/inflector": "~1.0", + "ext-mbstring": "*", + "ext-mcrypt": "*", + "ext-openssl": "*", "ircmaxell/password-compat": "~1.0", - "jeremeamia/superclosure": "~1.0.1", - "monolog/monolog": "~1.6", + "jeremeamia/superclosure": "~2.0", + "league/flysystem": "~1.0", + "monolog/monolog": "~1.11", + "mtdowling/cron-expression": "~1.0", "nesbot/carbon": "~1.0", - "patchwork/utf8": "1.1.*", "php": ">=5.4.0", - "phpseclib/phpseclib": "0.3.*", - "predis/predis": "0.8.*", - "stack/builder": "~1.0", + "psy/psysh": "0.4.*", "swiftmailer/swiftmailer": "~5.1", - "symfony/browser-kit": "2.5.*", - "symfony/console": "2.5.*", - "symfony/css-selector": "2.5.*", - "symfony/debug": "2.5.*", - "symfony/dom-crawler": "2.5.*", - "symfony/finder": "2.5.*", - "symfony/http-foundation": "2.5.*", - "symfony/http-kernel": "2.5.*", - "symfony/process": "2.5.*", - "symfony/routing": "2.5.*", - "symfony/security-core": "2.5.*", - "symfony/translation": "2.5.*" + "symfony/console": "2.6.*", + "symfony/debug": "2.6.*", + "symfony/finder": "2.6.*", + "symfony/http-foundation": "2.6.*", + "symfony/http-kernel": "2.6.*", + "symfony/process": "2.6.*", + "symfony/routing": "2.6.*", + "symfony/security-core": "2.6.*", + "symfony/translation": "2.6.*", + "symfony/var-dumper": "2.6.*", + "vlucas/phpdotenv": "~1.0" }, "replace": { "illuminate/auth": "self.version", + "illuminate/bus": "self.version", "illuminate/cache": "self.version", "illuminate/config": "self.version", "illuminate/console": "self.version", "illuminate/container": "self.version", + "illuminate/contracts": "self.version", "illuminate/cookie": "self.version", "illuminate/database": "self.version", "illuminate/encryption": "self.version", @@ -851,36 +1069,42 @@ "illuminate/filesystem": "self.version", "illuminate/foundation": "self.version", "illuminate/hashing": "self.version", - "illuminate/html": "self.version", "illuminate/http": "self.version", "illuminate/log": "self.version", "illuminate/mail": "self.version", "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", "illuminate/queue": "self.version", "illuminate/redis": "self.version", - "illuminate/remote": "self.version", "illuminate/routing": "self.version", "illuminate/session": "self.version", "illuminate/support": "self.version", "illuminate/translation": "self.version", "illuminate/validation": "self.version", - "illuminate/view": "self.version", - "illuminate/workbench": "self.version" + "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "~2.6", + "aws/aws-sdk-php": "~2.4", "iron-io/iron_mq": "~1.5", "mockery/mockery": "~0.9", - "pda/pheanstalk": "~2.1", - "phpunit/phpunit": "~4.0" + "pda/pheanstalk": "~3.0", + "phpunit/phpunit": "~4.0", + "predis/predis": "~1.0" }, "suggest": { - "doctrine/dbal": "Allow renaming columns and dropping SQLite columns." + "aws/aws-sdk-php": "Required to use the SQS queue driver (~2.4).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).", + "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers (~5.0).", + "iron-io/iron_mq": "Required to use the iron queue driver (~1.5).", + "league/flysystem-aws-s3-v2": "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)." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -888,10 +1112,11 @@ "src/Illuminate/Queue/IlluminateQueueClosure.php" ], "files": [ + "src/Illuminate/Foundation/helpers.php", "src/Illuminate/Support/helpers.php" ], - "psr-0": { - "Illuminate": "src/" + "psr-4": { + "Illuminate\\": "src/Illuminate/" } }, "notification-url": "https://packagist.org/downloads/", @@ -909,34 +1134,44 @@ "framework", "laravel" ], - "time": "2014-12-22 20:56:10" + "time": "2015-02-27 00:32:38" }, { - "name": "michelf/php-markdown", - "version": "1.4.1", + "name": "league/commonmark", + "version": "0.7.0", "source": { "type": "git", - "url": "https://github.com/michelf/php-markdown.git", - "reference": "de9a19c7bf352d41cc99ed86c3c0ef17e87394b6" + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "5f5137889b2aec36f8a1009ebe8673dac45f004e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/michelf/php-markdown/zipball/de9a19c7bf352d41cc99ed86c3c0ef17e87394b6", - "reference": "de9a19c7bf352d41cc99ed86c3c0ef17e87394b6", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/5f5137889b2aec36f8a1009ebe8673dac45f004e", + "reference": "5f5137889b2aec36f8a1009ebe8673dac45f004e", "shasum": "" }, "require": { - "php": ">=5.3.0" + "ext-mbstring": "*", + "php": ">=5.3.3" + }, + "replace": { + "colinodell/commonmark-php": "*" + }, + "require-dev": { + "erusev/parsedown": "~1.0", + "jgm/commonmark": "0.17", + "michelf/php-markdown": "~1.4", + "phpunit/phpunit": "~4.3" }, "type": "library", "extra": { "branch-alias": { - "dev-lib": "1.4.x-dev" + "dev-master": "0.7-dev" } }, "autoload": { - "psr-0": { - "Michelf": "" + "psr-4": { + "League\\CommonMark\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -945,22 +1180,103 @@ ], "authors": [ { - "name": "Michel Fortin", - "email": "michel.fortin@michelf.ca", - "homepage": "http://michelf.ca/", - "role": "Developer" - }, - { - "name": "John Gruber", - "homepage": "http://daringfireball.net/" + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "http://www.colinodell.com", + "role": "Lead Developer" } ], - "description": "PHP Markdown", - "homepage": "http://michelf.ca/projects/php-markdown/", + "description": "Markdown parser for PHP based on the CommonMark spec", + "homepage": "https://github.com/thephpleague/commonmark", "keywords": [ - "markdown" + "commonmark", + "markdown", + "parser" ], - "time": "2014-05-05 02:43:50" + "time": "2015-02-16 23:59:27" + }, + { + "name": "league/flysystem", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "efa1d394bb45b0984a863854c608c607b9c2a9a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/efa1d394bb45b0984a863854c608c607b9c2a9a4", + "reference": "efa1d394bb45b0984a863854c608c607b9c2a9a4", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "ext-fileinfo": "*", + "league/phpunit-coverage-listener": "~1.1", + "mockery/mockery": "~0.9", + "phpspec/phpspec": "~2.0.0", + "phpspec/prophecy-phpunit": "~1.0", + "phpunit/phpunit": "~4.0", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12.0" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "league/flysystem-aws-s3-v2": "Use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-copy": "Allows you to use Copy.com storage", + "league/flysystem-dropbox": "Use Dropbox storage", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "predis/predis": "Allows you to use Predis for caching" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "time": "2015-01-23 09:43:34" }, { "name": "monolog/monolog", @@ -1035,17 +1351,61 @@ "time": "2014-12-29 21:29:35" }, { - "name": "nesbot/carbon", - "version": "1.13.0", + "name": "mtdowling/cron-expression", + "version": "v1.0.4", "source": { "type": "git", - "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "5cb6e71055f7b0b57956b73d324cc4de31278f42" + "url": "https://github.com/mtdowling/cron-expression.git", + "reference": "fd92e883195e5dfa77720b1868cf084b08be4412" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/5cb6e71055f7b0b57956b73d324cc4de31278f42", - "reference": "5cb6e71055f7b0b57956b73d324cc4de31278f42", + "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/fd92e883195e5dfa77720b1868cf084b08be4412", + "reference": "fd92e883195e5dfa77720b1868cf084b08be4412", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "Cron": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "time": "2015-01-11 23:07:46" + }, + { + "name": "nesbot/carbon", + "version": "1.14.0", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "bb87460c995d97fe55b39e65f6ffb7f64b0a941e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bb87460c995d97fe55b39e65f6ffb7f64b0a941e", + "reference": "bb87460c995d97fe55b39e65f6ffb7f64b0a941e", "shasum": "" }, "require": { @@ -1078,36 +1438,36 @@ "datetime", "time" ], - "time": "2014-09-26 02:52:02" + "time": "2015-02-06 05:07:29" }, { "name": "nikic/php-parser", - "version": "v0.9.5", + "version": "v1.1.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb" + "reference": "ac05ef6f95bf8361549604b6031c115f92f39528" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ef70767475434bdb3615b43c327e2cae17ef12eb", - "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ac05ef6f95bf8361549604b6031c115f92f39528", + "reference": "ac05ef6f95bf8361549604b6031c115f92f39528", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=5.2" + "php": ">=5.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.9-dev" + "dev-master": "1.0-dev" } }, "autoload": { - "psr-0": { - "PHPParser": "lib/" - } + "files": [ + "lib/bootstrap.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1123,185 +1483,43 @@ "parser", "php" ], - "time": "2014-07-23 18:24:17" + "time": "2015-01-18 11:29:59" }, { - "name": "patchwork/utf8", - "version": "v1.1.28", + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/tchwork/utf8.git", - "reference": "ffa082111aa3cb23cf2479a17e6785ace91da982" + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tchwork/utf8/zipball/ffa082111aa3cb23cf2479a17e6785ace91da982", - "reference": "ffa082111aa3cb23cf2479a17e6785ace91da982", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", "shasum": "" }, "require": { - "lib-pcre": ">=7.3", - "php": ">=5.3.0" - }, - "suggest": { - "ext-iconv": "Use iconv for best performance", - "ext-intl": "Use Intl for best performance", - "ext-mbstring": "Use Mbstring for best performance" - }, - "type": "library", - "autoload": { - "psr-0": { - "Patchwork": "class/", - "Normalizer": "class/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "(Apache-2.0 or GPL-2.0)" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - } - ], - "description": "Portable and performant UTF-8, Unicode and Grapheme Clusters for PHP", - "homepage": "https://github.com/tchwork/utf8", - "keywords": [ - "grapheme", - "i18n", - "unicode", - "utf-8", - "utf8" - ], - "time": "2015-01-12 08:05:15" - }, - { - "name": "phpseclib/phpseclib", - "version": "0.3.9", - "source": { - "type": "git", - "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "c6e88ca6e81bc5a2d7161658e16a95b7ef8d6ad1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/c6e88ca6e81bc5a2d7161658e16a95b7ef8d6ad1", - "reference": "c6e88ca6e81bc5a2d7161658e16a95b7ef8d6ad1", - "shasum": "" - }, - "require": { - "php": ">=5.0.0" - }, - "require-dev": { - "phing/phing": "2.7.*", - "phpunit/phpunit": "4.0.*", - "sami/sami": "1.*", - "squizlabs/php_codesniffer": "1.*" - }, - "suggest": { - "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", - "ext-mcrypt": "Install the Mcrypt extension in order to speed up a wide variety of cryptographic operations.", - "pear-pear/PHP_Compat": "Install PHP_Compat to get phpseclib working on PHP < 4.3.3." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.3-dev" - } - }, - "autoload": { - "psr-0": { - "Crypt": "phpseclib/", - "File": "phpseclib/", - "Math": "phpseclib/", - "Net": "phpseclib/", - "System": "phpseclib/" - }, - "files": [ - "phpseclib/Crypt/Random.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "phpseclib/" - ], - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jim Wigginton", - "email": "terrafrost@php.net", - "role": "Lead Developer" - }, - { - "name": "Patrick Monnerat", - "email": "pm@datasphere.ch", - "role": "Developer" - }, - { - "name": "Andreas Fischer", - "email": "bantu@phpbb.com", - "role": "Developer" - }, - { - "name": "Hans-Jürgen Petrich", - "email": "petrich@tronic-media.com", - "role": "Developer" - } - ], - "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", - "homepage": "http://phpseclib.sourceforge.net", - "keywords": [ - "BigInteger", - "aes", - "asn.1", - "asn1", - "blowfish", - "crypto", - "cryptography", - "encryption", - "rsa", - "security", - "sftp", - "signature", - "signing", - "ssh", - "twofish", - "x.509", - "x509" - ], - "time": "2014-11-10 03:08:59" - }, - { - "name": "predis/predis", - "version": "v0.8.7", - "source": { - "type": "git", - "url": "https://github.com/nrk/predis.git", - "reference": "4123fcd85d61354c6c9900db76c9597dbd129bf6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nrk/predis/zipball/4123fcd85d61354c6c9900db76c9597dbd129bf6", - "reference": "4123fcd85d61354c6c9900db76c9597dbd129bf6", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" + "php": ">=5.3.3" }, "require-dev": { "phpunit/phpunit": "~4.0" }, "suggest": { - "ext-curl": "Allows access to Webdis when paired with phpiredis", - "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-0": { - "Predis": "lib/" + "phpDocumentor": [ + "src/" + ] } }, "notification-url": "https://packagist.org/downloads/", @@ -1310,19 +1528,11 @@ ], "authors": [ { - "name": "Daniele Alessandri", - "email": "suppakilla@gmail.com", - "homepage": "http://clorophilla.net" + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" } ], - "description": "Flexible and feature-complete PHP client library for Redis", - "homepage": "http://github.com/nrk/predis", - "keywords": [ - "nosql", - "predis", - "redis" - ], - "time": "2014-08-01 09:43:10" + "time": "2015-02-03 12:10:50" }, { "name": "psr/log", @@ -1363,36 +1573,53 @@ "time": "2012-12-21 11:40:51" }, { - "name": "stack/builder", - "version": "v1.0.3", + "name": "psy/psysh", + "version": "v0.4.1", "source": { "type": "git", - "url": "https://github.com/stackphp/builder.git", - "reference": "c1f8a4693b55c563405024f708a76ef576c3b276" + "url": "https://github.com/bobthecow/psysh.git", + "reference": "3787f3436f4fd898e0ac1eb6f5abd2ab6b24085b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stackphp/builder/zipball/c1f8a4693b55c563405024f708a76ef576c3b276", - "reference": "c1f8a4693b55c563405024f708a76ef576c3b276", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/3787f3436f4fd898e0ac1eb6f5abd2ab6b24085b", + "reference": "3787f3436f4fd898e0ac1eb6f5abd2ab6b24085b", "shasum": "" }, "require": { + "dnoegel/php-xdg-base-dir": "0.1", + "jakub-onderka/php-console-highlighter": "0.3.*", + "nikic/php-parser": "~1.0", "php": ">=5.3.0", - "symfony/http-foundation": "~2.1", - "symfony/http-kernel": "~2.1" + "symfony/console": "~2.3.10|~2.4.2|~2.5" }, "require-dev": { - "silex/silex": "~1.0" + "fabpot/php-cs-fixer": "~1.3", + "phpunit/phpunit": "~3.7|~4.0", + "squizlabs/php_codesniffer": "~2.0", + "symfony/finder": "~2.1" }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." + }, + "bin": [ + "bin/psysh" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-develop": "0.3.x-dev" } }, "autoload": { + "files": [ + "src/Psy/functions.php" + ], "psr-0": { - "Stack": "src" + "Psy\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1401,15 +1628,20 @@ ], "authors": [ { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" } ], - "description": "Builder for stack middlewares based on HttpKernelInterface.", + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", "keywords": [ - "stack" + "REPL", + "console", + "interactive", + "shell" ], - "time": "2014-11-23 20:37:11" + "time": "2015-02-25 20:35:54" }, { "name": "swiftmailer/swiftmailer", @@ -1464,40 +1696,35 @@ "time": "2014-12-05 14:17:14" }, { - "name": "symfony/browser-kit", - "version": "v2.5.9", - "target-dir": "Symfony/Component/BrowserKit", + "name": "symfony/class-loader", + "version": "v2.6.4", + "target-dir": "Symfony/Component/ClassLoader", "source": { "type": "git", - "url": "https://github.com/symfony/BrowserKit.git", - "reference": "b2b78b850a32251cbbd9915ab61453302e7ecd72" + "url": "https://github.com/symfony/ClassLoader.git", + "reference": "deac802f76910708ab50d039806cfd1866895b52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/BrowserKit/zipball/b2b78b850a32251cbbd9915ab61453302e7ecd72", - "reference": "b2b78b850a32251cbbd9915ab61453302e7ecd72", + "url": "https://api.github.com/repos/symfony/ClassLoader/zipball/deac802f76910708ab50d039806cfd1866895b52", + "reference": "deac802f76910708ab50d039806cfd1866895b52", "shasum": "" }, "require": { - "php": ">=5.3.3", - "symfony/dom-crawler": "~2.0,>=2.0.5" + "php": ">=5.3.3" }, "require-dev": { - "symfony/css-selector": "~2.0,>=2.0.5", - "symfony/process": "~2.0,>=2.0.5" - }, - "suggest": { - "symfony/process": "" + "symfony/finder": "~2.0,>=2.0.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { "psr-0": { - "Symfony\\Component\\BrowserKit\\": "" + "Symfony\\Component\\ClassLoader\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -1514,23 +1741,23 @@ "email": "fabien@symfony.com" } ], - "description": "Symfony BrowserKit Component", + "description": "Symfony ClassLoader Component", "homepage": "http://symfony.com", - "time": "2015-01-03 08:01:13" + "time": "2015-01-05 14:28:40" }, { "name": "symfony/console", - "version": "v2.5.9", + "version": "v2.6.4", "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "754f4b6de7b4a1d442f9b6a728bfb7adef54592c" + "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/754f4b6de7b4a1d442f9b6a728bfb7adef54592c", - "reference": "754f4b6de7b4a1d442f9b6a728bfb7adef54592c", + "url": "https://api.github.com/repos/symfony/Console/zipball/e44154bfe3e41e8267d7a3794cd9da9a51cfac34", + "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34", "shasum": "" }, "require": { @@ -1538,16 +1765,18 @@ }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.1" + "symfony/event-dispatcher": "~2.1", + "symfony/process": "~2.1" }, "suggest": { "psr/log": "For using the console logger", - "symfony/event-dispatcher": "" + "symfony/event-dispatcher": "", + "symfony/process": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -1571,76 +1800,29 @@ ], "description": "Symfony Console Component", "homepage": "http://symfony.com", - "time": "2015-01-06 17:40:45" - }, - { - "name": "symfony/css-selector", - "version": "v2.5.9", - "target-dir": "Symfony/Component/CssSelector", - "source": { - "type": "git", - "url": "https://github.com/symfony/CssSelector.git", - "reference": "d45b306421462295e76b94bcf76b963867450327" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/CssSelector/zipball/d45b306421462295e76b94bcf76b963867450327", - "reference": "d45b306421462295e76b94bcf76b963867450327", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\CssSelector\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony CssSelector Component", - "homepage": "http://symfony.com", - "time": "2015-01-03 08:01:13" + "time": "2015-01-25 04:39:26" }, { "name": "symfony/debug", - "version": "v2.5.9", + "version": "v2.6.4", "target-dir": "Symfony/Component/Debug", "source": { "type": "git", "url": "https://github.com/symfony/Debug.git", - "reference": "672a71e72310099540dfb03da2da553896e88483" + "reference": "150c80059c3ccf68f96a4fceb513eb6b41f23300" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Debug/zipball/672a71e72310099540dfb03da2da553896e88483", - "reference": "672a71e72310099540dfb03da2da553896e88483", + "url": "https://api.github.com/repos/symfony/Debug/zipball/150c80059c3ccf68f96a4fceb513eb6b41f23300", + "reference": "150c80059c3ccf68f96a4fceb513eb6b41f23300", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "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", @@ -1654,7 +1836,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -1678,74 +1860,21 @@ ], "description": "Symfony Debug Component", "homepage": "http://symfony.com", - "time": "2015-01-03 21:12:45" - }, - { - "name": "symfony/dom-crawler", - "version": "v2.5.9", - "target-dir": "Symfony/Component/DomCrawler", - "source": { - "type": "git", - "url": "https://github.com/symfony/DomCrawler.git", - "reference": "3860edcf7ff7e173cfe2151f0d425e610e77cc35" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/DomCrawler/zipball/3860edcf7ff7e173cfe2151f0d425e610e77cc35", - "reference": "3860edcf7ff7e173cfe2151f0d425e610e77cc35", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "symfony/css-selector": "~2.3" - }, - "suggest": { - "symfony/css-selector": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\DomCrawler\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony DomCrawler Component", - "homepage": "http://symfony.com", - "time": "2015-01-03 08:01:13" + "time": "2015-01-21 20:57:55" }, { "name": "symfony/event-dispatcher", - "version": "v2.6.3", + "version": "v2.6.4", "target-dir": "Symfony/Component/EventDispatcher", "source": { "type": "git", "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "40ff70cadea3785d83cac1c8309514b36113064e" + "reference": "f75989f3ab2743a82fe0b03ded2598a2b1546813" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/40ff70cadea3785d83cac1c8309514b36113064e", - "reference": "40ff70cadea3785d83cac1c8309514b36113064e", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/f75989f3ab2743a82fe0b03ded2598a2b1546813", + "reference": "f75989f3ab2743a82fe0b03ded2598a2b1546813", "shasum": "" }, "require": { @@ -1789,11 +1918,11 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "http://symfony.com", - "time": "2015-01-05 14:28:40" + "time": "2015-02-01 16:10:57" }, { "name": "symfony/filesystem", - "version": "v2.6.3", + "version": "v2.6.4", "target-dir": "Symfony/Component/Filesystem", "source": { "type": "git", @@ -1840,17 +1969,17 @@ }, { "name": "symfony/finder", - "version": "v2.5.9", + "version": "v2.6.4", "target-dir": "Symfony/Component/Finder", "source": { "type": "git", "url": "https://github.com/symfony/Finder.git", - "reference": "e527ebf47ff912a45e148b7d0b107b80ec0b3cc2" + "reference": "16513333bca64186c01609961a2bb1b95b5e1355" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/e527ebf47ff912a45e148b7d0b107b80ec0b3cc2", - "reference": "e527ebf47ff912a45e148b7d0b107b80ec0b3cc2", + "url": "https://api.github.com/repos/symfony/Finder/zipball/16513333bca64186c01609961a2bb1b95b5e1355", + "reference": "16513333bca64186c01609961a2bb1b95b5e1355", "shasum": "" }, "require": { @@ -1859,7 +1988,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -1883,21 +2012,21 @@ ], "description": "Symfony Finder Component", "homepage": "http://symfony.com", - "time": "2015-01-03 08:01:13" + "time": "2015-01-03 08:01:59" }, { "name": "symfony/http-foundation", - "version": "v2.5.9", + "version": "v2.6.4", "target-dir": "Symfony/Component/HttpFoundation", "source": { "type": "git", "url": "https://github.com/symfony/HttpFoundation.git", - "reference": "154d6c9ae8f7c27799a6119688dbd6026234441a" + "reference": "8fa63d614d56ccfe033e30411d90913cfc483ff6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/154d6c9ae8f7c27799a6119688dbd6026234441a", - "reference": "154d6c9ae8f7c27799a6119688dbd6026234441a", + "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/8fa63d614d56ccfe033e30411d90913cfc483ff6", + "reference": "8fa63d614d56ccfe033e30411d90913cfc483ff6", "shasum": "" }, "require": { @@ -1909,7 +2038,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -1936,35 +2065,35 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "http://symfony.com", - "time": "2015-01-03 11:12:44" + "time": "2015-02-01 16:10:57" }, { "name": "symfony/http-kernel", - "version": "v2.5.9", + "version": "v2.6.4", "target-dir": "Symfony/Component/HttpKernel", "source": { "type": "git", "url": "https://github.com/symfony/HttpKernel.git", - "reference": "a218b9ba87b24c440e4e9cd171c880e83796a5bb" + "reference": "27abf3106d8bd08562070dd4e2438c279792c434" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/a218b9ba87b24c440e4e9cd171c880e83796a5bb", - "reference": "a218b9ba87b24c440e4e9cd171c880e83796a5bb", + "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/27abf3106d8bd08562070dd4e2438c279792c434", + "reference": "27abf3106d8bd08562070dd4e2438c279792c434", "shasum": "" }, "require": { "php": ">=5.3.3", "psr/log": "~1.0", - "symfony/debug": "~2.5.9|~2.6,>=2.6.2", + "symfony/debug": "~2.6,>=2.6.2", "symfony/event-dispatcher": "~2.5.9|~2.6,>=2.6.2", - "symfony/http-foundation": "~2.5" + "symfony/http-foundation": "~2.5,>=2.5.4" }, "require-dev": { "symfony/browser-kit": "~2.3", "symfony/class-loader": "~2.1", "symfony/config": "~2.0,>=2.0.5", - "symfony/console": "~2.2", + "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", @@ -1973,7 +2102,9 @@ "symfony/process": "~2.0,>=2.0.5", "symfony/routing": "~2.2", "symfony/stopwatch": "~2.3", - "symfony/templating": "~2.2" + "symfony/templating": "~2.2", + "symfony/translation": "~2.0,>=2.0.5", + "symfony/var-dumper": "~2.6" }, "suggest": { "symfony/browser-kit": "", @@ -1981,12 +2112,13 @@ "symfony/config": "", "symfony/console": "", "symfony/dependency-injection": "", - "symfony/finder": "" + "symfony/finder": "", + "symfony/var-dumper": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -2010,21 +2142,21 @@ ], "description": "Symfony HttpKernel Component", "homepage": "http://symfony.com", - "time": "2015-01-07 12:32:08" + "time": "2015-02-02 18:02:30" }, { "name": "symfony/process", - "version": "v2.5.9", + "version": "v2.6.4", "target-dir": "Symfony/Component/Process", "source": { "type": "git", "url": "https://github.com/symfony/Process.git", - "reference": "3309098ce4d9b5e44c04e51bf4541ea466fbe343" + "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Process/zipball/3309098ce4d9b5e44c04e51bf4541ea466fbe343", - "reference": "3309098ce4d9b5e44c04e51bf4541ea466fbe343", + "url": "https://api.github.com/repos/symfony/Process/zipball/ecfc23e89d9967999fa5f60a1e9af7384396e9ae", + "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae", "shasum": "" }, "require": { @@ -2033,7 +2165,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -2057,21 +2189,21 @@ ], "description": "Symfony Process Component", "homepage": "http://symfony.com", - "time": "2015-01-05 20:58:03" + "time": "2015-01-25 04:39:26" }, { "name": "symfony/routing", - "version": "v2.5.9", + "version": "v2.6.4", "target-dir": "Symfony/Component/Routing", "source": { "type": "git", "url": "https://github.com/symfony/Routing.git", - "reference": "47e350dadadabdf64c8dbab499a1132c567f9411" + "reference": "bda1c3c67f2a33bbeabb1d321feaf626a0ca5698" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Routing/zipball/47e350dadadabdf64c8dbab499a1132c567f9411", - "reference": "47e350dadadabdf64c8dbab499a1132c567f9411", + "url": "https://api.github.com/repos/symfony/Routing/zipball/bda1c3c67f2a33bbeabb1d321feaf626a0ca5698", + "reference": "bda1c3c67f2a33bbeabb1d321feaf626a0ca5698", "shasum": "" }, "require": { @@ -2095,7 +2227,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -2125,21 +2257,21 @@ "uri", "url" ], - "time": "2015-01-05 08:51:41" + "time": "2015-01-15 12:15:12" }, { "name": "symfony/security-core", - "version": "v2.5.9", + "version": "v2.6.4", "target-dir": "Symfony/Component/Security/Core", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "e0d8f52dbb7d6e6a5d8df26b56bc68d829c8d519" + "reference": "4603bcc66e20e23f018c67f7f9f3f8146a100c11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/e0d8f52dbb7d6e6a5d8df26b56bc68d829c8d519", - "reference": "e0d8f52dbb7d6e6a5d8df26b56bc68d829c8d519", + "url": "https://api.github.com/repos/symfony/security-core/zipball/4603bcc66e20e23f018c67f7f9f3f8146a100c11", + "reference": "4603bcc66e20e23f018c67f7f9f3f8146a100c11", "shasum": "" }, "require": { @@ -2149,7 +2281,7 @@ "ircmaxell/password-compat": "1.0.*", "psr/log": "~1.0", "symfony/event-dispatcher": "~2.1", - "symfony/expression-language": "~2.4", + "symfony/expression-language": "~2.6", "symfony/http-foundation": "~2.4", "symfony/translation": "~2.0,>=2.0.5", "symfony/validator": "~2.5,>=2.5.5" @@ -2164,7 +2296,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -2188,39 +2320,41 @@ ], "description": "Symfony Security Component - Core Library", "homepage": "http://symfony.com", - "time": "2015-01-05 20:58:03" + "time": "2015-01-25 04:39:26" }, { "name": "symfony/translation", - "version": "v2.5.9", + "version": "v2.6.4", "target-dir": "Symfony/Component/Translation", "source": { "type": "git", "url": "https://github.com/symfony/Translation.git", - "reference": "165b5348cd20f8c4b2fcf1097c9c8300d1093b90" + "reference": "f289cdf8179d32058c1e1cbac723106a5ff6fa39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/165b5348cd20f8c4b2fcf1097c9c8300d1093b90", - "reference": "165b5348cd20f8c4b2fcf1097c9c8300d1093b90", + "url": "https://api.github.com/repos/symfony/Translation/zipball/f289cdf8179d32058c1e1cbac723106a5ff6fa39", + "reference": "f289cdf8179d32058c1e1cbac723106a5ff6fa39", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { + "psr/log": "~1.0", "symfony/config": "~2.3,>=2.3.12", "symfony/intl": "~2.3", "symfony/yaml": "~2.2" }, "suggest": { + "psr/log": "To use logging capability in translator", "symfony/config": "", "symfony/yaml": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -2244,34 +2378,147 @@ ], "description": "Symfony Translation Component", "homepage": "http://symfony.com", - "time": "2015-01-03 15:23:51" + "time": "2015-01-03 15:33:07" }, { - "name": "watson/validating", - "version": "0.10.6", + "name": "symfony/var-dumper", + "version": "v2.6.4", + "target-dir": "Symfony/Component/VarDumper", "source": { "type": "git", - "url": "https://github.com/dwightwatson/validating.git", - "reference": "673b165b4391942a7fae1e85a84f21b5f367f33f" + "url": "https://github.com/symfony/var-dumper.git", + "reference": "c3d5a36c3e3298bd8b070488fba5537174647353" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dwightwatson/validating/zipball/673b165b4391942a7fae1e85a84f21b5f367f33f", - "reference": "673b165b4391942a7fae1e85a84f21b5f367f33f", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c3d5a36c3e3298bd8b070488fba5537174647353", + "reference": "c3d5a36c3e3298bd8b070488fba5537174647353", "shasum": "" }, "require": { - "illuminate/database": "~4.2.6", - "illuminate/events": "~4.2.6", - "illuminate/support": "~4.2.6", - "illuminate/validation": "~4.2.6", + "php": ">=5.3.3" + }, + "suggest": { + "ext-symfony_debug": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-0": { + "Symfony\\Component\\VarDumper\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "http://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2015-02-02 16:32:08" + }, + { + "name": "vlucas/phpdotenv", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "732d2adb7d916c9593b9d58c3b0d9ebefead07aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/732d2adb7d916c9593b9d58c3b0d9ebefead07aa", + "reference": "732d2adb7d916c9593b9d58c3b0d9ebefead07aa", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Dotenv": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "authors": [ + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "http://www.vancelucas.com" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "homepage": "http://github.com/vlucas/phpdotenv", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "time": "2014-12-05 15:19:21" + }, + { + "name": "watson/validating", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/dwightwatson/validating.git", + "reference": "359a2a76666635f8ae122ece31a5da5e798005de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dwightwatson/validating/zipball/359a2a76666635f8ae122ece31a5da5e798005de", + "reference": "359a2a76666635f8ae122ece31a5da5e798005de", + "shasum": "" + }, + "require": { + "illuminate/database": "~5.0", + "illuminate/events": "~5.0", + "illuminate/support": "~5.0", + "illuminate/validation": "~5.0", "php": ">=5.4.0" }, "require-dev": { "mockery/mockery": "0.9.*", - "phpunit/phpunit": "4.1.*" + "phpunit/phpunit": "4.2.*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, "autoload": { "psr-4": { "Watson\\Validating\\": "src/" @@ -2293,16 +2540,2241 @@ "laravel", "validation" ], - "time": "2014-11-20 02:09:08" + "time": "2014-12-10 18:32:24" + } + ], + "packages-dev": [ + { + "name": "barryvdh/laravel-debugbar", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-debugbar.git", + "reference": "7bdf8acf3b955f4fcf922e74abdfdec370369196" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/7bdf8acf3b955f4fcf922e74abdfdec370369196", + "reference": "7bdf8acf3b955f4fcf922e74abdfdec370369196", + "shasum": "" + }, + "require": { + "illuminate/support": "5.0.x", + "maximebf/debugbar": "~1.10.2", + "php": ">=5.4.0", + "symfony/finder": "~2.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-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-02-19 10:26:39" + }, + { + "name": "codeception/c3", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/Codeception/c3.git", + "reference": "30321efb2421c5d201d02e2cb8da1a1ca96e4a38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/c3/zipball/30321efb2421c5d201d02e2cb8da1a1ca96e4a38", + "reference": "30321efb2421c5d201d02e2cb8da1a1ca96e4a38", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\c3\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert.php@resend.cc", + "homepage": "http://codegyre.com" + } + ], + "description": "CodeCoverage collector for Codeception", + "homepage": "http://codeception.com/", + "keywords": [ + "code coverage", + "codecoverage" + ], + "time": "2014-11-18 22:06:45" + }, + { + "name": "codeception/codeception", + "version": "2.0.11", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Codeception.git", + "reference": "9c7f23eff3e607225e9f43277c6d9cdb03d30b84" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/9c7f23eff3e607225e9f43277c6d9cdb03d30b84", + "reference": "9c7f23eff3e607225e9f43277c6d9cdb03d30b84", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "facebook/webdriver": "~0.4|~0.5", + "guzzlehttp/guzzle": "~4.0|~5.0", + "php": ">=5.4.0", + "phpunit/phpunit": "~4.5.0", + "symfony/browser-kit": "~2.4", + "symfony/console": "~2.4", + "symfony/css-selector": "~2.4", + "symfony/dom-crawler": "~2.4,!=2.4.5", + "symfony/event-dispatcher": "~2.4", + "symfony/finder": "~2.4", + "symfony/yaml": "~2.4" + }, + "require-dev": { + "codeception/specify": "~0.3", + "facebook/php-sdk": "~3.2", + "flow/jsonpath": "~0.2", + "monolog/monolog": "~1.8", + "pda/pheanstalk": "~2.0", + "videlalvaro/php-amqplib": "~2.4" + }, + "suggest": { + "codeception/phpbuiltinserver": "Extension to start and stop PHP built-in web server for your tests", + "codeception/specify": "BDD-style code blocks", + "codeception/verify": "BDD-style assertions", + "monolog/monolog": "Log test steps", + "phpseclib/phpseclib": "Extension required to use the SFTP option in the FTP Module." + }, + "bin": [ + "codecept" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-0": { + "Codeception": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" + } + ], + "description": "BDD-style testing framework", + "homepage": "http://codeception.com/", + "keywords": [ + "BDD", + "TDD", + "acceptance testing", + "functional testing", + "unit testing" + ], + "time": "2015-02-23 23:10:03" + }, + { + "name": "codeception/phpbuiltinserver", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/tiger-seo/PhpBuiltinServer.git", + "reference": "730206313b7e85d9ed4838ba02a0aee24fce1239" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tiger-seo/PhpBuiltinServer/zipball/730206313b7e85d9ed4838ba02a0aee24fce1239", + "reference": "730206313b7e85d9ed4838ba02a0aee24fce1239", + "shasum": "" + }, + "require": { + "codeception/codeception": ">=2.0.2", + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Codeception": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "tiger-seo", + "email": "tiger.seo@gmail.com" + } + ], + "description": "PhpBuiltinServer extension for Codeception", + "keywords": [ + "codeception" + ], + "time": "2014-09-19 10:14:07" + }, + { + "name": "codeception/specify", + "version": "0.4.1", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Specify.git", + "reference": "0c0ae07adfc231115b3b72ade22f44c23c199ded" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Specify/zipball/0c0ae07adfc231115b3b72ade22f44c23c199ded", + "reference": "0c0ae07adfc231115b3b72ade22f44c23c199ded", + "shasum": "" + }, + "require": { + "myclabs/deep-copy": "~1.1", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Codeception\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert.php@mailican.com" + } + ], + "description": "BDD code blocks for PHPUnit and Codeception", + "time": "2014-10-17 00:06:51" + }, + { + "name": "codeception/verify", + "version": "0.2.7", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Verify.git", + "reference": "66e5074905f4d9590ddb805d123fe632f4baa488" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Verify/zipball/66e5074905f4d9590ddb805d123fe632f4baa488", + "reference": "66e5074905f4d9590ddb805d123fe632f4baa488", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "files": [ + "src/Codeception/function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert.php@mailican.com", + "homepage": "http://codeception.com" + } + ], + "description": "BDD assertion library for PHPUnit", + "time": "2014-01-22 14:40:33" + }, + { + "name": "codeclimate/php-test-reporter", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/codeclimate/php-test-reporter.git", + "reference": "2a67d5d940e175fddba15f29c81a646ace26dc38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codeclimate/php-test-reporter/zipball/2a67d5d940e175fddba15f29c81a646ace26dc38", + "reference": "2a67d5d940e175fddba15f29c81a646ace26dc38", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3", + "satooshi/php-coveralls": "0.6.*", + "symfony/console": ">=2.0" + }, + "require-dev": { + "ext-xdebug": "*", + "phpunit/phpunit": "3.7.*@stable" + }, + "bin": [ + "composer/bin/test-reporter" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "CodeClimate\\Component": "src/", + "CodeClimate\\Bundle": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Code Climate", + "email": "hello@codeclimate.com", + "homepage": "https://codeclimate.com" + } + ], + "description": "PHP client for reporting test coverage to Code Climate", + "homepage": "https://github.com/codeclimate/php-test-reporter", + "keywords": [ + "codeclimate", + "coverage" + ], + "time": "2015-02-20 22:40:35" + }, + { + "name": "doctrine/instantiator", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119", + "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.*@ALPHA" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Instantiator\\": "src" + } + }, + "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": "2014-10-13 12:58:55" + }, + { + "name": "facebook/webdriver", + "version": "v0.5.1", + "source": { + "type": "git", + "url": "https://github.com/facebook/php-webdriver.git", + "reference": "bbcb697efb394d17bd9ec3d467e7da847cde4509" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/bbcb697efb394d17bd9ec3d467e7da847cde4509", + "reference": "bbcb697efb394d17bd9ec3d467e7da847cde4509", + "shasum": "" + }, + "require": { + "php": ">=5.3.19" + }, + "require-dev": { + "phpdocumentor/phpdocumentor": "2.*", + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "A php client for WebDriver", + "homepage": "https://github.com/facebook/php-webdriver", + "keywords": [ + "facebook", + "php", + "selenium", + "webdriver" + ], + "time": "2014-11-05 20:53:09" + }, + { + "name": "fzaninotto/faker", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "010c7efedd88bf31141a02719f51fb44c732d5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/010c7efedd88bf31141a02719f51fb44c732d5a0", + "reference": "010c7efedd88bf31141a02719f51fb44c732d5a0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "extra": { + "branch-alias": [] + }, + "autoload": { + "psr-0": { + "Faker": "src/", + "Faker\\PHPUnit": "test/" + } + }, + "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": "2014-06-04 14:43:02" + }, + { + "name": "guzzle/guzzle", + "version": "v3.9.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "54991459675c1a2924122afbb0e5609ade581155" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/54991459675c1a2924122afbb0e5609ade581155", + "reference": "54991459675c1a2924122afbb0e5609ade581155", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": "~2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/cache": "~1.3", + "monolog/monolog": "~1.0", + "phpunit/phpunit": "3.7.*", + "psr/log": "~1.0", + "symfony/class-loader": "~2.1", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.9-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2014-08-11 04:32:36" + }, + { + "name": "guzzlehttp/guzzle", + "version": "5.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "475b29ccd411f2fa8a408e64576418728c032cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/475b29ccd411f2fa8a408e64576418728c032cfa", + "reference": "475b29ccd411f2fa8a408e64576418728c032cfa", + "shasum": "" + }, + "require": { + "guzzlehttp/ringphp": "~1.0", + "php": ">=5.4.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0", + "psr/log": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2015-01-28 01:03:29" + }, + { + "name": "guzzlehttp/ringphp", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/guzzle/RingPHP.git", + "reference": "f43ab34aad69ca0ba04172cf2c3cd5c12fc0e5a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/f43ab34aad69ca0ba04172cf2c3cd5c12fc0e5a4", + "reference": "f43ab34aad69ca0ba04172cf2c3cd5c12fc0e5a4", + "shasum": "" + }, + "require": { + "guzzlehttp/streams": "~3.0", + "php": ">=5.4.0", + "react/promise": "~2.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "ext-curl": "Guzzle will use specific adapters if cURL is present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Ring\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", + "time": "2015-02-26 20:43:09" + }, + { + "name": "guzzlehttp/streams", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/streams.git", + "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", + "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple abstraction over streams of data", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "stream" + ], + "time": "2014-10-12 19:18:40" + }, + { + "name": "league/factory-muffin", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/factory-muffin.git", + "reference": "91f0adcdac6b5f7bf2277ac2c90f94352afe65de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/factory-muffin/zipball/91f0adcdac6b5f7bf2277ac2c90f94352afe65de", + "reference": "91f0adcdac6b5f7bf2277ac2c90f94352afe65de", + "shasum": "" + }, + "require": { + "fzaninotto/faker": "1.4.*", + "php": ">=5.3.3" + }, + "replace": { + "zizaco/factory-muff": "self.version" + }, + "require-dev": { + "illuminate/database": "~4.1", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "illuminate/database": "Factory Muffin works well with eloquent models." + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\FactoryMuffin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "graham@mineuk.com" + }, + { + "name": "Zizaco Zizuini", + "email": "zizaco@gmail.com" + }, + { + "name": "Scott Robertson", + "email": "scottymeuk@gmail.com" + } + ], + "description": "The goal of this package is to enable the rapid creation of objects for the purpose of testing.", + "homepage": "http://factory-muffin.thephpleague.com/", + "keywords": [ + "factory", + "laravel", + "testing" + ], + "time": "2014-09-18 18:29:06" + }, + { + "name": "maximebf/debugbar", + "version": "v1.10.4", + "source": { + "type": "git", + "url": "https://github.com/maximebf/php-debugbar.git", + "reference": "7b2006e6e095126b5a061ec33fca3d90ea8a8219" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/7b2006e6e095126b5a061ec33fca3d90ea8a8219", + "reference": "7b2006e6e095126b5a061ec33fca3d90ea8a8219", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0", + "symfony/var-dumper": "~2.6" + }, + "require-dev": { + "phpunit/phpunit": "~4.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.10-dev" + } + }, + "autoload": { + "psr-0": { + "DebugBar": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maxime Bouroumeau-Fuseau", + "email": "maxime.bouroumeau@gmail.com", + "homepage": "http://maximebf.com" + } + ], + "description": "Debug bar in the browser for php application", + "homepage": "https://github.com/maximebf/php-debugbar", + "keywords": [ + "debug" + ], + "time": "2015-02-05 07:51:20" + }, + { + "name": "myclabs/deep-copy", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "d93c485e71bcd22df0a994e9e3e03a3ef3a3e3f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/d93c485e71bcd22df0a994e9e3e03a3ef3a3e3f3", + "reference": "d93c485e71bcd22df0a994e9e3e03a3ef3a3e3f3", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "doctrine/collections": "1.*", + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "homepage": "https://github.com/myclabs/DeepCopy", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2014-11-20 05:11:17" + }, + { + "name": "phpspec/php-diff", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/phpspec/php-diff.git", + "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/php-diff/zipball/30e103d19519fe678ae64a60d77884ef3d71b28a", + "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Diff": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Chris Boulton", + "homepage": "http://github.com/chrisboulton", + "role": "Original developer" + } + ], + "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", + "time": "2013-11-01 13:02:21" + }, + { + "name": "phpspec/phpspec", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/phpspec.git", + "reference": "66a1df93099282b1514e9e001fcf6e9393f7783d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/phpspec/zipball/66a1df93099282b1514e9e001fcf6e9393f7783d", + "reference": "66a1df93099282b1514e9e001fcf6e9393f7783d", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.1", + "php": ">=5.3.3", + "phpspec/php-diff": "~1.0.0", + "phpspec/prophecy": "~1.1", + "sebastian/exporter": "~1.0", + "symfony/console": "~2.3", + "symfony/event-dispatcher": "~2.1", + "symfony/finder": "~2.1", + "symfony/process": "~2.1", + "symfony/yaml": "~2.1" + }, + "require-dev": { + "behat/behat": "~3.0,>=3.0.11", + "bossa/phpspec2-expect": "~1.0", + "symfony/filesystem": "~2.1" + }, + "suggest": { + "phpspec/nyan-formatters": "~1.0 – Adds Nyan formatters" + }, + "bin": [ + "bin/phpspec" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "PhpSpec": "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", + "homepage": "http://marcelloduarte.net/" + } + ], + "description": "Specification-oriented BDD framework for PHP 5.3+", + "homepage": "http://phpspec.net/", + "keywords": [ + "BDD", + "SpecBDD", + "TDD", + "spec", + "specification", + "testing", + "tests" + ], + "time": "2015-01-09 13:21:45" + }, + { + "name": "phpspec/prophecy", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/9ca52329bcdd1500de24427542577ebf3fc2f1c9", + "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.2", + "phpdocumentor/reflection-docblock": "~2.0" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.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": "http://phpspec.org", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2014-11-17 16:23:49" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.0.15", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "34cc484af1ca149188d0d9e91412191e398e0b67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/34cc484af1ca149188d0d9e91412191e398e0b67", + "reference": "34cc484af1ca149188d0d9e91412191e398e0b67", + "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.0", + "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.0.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-01-24 10:06:35" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "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": "2013-10-10 15:34:57" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2014-01-30 17:20:04" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "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": "2013-08-02 07:42:54" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/db32c18eba00b121c145575fcbcd4d4d24e6db74", + "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74", + "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-01-17 09:51:32" + }, + { + "name": "phpunit/phpunit", + "version": "4.5.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "5b578d3865a9128b9c209b011fda6539ec06e7a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5b578d3865a9128b9c209b011fda6539ec06e7a5", + "reference": "5b578d3865a9128b9c209b011fda6539ec06e7a5", + "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.0", + "phpunit/php-file-iterator": "~1.3.2", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "~1.0.2", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.1", + "sebastian/environment": "~1.2", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.5.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-02-05 15:51:19" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "c63d2367247365f688544f0d500af90a11a44c65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/c63d2367247365f688544f0d500af90a11a44c65", + "reference": "c63d2367247365f688544f0d500af90a11a44c65", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.1", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "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": "2014-10-03 05:12:11" + }, + { + "name": "react/promise", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/365fcee430dfa4ace1fbc75737ca60ceea7eeeef", + "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@googlemail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "time": "2014-12-30 13:32:42" + }, + { + "name": "satooshi/php-coveralls", + "version": "v0.6.1", + "source": { + "type": "git", + "url": "https://github.com/satooshi/php-coveralls.git", + "reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/dd0df95bd37a7cf5c5c50304dfe260ffe4b50760", + "reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-simplexml": "*", + "guzzle/guzzle": ">=3.0", + "php": ">=5.3", + "psr/log": "1.0.0", + "symfony/config": ">=2.0", + "symfony/console": ">=2.0", + "symfony/stopwatch": ">=2.2", + "symfony/yaml": ">=2.0" + }, + "require-dev": { + "apigen/apigen": "2.8.*@stable", + "pdepend/pdepend": "dev-master", + "phpmd/phpmd": "dev-master", + "phpunit/php-invoker": ">=1.1.0,<1.2.0", + "phpunit/phpunit": "3.7.*@stable", + "sebastian/finder-facade": "dev-master", + "sebastian/phpcpd": "1.4.*@stable", + "squizlabs/php_codesniffer": "1.4.*@stable", + "theseer/fdomdocument": "dev-master" + }, + "bin": [ + "composer/bin/coveralls" + ], + "type": "library", + "autoload": { + "psr-0": { + "Contrib\\Component": "src/", + "Contrib\\Bundle": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kitamura Satoshi", + "email": "with.no.parachute@gmail.com", + "homepage": "https://www.facebook.com/satooshi.jp" + } + ], + "description": "PHP client library for Coveralls API", + "homepage": "https://github.com/satooshi/php-coveralls", + "keywords": [ + "ci", + "coverage", + "github", + "test" + ], + "time": "2013-05-04 08:07:33" + }, + { + "name": "sebastian/comparator", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e", + "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.1.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-01-29 16:28:08" + }, + { + "name": "sebastian/diff", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "5843509fed39dee4b356a306401e9dd1a931fec7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7", + "reference": "5843509fed39dee4b356a306401e9dd1a931fec7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-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": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2014-08-15 10:29:00" + }, + { + "name": "sebastian/environment", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e6c71d918088c251b181ba8b3088af4ac336dd7", + "reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "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": "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": "2014-10-25 08:00:45" + }, + { + "name": "sebastian/exporter", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "84839970d05254c73cde183a721c7af13aede943" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", + "reference": "84839970d05254c73cde183a721c7af13aede943", + "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-01-27 07:23:06" + }, + { + "name": "sebastian/global-state", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "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": "2014-10-06 09:23:50" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252", + "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-01-24 09:48:32" + }, + { + "name": "sebastian/version", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "a77d9123f8e809db3fbdea15038c27a95da4058b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/a77d9123f8e809db3fbdea15038c27a95da4058b", + "reference": "a77d9123f8e809db3fbdea15038c27a95da4058b", + "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": "2014-12-15 14:25:24" + }, + { + "name": "symfony/browser-kit", + "version": "v2.6.4", + "target-dir": "Symfony/Component/BrowserKit", + "source": { + "type": "git", + "url": "https://github.com/symfony/BrowserKit.git", + "reference": "2ecec44ed5047020c65dd6e4a4b2f3cf13ae3c04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/BrowserKit/zipball/2ecec44ed5047020c65dd6e4a4b2f3cf13ae3c04", + "reference": "2ecec44ed5047020c65dd6e4a4b2f3cf13ae3c04", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/dom-crawler": "~2.0,>=2.0.5" + }, + "require-dev": { + "symfony/css-selector": "~2.0,>=2.0.5", + "symfony/process": "~2.0,>=2.0.5" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\BrowserKit\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "http://symfony.com", + "time": "2015-01-03 08:01:59" + }, + { + "name": "symfony/config", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Config", + "source": { + "type": "git", + "url": "https://github.com/symfony/Config.git", + "reference": "a9f781ba1221067d1f07c8cec0bc50f81b8d7408" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Config/zipball/a9f781ba1221067d1f07c8cec0bc50f81b8d7408", + "reference": "a9f781ba1221067d1f07c8cec0bc50f81b8d7408", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/filesystem": "~2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Config\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Config Component", + "homepage": "http://symfony.com", + "time": "2015-01-21 20:57:55" + }, + { + "name": "symfony/css-selector", + "version": "v2.6.4", + "target-dir": "Symfony/Component/CssSelector", + "source": { + "type": "git", + "url": "https://github.com/symfony/CssSelector.git", + "reference": "3f80ecc614fec68d5b4a84a0703db3fdf5ce8584" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/CssSelector/zipball/3f80ecc614fec68d5b4a84a0703db3fdf5ce8584", + "reference": "3f80ecc614fec68d5b4a84a0703db3fdf5ce8584", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\CssSelector\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "http://symfony.com", + "time": "2015-01-03 08:01:59" + }, + { + "name": "symfony/dom-crawler", + "version": "v2.6.4", + "target-dir": "Symfony/Component/DomCrawler", + "source": { + "type": "git", + "url": "https://github.com/symfony/DomCrawler.git", + "reference": "26a9eb302decd828990e1015afaa11b78b016073" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/DomCrawler/zipball/26a9eb302decd828990e1015afaa11b78b016073", + "reference": "26a9eb302decd828990e1015afaa11b78b016073", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/css-selector": "~2.3" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\DomCrawler\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "http://symfony.com", + "time": "2015-01-03 08:01:59" + }, + { + "name": "symfony/stopwatch", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Stopwatch", + "source": { + "type": "git", + "url": "https://github.com/symfony/Stopwatch.git", + "reference": "e8da5286132ba75ce4b4275fbf0f4cd369bfd71c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/e8da5286132ba75ce4b4275fbf0f4cd369bfd71c", + "reference": "e8da5286132ba75ce4b4275fbf0f4cd369bfd71c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Stopwatch\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Stopwatch Component", + "homepage": "http://symfony.com", + "time": "2015-01-03 08:01:59" + }, + { + "name": "symfony/yaml", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/60ed7751671113cf1ee7d7778e691642c2e9acd8", + "reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com", + "time": "2015-01-25 04:39:26" } ], - "packages-dev": null, "aliases": [], "minimum-stability": "stable", "stability-flags": { + "grumpydictator/gchart": 20, + "watson/validating": 20, "barryvdh/laravel-debugbar": 0, - "barryvdh/laravel-ide-helper": 0, - "mockery/mockery": 0, + "codeception/codeception": 0, + "codeception/c3": 0, "codeclimate/php-test-reporter": 20 }, "prefer-stable": false, diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000000..23d8fa9af1 --- /dev/null +++ b/config/app.php @@ -0,0 +1,213 @@ + env('APP_DEBUG'), + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | your application so that it is used when running Artisan tasks. + | + */ + + 'url' => 'http://localhost', + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. We have gone + | ahead and set this to a sensible default for you out of the box. + | + */ + + 'timezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by the translation service provider. You are free to set this value + | to any of the locales which will be supported by the application. + | + */ + + 'locale' => 'en', + + /* + |-------------------------------------------------------------------------- + | Application Fallback Locale + |-------------------------------------------------------------------------- + | + | The fallback locale determines the locale to use when the current one + | is not available. You may change the value to correspond to any of + | the language folders that are provided through your application. + | + */ + + 'fallback_locale' => 'en', + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is used by the Illuminate encrypter service and should be set + | to a random, 32 character string, otherwise these encrypted strings + | will not be safe. Please do this before deploying an application! + | + */ + + 'key' => env('APP_KEY', 'SomeRandomString'), + + 'cipher' => MCRYPT_RIJNDAEL_128, + + /* + |-------------------------------------------------------------------------- + | Logging Configuration + |-------------------------------------------------------------------------- + | + | Here you may configure the log settings for your application. Out of + | the box, Laravel uses the Monolog PHP logging library. This gives + | you a variety of powerful log handlers / formatters to utilize. + | + | Available Settings: "single", "daily", "syslog", "errorlog" + | + */ + + 'log' => 'daily', + + /* + |-------------------------------------------------------------------------- + | Autoloaded Service Providers + |-------------------------------------------------------------------------- + | + | The service providers listed here will be automatically loaded on the + | request to your application. Feel free to add your own services to + | this array to grant expanded functionality to your applications. + | + */ + + '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', + 'Barryvdh\Debugbar\ServiceProvider', + 'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider', + 'DaveJamesMiller\Breadcrumbs\ServiceProvider', + + /* + * Application Service Providers... + */ + 'FireflyIII\Providers\AppServiceProvider', + 'FireflyIII\Providers\BusServiceProvider', + 'FireflyIII\Providers\ConfigServiceProvider', + 'FireflyIII\Providers\EventServiceProvider', + 'FireflyIII\Providers\RouteServiceProvider', + 'FireflyIII\Providers\FireflyServiceProvider', + 'FireflyIII\Providers\TestingServiceProvider', + + ], + + /* + |-------------------------------------------------------------------------- + | Class Aliases + |-------------------------------------------------------------------------- + | + | This array of class aliases will be registered when this application + | is started. However, feel free to register as many as you wish as + | the aliases are "lazy" loaded so they don't hinder performance. + | + */ + + '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', + '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', + + ], + +]; diff --git a/config/auth.php b/config/auth.php new file mode 100644 index 0000000000..feff197837 --- /dev/null +++ b/config/auth.php @@ -0,0 +1,68 @@ + '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 + +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000000..9ddd5f331c --- /dev/null +++ b/config/cache.php @@ -0,0 +1,79 @@ + env('CACHE_DRIVER', 'file'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + */ + + 'stores' => [ + + 'apc' => [ + 'driver' => 'apc' + ], + + 'array' => [ + 'driver' => 'array' + ], + + 'database' => [ + 'driver' => 'database', + 'table' => 'cache', + 'connection' => null, + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path().'/framework/cache', + ], + + 'memcached' => [ + 'driver' => 'memcached', + 'servers' => [ + [ + 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 100 + ], + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing a RAM based store such as APC or Memcached, there might + | be other applications utilizing the same cache. So, we'll specify a + | value to get prefixed to all our keys so we can avoid collisions. + | + */ + + 'prefix' => 'laravel', + +]; diff --git a/config/compile.php b/config/compile.php new file mode 100644 index 0000000000..3a002fcaaa --- /dev/null +++ b/config/compile.php @@ -0,0 +1,41 @@ + [ + + 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'), + + ], + + /* + |-------------------------------------------------------------------------- + | Compiled File Providers + |-------------------------------------------------------------------------- + | + | Here you may list service providers which define a "compiles" function + | that returns additional files that should be compiled, providing an + | easy way to get common files from any packages you are utilizing. + | + */ + + 'providers' => [ + // + ], + +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000000..1f50345a38 --- /dev/null +++ b/config/database.php @@ -0,0 +1,125 @@ + PDO::FETCH_CLASS, + + /* + |-------------------------------------------------------------------------- + | Default Database Connection Name + |-------------------------------------------------------------------------- + | + | Here you may specify which of the database connections below you wish + | to use as your default connection for all database work. Of course + | you may use many connections at once using the Database library. + | + */ + + 'default' => env('DB_CONNECTION', 'mysql'), + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Here are each of the database connections setup for your application. + | Of course, examples of configuring each database platform that is + | supported by Laravel is shown below to make development simple. + | + | + | All database work in Laravel is done through the PHP PDO facilities + | so make sure you have the driver for your particular database of + | choice installed on your machine before you begin development. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'database' => realpath(__DIR__ . '/../tests/_data/db.sqlite'), + 'prefix' => '', + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'host' => env('DB_HOST', 'localhost'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + 'strict' => false, + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'host' => env('DB_HOST', 'localhost'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8', + 'prefix' => '', + 'schema' => 'public', + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'host' => env('DB_HOST', 'localhost'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'prefix' => '', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run in the database. + | + */ + + 'migrations' => 'migrations', + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer set of commands than a typical key-value systems + | such as APC or Memcached. Laravel makes it easy to dig right in. + | + */ + + 'redis' => [ + + 'cluster' => false, + + 'default' => [ + 'host' => '127.0.0.1', + 'port' => 6379, + 'database' => 0, + ], + + ], + +]; diff --git a/config/filesystems.php b/config/filesystems.php new file mode 100644 index 0000000000..ad8228f2fa --- /dev/null +++ b/config/filesystems.php @@ -0,0 +1,70 @@ + 'local', + + /* + |-------------------------------------------------------------------------- + | Default Cloud Filesystem Disk + |-------------------------------------------------------------------------- + | + | Many applications store files both locally and in the cloud. For this + | reason, you may specify a default "cloud" driver here. This driver + | will be bound as the Cloud disk implementation in the container. + | + */ + + 'cloud' => 's3', + + /* + |-------------------------------------------------------------------------- + | Filesystem Disks + |-------------------------------------------------------------------------- + | + | Here you may configure as many filesystem "disks" as you wish, and you + | may even configure multiple disks of the same driver. Defaults have + | been setup for each driver as an example of the required options. + | + */ + + 'disks' => [ + + 'local' => [ + 'driver' => 'local', + 'root' => storage_path().'/app', + ], + + 's3' => [ + 'driver' => 's3', + 'key' => 'your-key', + 'secret' => 'your-secret', + 'region' => 'your-region', + 'bucket' => 'your-bucket', + ], + + 'rackspace' => [ + 'driver' => 'rackspace', + 'username' => 'your-username', + 'key' => 'your-key', + 'container' => 'your-container', + 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', + 'region' => 'IAD', + ], + + ], + +]; diff --git a/config/firefly.php b/config/firefly.php new file mode 100644 index 0000000000..004b9803bf --- /dev/null +++ b/config/firefly.php @@ -0,0 +1,89 @@ + ['1D', '1W', '1M', '3M', '6M', '1Y', 'custom'], + 'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'], + 'piggy_bank_periods' => [ + 'week' => 'Week', + 'month' => 'Month', + 'quarter' => 'Quarter', + 'year' => 'Year' + ], + 'periods_to_text' => [ + 'weekly' => 'A week', + 'monthly' => 'A month', + 'quarterly' => 'A quarter', + 'half-year' => 'Six months', + 'yearly' => 'A year', + ], + + 'accountRoles' => [ + 'defaultExpense' => 'Default expense account', + 'sharedExpense' => 'Shared expense account' + ], + + 'range_to_text' => [ + '1D' => 'day', + '1W' => 'week', + '1M' => 'month', + '3M' => 'three months', + '6M' => 'half year', + 'custom' => '(custom)' + ], + 'range_to_name' => [ + '1D' => 'one day', + '1W' => 'one week', + '1M' => 'one month', + '3M' => 'three months', + '6M' => 'six months', + '1Y' => 'one year', + ], + 'range_to_repeat_freq' => [ + '1D' => 'weekly', + '1W' => 'weekly', + '1M' => 'monthly', + '3M' => 'quarterly', + '6M' => 'half-year', + 'custom' => 'monthly' + ], + 'subTitlesByIdentifier' => + [ + 'asset' => 'Asset accounts', + 'expense' => 'Expense accounts', + 'revenue' => 'Revenue accounts', + ], + 'subIconsByIdentifier' => + [ + 'asset' => 'fa-money', + 'Asset account' => 'fa-money', + 'Default account' => 'fa-money', + 'Cash account' => 'fa-money', + 'expense' => 'fa-shopping-cart', + 'Expense account' => 'fa-shopping-cart', + 'Beneficiary account' => 'fa-shopping-cart', + 'revenue' => 'fa-download', + 'Revenue account' => 'fa-download', + ], + 'accountTypesByIdentifier' => + [ + 'asset' => ['Default account', 'Asset account'], + 'expense' => ['Expense account', 'Beneficiary account'], + 'revenue' => ['Revenue account'], + ], + 'accountTypeByIdentifier' => + [ + 'asset' => 'Asset account', + 'expense' => 'Expense account', + 'revenue' => 'Revenue account', + ], + 'shortNamesByFullName' => + [ + 'Default account' => 'asset', + 'Asset account' => 'asset', + 'Expense account' => 'expense', + 'Beneficiary account' => 'expense', + 'Revenue account' => 'revenue', + 'Cash account' => 'cash', + ] + +]; diff --git a/config/mail.php b/config/mail.php new file mode 100644 index 0000000000..76d5eff892 --- /dev/null +++ b/config/mail.php @@ -0,0 +1,124 @@ + 'smtp', + + /* + |-------------------------------------------------------------------------- + | SMTP Host Address + |-------------------------------------------------------------------------- + | + | Here you may provide the host address of the SMTP server used by your + | applications. A default option is provided that is compatible with + | the Mailgun mail service which will provide reliable deliveries. + | + */ + + 'host' => env('EMAIL_SMTP', 'smtp.mailgun.org'), + + /* + |-------------------------------------------------------------------------- + | SMTP Host Port + |-------------------------------------------------------------------------- + | + | This is the SMTP port used by your application to deliver e-mails to + | users of the application. Like the host we have set this value to + | stay compatible with the Mailgun e-mail application by default. + | + */ + + 'port' => 587, + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all e-mails sent by your application to be sent from + | the same address. Here, you may specify a name and address that is + | used globally for all e-mails that are sent by your application. + | + */ + + 'from' => ['address' => env('EMAIL_USERNAME', null), 'name' => 'Firefly III Mailer'], + + /* + |-------------------------------------------------------------------------- + | E-Mail Encryption Protocol + |-------------------------------------------------------------------------- + | + | Here you may specify the encryption protocol that should be used when + | the application send e-mail messages. A sensible default using the + | transport layer security protocol should provide great security. + | + */ + + 'encryption' => 'tls', + + /* + |-------------------------------------------------------------------------- + | SMTP Server Username + |-------------------------------------------------------------------------- + | + | If your SMTP server requires a username for authentication, you should + | set it here. This will get used to authenticate with your server on + | connection. You may also set the "password" value below this one. + | + */ + + 'username' => env('EMAIL_USERNAME', null), + + /* + |-------------------------------------------------------------------------- + | SMTP Server Password + |-------------------------------------------------------------------------- + | + | Here you may set the password required by your SMTP server to send out + | messages from your application. This will be given to the server on + | connection so that the application will be able to send messages. + | + */ + + 'password' => env('EMAIL_PASSWORD', null), + + /* + |-------------------------------------------------------------------------- + | Sendmail System Path + |-------------------------------------------------------------------------- + | + | When using the "sendmail" driver to send e-mails, we will need to know + | the path to where Sendmail lives on this server. A default path has + | been provided here, which will work well on most of your systems. + | + */ + + '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' => false, + +]; diff --git a/config/queue.php b/config/queue.php new file mode 100644 index 0000000000..9c39a13644 --- /dev/null +++ b/config/queue.php @@ -0,0 +1,92 @@ + env('QUEUE_DRIVER', 'sync'), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection information for each server that + | is used by your application. A default configuration has been added + | for each back-end shipped with Laravel. You are free to add more. + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'database' => [ + 'driver' => 'database', + 'table' => 'jobs', + 'queue' => 'default', + 'expire' => 60, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => 'localhost', + 'queue' => 'default', + 'ttr' => 60, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => 'your-public-key', + 'secret' => 'your-secret-key', + 'queue' => 'your-queue-url', + '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, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control which database and table are used to store the jobs that + | have failed. You may change them to any database / table you wish. + | + */ + + 'failed' => [ + 'database' => 'mysql', 'table' => 'failed_jobs', + ], + +]; diff --git a/config/services.php b/config/services.php new file mode 100644 index 0000000000..dddc986601 --- /dev/null +++ b/config/services.php @@ -0,0 +1,37 @@ + [ + 'domain' => '', + 'secret' => '', + ], + + 'mandrill' => [ + 'secret' => '', + ], + + 'ses' => [ + 'key' => '', + 'secret' => '', + 'region' => 'us-east-1', + ], + + 'stripe' => [ + 'model' => 'User', + 'secret' => '', + ], + +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000000..47470fabc7 --- /dev/null +++ b/config/session.php @@ -0,0 +1,153 @@ + env('SESSION_DRIVER', 'file'), + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to immediately expire on the browser closing, set that option. + | + */ + + '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' => false, + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When using the native session driver, we need a location where session + | files may be stored. A default has been set for you but a different + | location may be specified. This is only needed for file 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, + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table we + | should use to manage the sessions. Of course, a sensible default is + | provided for you; however, you are free to change this as needed. + | + */ + + 'table' => 'sessions', + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | 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. + | + */ + + 'cookie' => 'laravel_session', + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application but you are free to change this when necessary. + | + */ + + 'path' => '/', + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | Here you may change the domain of the cookie used to identify a session + | in your application. This will determine which domains the cookie is + | available to in your application. A sensible default has been set. + | + */ + + 'domain' => null, + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you if it can not be done securely. + | + */ + + 'secure' => false, + +]; diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000000..88fc534aeb --- /dev/null +++ b/config/view.php @@ -0,0 +1,33 @@ + [ + realpath(base_path('resources/views')) + ], + + /* + |-------------------------------------------------------------------------- + | Compiled View Path + |-------------------------------------------------------------------------- + | + | This option determines where all the compiled Blade templates will be + | stored for your application. Typically, this is within the storage + | directory. However, as usual, you are free to change this value. + | + */ + + 'compiled' => realpath(storage_path().'/framework/views'), + +]; diff --git a/database/.gitignore b/database/.gitignore new file mode 100644 index 0000000000..9b1dffd90f --- /dev/null +++ b/database/.gitignore @@ -0,0 +1 @@ +*.sqlite diff --git a/app/controllers/.gitkeep b/database/migrations/.gitkeep similarity index 100% rename from app/controllers/.gitkeep rename to database/migrations/.gitkeep diff --git a/app/database/migrations/2014_06_27_163032_create_users_table.php b/database/migrations/2014_06_27_163032_create_users_table.php similarity index 61% rename from app/database/migrations/2014_06_27_163032_create_users_table.php rename to database/migrations/2014_06_27_163032_create_users_table.php index cd554148db..1bd8824f42 100644 --- a/app/database/migrations/2014_06_27_163032_create_users_table.php +++ b/database/migrations/2014_06_27_163032_create_users_table.php @@ -5,7 +5,7 @@ use Illuminate\Database\Schema\Blueprint; /** * @SuppressWarnings(PHPMD.ShortMethodName) - * + * * Class CreateUsersTable */ class CreateUsersTable extends Migration @@ -30,14 +30,13 @@ class CreateUsersTable extends Migration { Schema::create( 'users', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - $table->string('email', 100); - $table->string('password', 60); - $table->string('reset', 32)->nullable(); - $table->string('remember_token', 255)->nullable(); - $table->unique('email'); - } + $table->increments('id'); + $table->timestamps(); + $table->string('email', 100)->unique(); + $table->string('password', 60); + $table->rememberToken(); + $table->string('reset', 32)->nullable(); + } ); } diff --git a/app/database/migrations/2014_06_27_163145_create_account_types_table.php b/database/migrations/2014_06_27_163145_create_account_types_table.php similarity index 72% rename from app/database/migrations/2014_06_27_163145_create_account_types_table.php rename to database/migrations/2014_06_27_163145_create_account_types_table.php index 783ec4d15d..f55c0f09b6 100644 --- a/app/database/migrations/2014_06_27_163145_create_account_types_table.php +++ b/database/migrations/2014_06_27_163145_create_account_types_table.php @@ -5,7 +5,7 @@ use Illuminate\Database\Schema\Blueprint; /** * @SuppressWarnings(PHPMD.ShortMethodName) - * + * * Class CreateAccountTypesTable * */ @@ -31,13 +31,13 @@ class CreateAccountTypesTable extends Migration { Schema::create( 'account_types', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - $table->string('type', 30); - $table->boolean('editable'); + $table->increments('id'); + $table->timestamps(); + $table->string('type', 30); + $table->boolean('editable'); - $table->unique('type'); - } + $table->unique('type'); + } ); } diff --git a/database/migrations/2014_06_27_163259_create_accounts_table.php b/database/migrations/2014_06_27_163259_create_accounts_table.php new file mode 100644 index 0000000000..59c3cd4682 --- /dev/null +++ b/database/migrations/2014_06_27_163259_create_accounts_table.php @@ -0,0 +1,54 @@ +increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->integer('user_id')->unsigned(); + $table->integer('account_type_id')->unsigned(); + $table->string('name', 100); + $table->boolean('active'); + + // connect accounts to users + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + // connect accounts to account_types + $table->foreign('account_type_id')->references('id')->on('account_types')->onDelete('cascade'); + + // for a user, the account name must be unique. + $table->unique(['user_id', 'account_type_id', 'name']); + } + ); + } + +} diff --git a/app/database/migrations/2014_06_27_163817_create_components_table.php b/database/migrations/2014_06_27_163817_create_components_table.php similarity index 51% rename from app/database/migrations/2014_06_27_163817_create_components_table.php rename to database/migrations/2014_06_27_163817_create_components_table.php index 465b1ecaff..a96ab4d388 100644 --- a/app/database/migrations/2014_06_27_163817_create_components_table.php +++ b/database/migrations/2014_06_27_163817_create_components_table.php @@ -5,7 +5,7 @@ use Illuminate\Database\Schema\Blueprint; /** * @SuppressWarnings(PHPMD.ShortMethodName) - * + * * Class CreateComponentsTable * */ @@ -31,19 +31,19 @@ class CreateComponentsTable extends Migration { Schema::create( 'components', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - $table->softDeletes(); - $table->string('name', 50); - $table->integer('user_id')->unsigned(); - $table->string('class', 20); + $table->increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->string('name', 50); + $table->integer('user_id')->unsigned(); + $table->string('class', 20); - // connect components to users - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + // connect components to users + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - // for a user, the component type & name must be unique. - $table->unique(['user_id', 'class', 'name']); - } + // for a user, the component type & name must be unique. + $table->unique(['user_id', 'class', 'name']); + } ); } diff --git a/database/migrations/2014_06_27_163818_create_piggybanks_table.php b/database/migrations/2014_06_27_163818_create_piggybanks_table.php new file mode 100644 index 0000000000..827c5f4c48 --- /dev/null +++ b/database/migrations/2014_06_27_163818_create_piggybanks_table.php @@ -0,0 +1,60 @@ +increments('id'); + $table->timestamps(); + $table->integer('account_id')->unsigned(); + $table->string('name', 100); + $table->decimal('targetamount', 10, 2); + $table->date('startdate')->nullable(); + $table->date('targetdate')->nullable(); + $table->boolean('repeats'); + $table->enum('rep_length', ['day', 'week', 'quarter', 'month', 'year'])->nullable(); + $table->smallInteger('rep_every')->unsigned(); + $table->smallInteger('rep_times')->unsigned()->nullable(); + $table->enum('reminder', ['day', 'week', 'quarter', 'month', 'year'])->nullable(); + $table->smallInteger('reminder_skip')->unsigned(); + $table->boolean('remind_me'); + $table->integer('order')->unsigned(); + + // connect account to piggy bank. + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + + // for an account, the name must be unique. + $table->unique(['account_id', 'name']); + + } + ); + } + +} diff --git a/app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php b/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php similarity index 70% rename from app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php rename to database/migrations/2014_06_27_164042_create_transaction_currencies_table.php index 809a837bc9..d32e52f07b 100644 --- a/app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php +++ b/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php @@ -5,7 +5,7 @@ use Illuminate\Database\Schema\Blueprint; /** * @SuppressWarnings(PHPMD.ShortMethodName) - * + * * Class CreateTransactionCurrenciesTable * */ @@ -31,14 +31,14 @@ class CreateTransactionCurrenciesTable extends Migration { Schema::create( 'transaction_currencies', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - $table->softDeletes(); - $table->string('code', 3); + $table->increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->string('code', 3); - // code must be unique. - $table->unique(['code']); - } + // code must be unique. + $table->unique(['code']); + } ); } diff --git a/app/database/migrations/2014_06_27_164512_create_transaction_types_table.php b/database/migrations/2014_06_27_164512_create_transaction_types_table.php similarity index 69% rename from app/database/migrations/2014_06_27_164512_create_transaction_types_table.php rename to database/migrations/2014_06_27_164512_create_transaction_types_table.php index 746f037a84..4aa42eb9bd 100644 --- a/app/database/migrations/2014_06_27_164512_create_transaction_types_table.php +++ b/database/migrations/2014_06_27_164512_create_transaction_types_table.php @@ -5,7 +5,7 @@ use Illuminate\Database\Schema\Blueprint; /** * @SuppressWarnings(PHPMD.ShortMethodName) - * + * * Class CreateTransactionTypesTable * */ @@ -31,14 +31,14 @@ class CreateTransactionTypesTable extends Migration { Schema::create( 'transaction_types', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - $table->softDeletes(); - $table->string('type', 50); + $table->increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->string('type', 50); - // type must be unique. - $table->unique(['type']); - } + // type must be unique. + $table->unique(['type']); + } ); } diff --git a/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php b/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php new file mode 100644 index 0000000000..6c9ae0f668 --- /dev/null +++ b/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php @@ -0,0 +1,59 @@ +increments('id'); + $table->timestamps(); + $table->integer('user_id')->unsigned(); + $table->string('name', 50); + $table->string('match', 255); + $table->decimal('amount_min', 10, 2); + $table->decimal('amount_max', 10, 2); + $table->date('date'); + $table->boolean('active'); + + $table->boolean('automatch'); + $table->enum('repeat_freq', ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly']); + $table->smallInteger('skip')->unsigned(); + + // connect user id to users + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + // for a user, the name must be unique + $table->unique(['user_id', 'name']); + + + } + ); + } + +} diff --git a/database/migrations/2014_06_27_164620_create_transaction_journals_table.php b/database/migrations/2014_06_27_164620_create_transaction_journals_table.php new file mode 100644 index 0000000000..b41b1ff493 --- /dev/null +++ b/database/migrations/2014_06_27_164620_create_transaction_journals_table.php @@ -0,0 +1,62 @@ +increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->integer('user_id')->unsigned(); + $table->integer('transaction_type_id')->unsigned(); + $table->integer('recurring_transaction_id')->unsigned()->nullable(); + $table->integer('transaction_currency_id')->unsigned(); + $table->string('description', 255)->nullable(); + $table->boolean('completed'); + $table->date('date'); + + // connect users + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + // connect transaction journals to transaction types + $table->foreign('transaction_type_id')->references('id')->on('transaction_types')->onDelete('cascade'); + + // connect transaction journals to recurring transactions + $table->foreign('recurring_transaction_id')->references('id')->on('recurring_transactions')->onDelete('set null'); + + // connect transaction journals to transaction currencies + $table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('cascade'); + + + } + ); + } + +} diff --git a/database/migrations/2014_06_27_164836_create_transactions_table.php b/database/migrations/2014_06_27_164836_create_transactions_table.php new file mode 100644 index 0000000000..8e1c847db5 --- /dev/null +++ b/database/migrations/2014_06_27_164836_create_transactions_table.php @@ -0,0 +1,57 @@ +increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->integer('account_id')->unsigned(); + $table->integer('piggybank_id')->nullable()->unsigned(); + $table->integer('transaction_journal_id')->unsigned(); + $table->string('description', 255)->nullable(); + $table->decimal('amount', 10, 2); + + // connect account id: + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + + // connect piggy banks + $table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('set null'); + + // connect transactions to transaction journals + $table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade'); + + + } + ); + } + +} diff --git a/app/database/migrations/2014_06_27_165344_create_component_transaction_table.php b/database/migrations/2014_06_27_165344_create_component_transaction_table.php similarity index 51% rename from app/database/migrations/2014_06_27_165344_create_component_transaction_table.php rename to database/migrations/2014_06_27_165344_create_component_transaction_table.php index 6eee751926..03020da537 100644 --- a/app/database/migrations/2014_06_27_165344_create_component_transaction_table.php +++ b/database/migrations/2014_06_27_165344_create_component_transaction_table.php @@ -5,7 +5,7 @@ use Illuminate\Database\Schema\Blueprint; /** * @SuppressWarnings(PHPMD.ShortMethodName) - * + * * Class CreateComponentTransactionTable * */ @@ -31,19 +31,19 @@ class CreateComponentTransactionTable extends Migration { Schema::create( 'component_transaction', function (Blueprint $table) { - $table->increments('id'); - $table->integer('component_id')->unsigned(); - $table->integer('transaction_id')->unsigned(); + $table->increments('id'); + $table->integer('component_id')->unsigned(); + $table->integer('transaction_id')->unsigned(); - // connect to components - $table->foreign('component_id')->references('id')->on('components')->onDelete('cascade'); + // connect to components + $table->foreign('component_id')->references('id')->on('components')->onDelete('cascade'); - // connect to transactions - $table->foreign('transaction_id')->references('id')->on('transactions')->onDelete('cascade'); + // connect to transactions + $table->foreign('transaction_id')->references('id')->on('transactions')->onDelete('cascade'); - // combo must be unique: - $table->unique(['component_id', 'transaction_id']); - } + // combo must be unique: + $table->unique(['component_id', 'transaction_id']); + } ); } diff --git a/app/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php b/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php similarity index 100% rename from app/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php rename to database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php diff --git a/app/database/migrations/2014_07_06_123842_create_preferences_table.php b/database/migrations/2014_07_06_123842_create_preferences_table.php similarity index 55% rename from app/database/migrations/2014_07_06_123842_create_preferences_table.php rename to database/migrations/2014_07_06_123842_create_preferences_table.php index 7cd7069c8e..ef510274c9 100644 --- a/app/database/migrations/2014_07_06_123842_create_preferences_table.php +++ b/database/migrations/2014_07_06_123842_create_preferences_table.php @@ -31,18 +31,18 @@ class CreatePreferencesTable extends Migration { Schema::create( 'preferences', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - $table->integer('user_id')->unsigned(); - $table->string('name'); - $table->text('data'); + $table->increments('id'); + $table->timestamps(); + $table->integer('user_id')->unsigned(); + $table->string('name'); + $table->text('data'); - // connect preferences to users - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + // connect preferences to users + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - // only one preference per name per user - $table->unique(['user_id', 'name']); - } + // only one preference per name per user + $table->unique(['user_id', 'name']); + } ); } diff --git a/app/database/migrations/2014_07_09_204843_create_session_table.php b/database/migrations/2014_07_09_204843_create_session_table.php similarity index 100% rename from app/database/migrations/2014_07_09_204843_create_session_table.php rename to database/migrations/2014_07_09_204843_create_session_table.php diff --git a/app/database/migrations/2014_07_17_183717_create_limits_table.php b/database/migrations/2014_07_17_183717_create_limits_table.php similarity index 100% rename from app/database/migrations/2014_07_17_183717_create_limits_table.php rename to database/migrations/2014_07_17_183717_create_limits_table.php diff --git a/app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php b/database/migrations/2014_07_19_055011_create_limit_repeat_table.php similarity index 55% rename from app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php rename to database/migrations/2014_07_19_055011_create_limit_repeat_table.php index 46edc87ac9..5174585c72 100644 --- a/app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php +++ b/database/migrations/2014_07_19_055011_create_limit_repeat_table.php @@ -31,18 +31,18 @@ class CreateLimitRepeatTable extends Migration { Schema::create( 'limit_repetitions', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - $table->integer('limit_id')->unsigned(); - $table->date('startdate'); - $table->date('enddate'); - $table->decimal('amount', 10, 2); + $table->increments('id'); + $table->timestamps(); + $table->integer('limit_id')->unsigned(); + $table->date('startdate'); + $table->date('enddate'); + $table->decimal('amount', 10, 2); - $table->unique(['limit_id', 'startdate', 'enddate']); + $table->unique(['limit_id', 'startdate', 'enddate']); - // connect limit - $table->foreign('limit_id')->references('id')->on('limits')->onDelete('cascade'); - } + // connect limit + $table->foreign('limit_id')->references('id')->on('limits')->onDelete('cascade'); + } ); } diff --git a/app/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php b/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php similarity index 100% rename from app/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php rename to database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php diff --git a/app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php b/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php similarity index 52% rename from app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php rename to database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php index 341d36a9d8..223c4262ed 100644 --- a/app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php +++ b/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php @@ -31,18 +31,18 @@ class CreatePiggybankRepetitionsTable extends Migration { Schema::create( 'piggybank_repetitions', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - $table->integer('piggybank_id')->unsigned(); - $table->date('startdate')->nullable(); - $table->date('targetdate')->nullable(); - $table->decimal('currentamount', 10, 2); + $table->increments('id'); + $table->timestamps(); + $table->integer('piggybank_id')->unsigned(); + $table->date('startdate')->nullable(); + $table->date('targetdate')->nullable(); + $table->decimal('currentamount', 10, 2); - $table->unique(['piggybank_id', 'startdate', 'targetdate']); + $table->unique(['piggybank_id', 'startdate', 'targetdate']); - // connect instance to piggybank. - $table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('cascade'); - } + // connect instance to piggybank. + $table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('cascade'); + } ); } diff --git a/database/migrations/2014_08_18_100330_create_piggybank_events_table.php b/database/migrations/2014_08_18_100330_create_piggybank_events_table.php new file mode 100644 index 0000000000..5c68410837 --- /dev/null +++ b/database/migrations/2014_08_18_100330_create_piggybank_events_table.php @@ -0,0 +1,51 @@ +increments('id'); + $table->timestamps(); + $table->integer('piggybank_id')->unsigned(); + $table->integer('transaction_journal_id')->unsigned()->nullable(); + + $table->date('date'); + $table->decimal('amount', 10, 2); + + // connect instance to piggybank. + $table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('cascade'); + + // connect to journal: + $table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('set null'); + } + ); + } + +} diff --git a/database/migrations/2014_08_23_113221_create_reminders_table.php b/database/migrations/2014_08_23_113221_create_reminders_table.php new file mode 100644 index 0000000000..aaecf27eb6 --- /dev/null +++ b/database/migrations/2014_08_23_113221_create_reminders_table.php @@ -0,0 +1,50 @@ +increments('id'); + $table->timestamps(); + $table->integer('user_id')->unsigned(); + $table->date('startdate'); + $table->date('enddate')->nullable(); + $table->boolean('active'); + $table->boolean('notnow')->default(0); + $table->integer('remindersable_id')->unsigned()->nullable(); + $table->string('remindersable_type')->nullable(); + + // connect reminders to users + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + } + ); + } + +} diff --git a/database/migrations/2014_10_12_100000_create_password_resets_table.php b/database/migrations/2014_10_12_100000_create_password_resets_table.php new file mode 100644 index 0000000000..788ebc23e6 --- /dev/null +++ b/database/migrations/2014_10_12_100000_create_password_resets_table.php @@ -0,0 +1,38 @@ +string('email')->index(); + $table->string('token')->index(); + $table->timestamp('created_at'); + } + ); + } + +} diff --git a/app/database/migrations/2014_11_10_172053_create_account_meta_table.php b/database/migrations/2014_11_10_172053_create_account_meta_table.php similarity index 68% rename from app/database/migrations/2014_11_10_172053_create_account_meta_table.php rename to database/migrations/2014_11_10_172053_create_account_meta_table.php index 1febb05a1b..24f92af144 100644 --- a/app/database/migrations/2014_11_10_172053_create_account_meta_table.php +++ b/database/migrations/2014_11_10_172053_create_account_meta_table.php @@ -33,16 +33,16 @@ class CreateAccountMetaTable extends Migration // Schema::create( 'account_meta', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - $table->integer('account_id')->unsigned(); - $table->string('name'); - $table->text('data'); + $table->increments('id'); + $table->timestamps(); + $table->integer('account_id')->unsigned(); + $table->string('name'); + $table->text('data'); - $table->unique(['account_id', 'name']); + $table->unique(['account_id', 'name']); - } + } ); } diff --git a/app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php b/database/migrations/2014_11_29_135749_create_transaction_groups_table.php similarity index 61% rename from app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php rename to database/migrations/2014_11_29_135749_create_transaction_groups_table.php index c3d2e3af49..db68b79146 100644 --- a/app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php +++ b/database/migrations/2014_11_29_135749_create_transaction_groups_table.php @@ -31,15 +31,15 @@ class CreateTransactionGroupsTable extends Migration { Schema::create( 'transaction_groups', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - $table->softDeletes(); - $table->integer('user_id')->unsigned(); - $table->enum('relation', ['balance']); + $table->increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->integer('user_id')->unsigned(); + $table->enum('relation', ['balance']); - // connect reminders to users - $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - } + // connect reminders to users + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + } ); diff --git a/app/database/migrations/2014_11_29_140217_create_transaction_group_transaction_journal_table.php b/database/migrations/2014_11_29_140217_create_transaction_group_transaction_journal_table.php similarity index 52% rename from app/database/migrations/2014_11_29_140217_create_transaction_group_transaction_journal_table.php rename to database/migrations/2014_11_29_140217_create_transaction_group_transaction_journal_table.php index 7a275b68d6..444e64b7c1 100644 --- a/app/database/migrations/2014_11_29_140217_create_transaction_group_transaction_journal_table.php +++ b/database/migrations/2014_11_29_140217_create_transaction_group_transaction_journal_table.php @@ -32,17 +32,17 @@ class CreateTransactionGroupTransactionJournalTable extends Migration Schema::create( 'transaction_group_transaction_journal', function (Blueprint $table) { - $table->increments('id'); - $table->integer('transaction_group_id')->unsigned(); - $table->integer('transaction_journal_id')->unsigned(); + $table->increments('id'); + $table->integer('transaction_group_id')->unsigned(); + $table->integer('transaction_journal_id')->unsigned(); - // link to foreign tables. - $table->foreign('transaction_group_id', 'tr_grp_id')->references('id')->on('transaction_groups')->onDelete('cascade'); - $table->foreign('transaction_journal_id', 'tr_trj_id')->references('id')->on('transaction_journals')->onDelete('cascade'); + // link to foreign tables. + $table->foreign('transaction_group_id', 'tr_grp_id')->references('id')->on('transaction_groups')->onDelete('cascade'); + $table->foreign('transaction_journal_id', 'tr_trj_id')->references('id')->on('transaction_journals')->onDelete('cascade'); - // add unique. - $table->unique(['transaction_group_id', 'transaction_journal_id'], 'tt_joined'); - } + // add unique. + $table->unique(['transaction_group_id', 'transaction_journal_id'], 'tt_joined'); + } ); } diff --git a/app/database/migrations/2014_12_13_190730_changes_for_v321.php b/database/migrations/2014_12_13_190730_changes_for_v321.php similarity index 97% rename from app/database/migrations/2014_12_13_190730_changes_for_v321.php rename to database/migrations/2014_12_13_190730_changes_for_v321.php index 9d5242189d..c5a2be3f0c 100644 --- a/app/database/migrations/2014_12_13_190730_changes_for_v321.php +++ b/database/migrations/2014_12_13_190730_changes_for_v321.php @@ -1,5 +1,7 @@ dropForeign('limit_repetitions_budget_limit_id_foreign'); $table->renameColumn('budget_limit_id', 'limit_id'); + $table->foreign('limit_id')->references('id')->on('limits')->onDelete('cascade'); } ); } @@ -402,7 +406,9 @@ class ChangesForV321 extends Migration { Schema::table( 'limit_repetitions', function (Blueprint $table) { + $table->dropForeign('limit_repetitions_limit_id_foreign'); $table->renameColumn('limit_id', 'budget_limit_id'); + $table->foreign('budget_limit_id')->references('id')->on('budget_limits')->onDelete('cascade'); } ); } diff --git a/app/database/migrations/2014_12_24_191544_changes_for_v322.php b/database/migrations/2014_12_24_191544_changes_for_v322.php similarity index 93% rename from app/database/migrations/2014_12_24_191544_changes_for_v322.php rename to database/migrations/2014_12_24_191544_changes_for_v322.php index 5b5e7abff2..fc78f7b173 100644 --- a/app/database/migrations/2014_12_24_191544_changes_for_v322.php +++ b/database/migrations/2014_12_24_191544_changes_for_v322.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * @SuppressWarnings(PHPMD.ShortMethodName) * @SuppressWarnings("MethodLength") // I don't mind this in case of migrations. - * * Class ChangesForV322 */ @@ -109,13 +108,17 @@ class ChangesForV322 extends Migration // rename fields Schema::table( 'piggy_bank_events', function (Blueprint $table) { + $table->dropForeign('piggybank_events_piggybank_id_foreign'); $table->renameColumn('piggybank_id', 'piggy_bank_id'); + $table->foreign('piggy_bank_id')->references('id')->on('piggy_banks')->onDelete('cascade'); } ); Schema::table( 'piggy_bank_repetitions', function (Blueprint $table) { + $table->dropForeign('piggybank_repetitions_piggybank_id_foreign'); $table->renameColumn('piggybank_id', 'piggy_bank_id'); + $table->foreign('piggy_bank_id')->references('id')->on('piggy_banks')->onDelete('cascade'); } ); diff --git a/app/database/migrations/2015_01_18_082406_changes_for_v325.php b/database/migrations/2015_01_18_082406_changes_for_v325.php similarity index 96% rename from app/database/migrations/2015_01_18_082406_changes_for_v325.php rename to database/migrations/2015_01_18_082406_changes_for_v325.php index 32a4d2e769..d24b6d1c87 100644 --- a/app/database/migrations/2015_01_18_082406_changes_for_v325.php +++ b/database/migrations/2015_01_18_082406_changes_for_v325.php @@ -1,7 +1,6 @@ call('AccountTypeSeeder'); $this->call('TransactionCurrencySeeder'); diff --git a/app/database/seeds/TestDataSeeder.php b/database/seeds/TestDataSeeder.php similarity index 93% rename from app/database/seeds/TestDataSeeder.php rename to database/seeds/TestDataSeeder.php index 0c3de6f0af..35bd3d8d9f 100644 --- a/app/database/seeds/TestDataSeeder.php +++ b/database/seeds/TestDataSeeder.php @@ -1,5 +1,23 @@ $user->id, 'account_type_id' => $assetType->id, 'name' => 'Savings account', 'active' => 1]); $acc_c = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Delete me', 'active' => 1]); + // create account meta: + $meta_a = AccountMeta::create(['account_id' => $acc_a->id, 'name' => 'accountRole', 'data' => 'defaultExpense']); + $meta_b = AccountMeta::create(['account_id' => $acc_b->id, 'name' => 'accountRole', 'data' => 'defaultExpense']); + $meta_c = AccountMeta::create(['account_id' => $acc_c->id, 'name' => 'accountRole', 'data' => 'defaultExpense']); +// var_dump($meta_a->toArray()); +// var_dump($meta_b->toArray()); +// var_dump($meta_c->toArray()); + $acc_d = Account::create(['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Checking account initial balance', 'active' => 0]); $acc_e = Account::create(['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Savings account initial balance', 'active' => 0]); $acc_f = Account::create(['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Delete me initial balance', 'active' => 0]); @@ -197,9 +223,9 @@ class TestDataSeeder extends Seeder ); // and because we have no filters, some repetitions: - LimitRepetition::create(['budget_limit_id' => $groceriesLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 201]); - LimitRepetition::create(['budget_limit_id' => $billsLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 202]); - LimitRepetition::create(['budget_limit_id' => $deleteMeLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 203]); + // LimitRepetition::create(['budget_limit_id' => $groceriesLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 201]); + // LimitRepetition::create(['budget_limit_id' => $billsLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 202]); + // LimitRepetition::create(['budget_limit_id' => $deleteMeLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 203]); } /** @@ -366,7 +392,7 @@ class TestDataSeeder extends Seeder $user = User::whereEmail('thegrumpydictator@gmail.com')->first(); // bill Bill::create( - ['user_id' => $user->id, 'name' => 'Rent', 'match' => 'rent,landlord', 'amount_min' => 700, 'amount_max' => 900, 'date' => $this->som, + ['user_id' => $user->id, 'name' => 'Rent', 'match' => 'rent,land,lord', 'amount_min' => 700, 'amount_max' => 900, 'date' => $this->som, 'active' => 1, 'automatch' => 1, 'repeat_freq' => 'monthly', 'skip' => 0,] ); @@ -592,8 +618,8 @@ class TestDataSeeder extends Seeder $house = Category::whereName('House')->orderBy('id', 'DESC')->first(); $piggyBank = PiggyBank::whereName('New camera')->orderBy('id', 'DESC')->first(); $intoPiggy = $this->createJournal( - ['from' => $checking, 'to' => $savings, 'amount' => 100, 'transactionType' => $transfer, 'description' => 'Money for piggy', - 'date' => $this->yaeom, 'transactionCurrency' => $euro, 'category' => $house, 'budget' => $groceries] + ['from' => $checking, 'to' => $savings, 'amount' => 100, 'transactionType' => $transfer, 'description' => 'Money for piggy', + 'date' => $this->yaeom, 'transactionCurrency' => $euro, 'category' => $house, 'budget' => $groceries] ); PiggyBankEvent::create( [ diff --git a/database/seeds/TransactionCurrencySeeder.php b/database/seeds/TransactionCurrencySeeder.php new file mode 100644 index 0000000000..a53bb414b6 --- /dev/null +++ b/database/seeds/TransactionCurrencySeeder.php @@ -0,0 +1,20 @@ +delete(); + + TransactionCurrency::create(['code' => 'EUR', 'name' => 'Euro', 'symbol' => '€']); + TransactionCurrency::create(['code' => 'USD', 'name' => 'US Dollar', 'symbol' => '$']); + TransactionCurrency::create(['code' => 'HUF', 'name' => 'Hungarian forint', 'symbol' => 'Ft']); + } + +} diff --git a/app/database/seeds/TransactionTypeSeeder.php b/database/seeds/TransactionTypeSeeder.php similarity index 85% rename from app/database/seeds/TransactionTypeSeeder.php rename to database/seeds/TransactionTypeSeeder.php index cf0e6a5e12..ecdff20b05 100644 --- a/app/database/seeds/TransactionTypeSeeder.php +++ b/database/seeds/TransactionTypeSeeder.php @@ -1,5 +1,6 @@ - - - - - ./app/models - ./app/controllers - ./app/events - ./app/extensions - ./app/queue - ./app/helpers - ./app/lib/FireflyIII - - ./app/controllers/BaseController.php - - - - - - - - - - ./app/tests/ - - - ./tests/unit/ + ./tests/ + + + + + diff --git a/provider/assets/javascripts/jquery.min.js b/provider/assets/javascripts/jquery.min.js deleted file mode 100644 index da4170647d..0000000000 --- a/provider/assets/javascripts/jquery.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license -//@ sourceMappingURL=jquery-1.10.2.min.map -*/ -(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="
",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
t
",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t -}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); -u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("