diff --git a/.travis.yml b/.travis.yml index 1f82f07b02..102eb830b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,12 @@ php: - 5.5 - 5.6 +addons: + code_climate: + repo_token: 26489f9e854fcdf7e7660ba29c1455694685465b1f90329a79f7d2bf448acb61 + install: + - rm composer.lock - composer install script: @@ -13,4 +18,7 @@ script: - php vendor/bin/codecept run --coverage --coverage-xml after_script: + - cp -v tests/_output/coverage.xml build/logs/clover.xml - php vendor/bin/coveralls + - vendor/bin/test-reporter --stdout > codeclimate.json + - "curl -X POST -d @codeclimate.json -H 'Content-Type: application/json' -H 'User-Agent: Code Climate (PHP Test Reporter v0.1.1)' https://codeclimate.com/test_reports" \ No newline at end of file diff --git a/README.md b/README.md index 2a83d210a2..a65289f98f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -Firefly III +Firefly III (v3.2.5) =========== [![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=develop)](https://travis-ci.org/JC5/firefly-iii) [![Project Status](http://stillmaintained.com/JC5/firefly-iii.png?a=b)](http://stillmaintained.com/JC5/firefly-iii) [![Coverage Status](https://coveralls.io/repos/JC5/firefly-iii/badge.png?branch=master)](https://coveralls.io/r/JC5/firefly-iii?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102/mini.png)](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102) +[![Code Climate](https://codeclimate.com/github/JC5/firefly-iii/badges/gpa.svg)](https://codeclimate.com/github/JC5/firefly-iii) +[![Test Coverage](https://codeclimate.com/github/JC5/firefly-iii/badges/coverage.svg)](https://codeclimate.com/github/JC5/firefly-iii) [![Latest Stable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/stable.svg)](https://packagist.org/packages/grumpydictator/firefly-iii) [![Total Downloads](https://poser.pugx.org/grumpydictator/firefly-iii/downloads.svg)](https://packagist.org/packages/grumpydictator/firefly-iii) diff --git a/_sql/firefly-iii-reference-3.2.5.sql b/_sql/firefly-iii-reference-3.2.5.sql new file mode 100644 index 0000000000..b2ad69f707 --- /dev/null +++ b/_sql/firefly-iii-reference-3.2.5.sql @@ -0,0 +1,607 @@ +# ************************************************************ +# 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/controllers/BillController.php b/app/controllers/BillController.php index 521c21736b..0fdd0f7309 100644 --- a/app/controllers/BillController.php +++ b/app/controllers/BillController.php @@ -5,8 +5,7 @@ use FireflyIII\Exception\FireflyException; /** * * @SuppressWarnings("CamelCase") // I'm fine with this. - * @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok. - * @SuppressWarnings("NPathComplexity") + * * Class BillController * */ @@ -120,9 +119,9 @@ class BillController extends BaseController */ public function show(Bill $bill) { - $journals = $bill->transactionjournals()->withRelevantData()->orderBy('date', 'DESC')->get(); + $journals = $bill->transactionjournals()->withRelevantData()->orderBy('date', 'DESC')->get(); $bill->nextExpectedMatch = $this->_repository->nextExpectedMatch($bill); - $hideBill = true; + $hideBill = true; return View::make('bills.show', compact('journals', 'hideBill', 'bill'))->with( @@ -136,7 +135,7 @@ class BillController extends BaseController */ public function store() { - $data = Input::all(); + $data = Input::except(['_token', 'post_submit_action']); $data['user_id'] = Auth::user()->id; @@ -149,17 +148,19 @@ class BillController extends BaseController 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 ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + 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 ($data['post_submit_action'] == 'store') { + if (Input::get('post_submit_action') == 'store') { return Redirect::route('bills.index'); } @@ -176,8 +177,8 @@ class BillController extends BaseController public function update(Bill $bill) { $data = Input::except('_token'); - $data['active'] = isset($data['active']) ? 1 : 0; - $data['automatch'] = isset($data['automatch']) ? 1 : 0; + $data['active'] = intval(Input::get('active')); + $data['automatch'] = intval(Input::get('automatch')); $data['user_id'] = Auth::user()->id; // always validate: @@ -189,10 +190,12 @@ class BillController extends BaseController 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' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('bills.edit', $bill->id)->withInput(); } diff --git a/app/controllers/BudgetController.php b/app/controllers/BudgetController.php index 500ed85573..5a42967adc 100644 --- a/app/controllers/BudgetController.php +++ b/app/controllers/BudgetController.php @@ -8,9 +8,6 @@ use FireflyIII\Shared\Preferences\PreferencesInterface as Pref; * Class BudgetController * * @SuppressWarnings("CamelCase") // I'm fine with this. - * @SuppressWarnings("TooManyMethods") // I'm also fine with this. - * @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok. - * @SuppressWarnings("CouplingBetweenObjects") // There's only so much I can remove. * */ class BudgetController extends BaseController @@ -45,7 +42,7 @@ class BudgetController extends BaseController $date = Session::get('start', Carbon::now()->startOfMonth()); $limitRepetition = $this->_repository->updateLimitAmount($budget, $date, $amount); - return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition->id]); + return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0]); } @@ -148,6 +145,8 @@ class BudgetController extends BaseController } /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param Budget $budget * @param LimitRepetition $repetition * @@ -184,10 +183,11 @@ class BudgetController extends BaseController 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' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('budgets.create')->withInput(); } @@ -222,10 +222,11 @@ class BudgetController extends BaseController 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' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('budgets.edit', $budget->id)->withInput(); } diff --git a/app/controllers/CategoryController.php b/app/controllers/CategoryController.php index 8459b4c40f..bc5d0846f1 100644 --- a/app/controllers/CategoryController.php +++ b/app/controllers/CategoryController.php @@ -6,7 +6,6 @@ use FireflyIII\Exception\FireflyException; /** * * @SuppressWarnings("CamelCase") // I'm fine with this. - * @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok. * * Class CategoryController */ @@ -106,6 +105,7 @@ class CategoryController extends BaseController } /** + * * @return $this * @throws FireflyException */ @@ -123,10 +123,11 @@ class CategoryController extends BaseController 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' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('categories.create')->withInput(); } @@ -141,6 +142,7 @@ class CategoryController extends BaseController } /** + * * @param Category $category * * @return $this @@ -160,10 +162,11 @@ class CategoryController extends BaseController 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' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('categories.edit', $category->id)->withInput(); } diff --git a/app/controllers/CurrencyController.php b/app/controllers/CurrencyController.php index d8c2d5b5d6..9b55132333 100644 --- a/app/controllers/CurrencyController.php +++ b/app/controllers/CurrencyController.php @@ -4,7 +4,6 @@ use FireflyIII\Database\TransactionCurrency\TransactionCurrency as Repository; /** * * @SuppressWarnings("CamelCase") // I'm fine with this. - * @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok. * * Class CurrencyController */ @@ -123,6 +122,8 @@ class CurrencyController extends BaseController } /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @return $this|\Illuminate\Http\RedirectResponse */ public function store() @@ -174,10 +175,11 @@ class CurrencyController extends BaseController 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' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('currency.edit', $currency->id)->withInput(); } diff --git a/app/controllers/GoogleChartController.php b/app/controllers/GoogleChartController.php index f413c9c5a3..efafc28d6b 100644 --- a/app/controllers/GoogleChartController.php +++ b/app/controllers/GoogleChartController.php @@ -6,10 +6,6 @@ use Grumpydictator\Gchart\GChart as GChart; /** * Class GoogleChartController * @SuppressWarnings("CamelCase") // I'm fine with this. - * @SuppressWarnings("TooManyMethods") // I'm also fine with this. - * @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok. - * @SuppressWarnings("MethodLength") // There is one with 45 lines and im gonna move it. - * @SuppressWarnings("CouplingBetweenObjects") // There's only so much I can remove. */ class GoogleChartController extends BaseController { @@ -46,6 +42,7 @@ class GoogleChartController extends BaseController { $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; @@ -65,7 +62,7 @@ class GoogleChartController extends BaseController $current = clone $start; while ($end >= $current) { - $this->_chart->addRow(clone $current, Steam::balance($account, $current)); + $this->_chart->addRow(clone $current, Steam::balance($account, $current), false); $current->addDay(); } @@ -76,7 +73,7 @@ class GoogleChartController extends BaseController } /** - * This method renders the b + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. */ public function allAccountsBalanceChart() { @@ -88,19 +85,25 @@ class GoogleChartController extends BaseController /** @var \FireflyIII\Database\Account\Account $acct */ $acct = App::make('FireflyIII\Database\Account\Account'); - $accounts = count($pref->data) > 0 ? $acct->getByIds($pref->data) : $acct->getAssetAccounts(); + $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]; + $row = [clone $current]; + $certain = $current < $today; foreach ($accounts as $account) { + $row[] = Steam::balance($account, $current); + $row[] = $certain; } $this->_chart->addRowArray($row); $current->addDay(); @@ -112,6 +115,49 @@ class GoogleChartController extends BaseController } + /** + * @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 */ @@ -121,8 +167,6 @@ class GoogleChartController extends BaseController $this->_chart->addColumn('Budgeted', 'number'); $this->_chart->addColumn('Spent', 'number'); - Log::debug('Now in allBudgetsHomeChart()'); - /** @var \FireflyIII\Database\Budget\Budget $bdt */ $bdt = App::make('FireflyIII\Database\Budget\Budget'); $budgets = $bdt->get(); @@ -130,18 +174,13 @@ class GoogleChartController extends BaseController /** @var Budget $budget */ foreach ($budgets as $budget) { - Log::debug('Now working budget #' . $budget->id . ', ' . $budget->name); - /** @var \LimitRepetition $repetition */ $repetition = $bdt->repetitionOnStartingOnDate($budget, $this->_start); - if (is_null($repetition)) { - \Log::debug('Budget #' . $budget->id . ' has no repetition on ' . $this->_start->format('Y-m-d')); - // use the session start and end for our search query + 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 { - \Log::debug('Budget #' . $budget->id . ' has a repetition on ' . $this->_start->format('Y-m-d') . '!'); // use the limit's start and end for our search query $searchStart = $repetition->startdate; $searchEnd = $repetition->enddate; @@ -149,7 +188,6 @@ class GoogleChartController extends BaseController } $expenses = floatval($budget->transactionjournals()->before($searchEnd)->after($searchStart)->lessThan(0)->sum('amount')) * -1; - \Log::debug('Expenses in budget ' . $budget->name . ' before ' . $searchEnd->format('Y-m-d') . ' and after ' . $searchStart . ' are: ' . $expenses); if ($expenses > 0) { $this->_chart->addRow($budget->name, $limit, $expenses); } @@ -289,47 +327,56 @@ class GoogleChartController extends BaseController /** * - * @param Budget $budget - * @param $year + * @param Budget $budget * * @return \Illuminate\Http\JsonResponse */ - public function budgetsAndSpending(Budget $budget, $year) + public function budgetsAndSpending(Budget $budget, $year = 0) { - 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'); $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(); + } + - $start = new Carbon('01-01-' . $year); - $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.'!'); + \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); + \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()); diff --git a/app/controllers/HelpController.php b/app/controllers/HelpController.php index 813b8faf5c..dbb9f7a2aa 100644 --- a/app/controllers/HelpController.php +++ b/app/controllers/HelpController.php @@ -1,9 +1,10 @@ There is no help for this route!

'; - $helpTitle = 'Help'; + $content = [ + 'text' => '

There is no help for this route!

', + 'title' => 'Help', + ]; + if (!Route::has($route)) { \Log::error('No such route: ' . $route); - return Response::json(['title' => $helpTitle, 'text' => $helpText]); - } - if (Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text')) { - $helpText = Cache::get('help.' . $route . '.text'); - $helpTitle = Cache::get('help.' . $route . '.title'); - - return Response::json(['title' => $helpTitle, 'text' => $helpText]); + return Response::json($content); } - $uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md'; - \Log::debug('URL is: ' . $uri); + if ($this->_inCache($route)) { + $content = [ + 'text' => Cache::get('help.' . $route . '.text'), + 'title' => Cache::get('help.' . $route . '.title'), + ]; + + return Response::json($content); + } + $content = $this->_getFromGithub($route); + + + Cache::put('help.' . $route . '.text', $content['text'], 10080); // a week. + Cache::put('help.' . $route . '.title', $content['title'], 10080); + + return Response::json($content); + + } + + /** + * @param $route + * + * @return bool + */ + protected function _inCache($route) + { + return Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text'); + } + + /** + * @param $route + * + * @return array + */ + protected function _getFromGithub($route) + { + $uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md'; + $content = [ + 'text' => '

There is no help for this route!

', + 'title' => $route, + ]; try { - $helpText = file_get_contents($uri); + $content['text'] = file_get_contents($uri); } catch (ErrorException $e) { \Log::error(trim($e->getMessage())); } - \Log::debug('Found help for ' . $route); - \Log::debug('Help text length for route ' . $route . ' is ' . strlen($helpText)); - \Log::debug('Help text IS: "' . $helpText . '".'); - if (strlen(trim($helpText)) == 0) { - $helpText = '

There is no help for this route.

'; + if (strlen(trim($content['text'])) == 0) { + $content['text'] = '

There is no help for this route.

'; } + $content['text'] = \Michelf\Markdown::defaultTransform($content['text']); - $helpText = \Michelf\Markdown::defaultTransform($helpText); - $helpTitle = $route; + return $content; - Cache::put('help.' . $route . '.text', $helpText, 10080); // a week. - Cache::put('help.' . $route . '.title', $helpTitle, 10080); - - return Response::json(['title' => $helpTitle, 'text' => $helpText]); } -} +} + diff --git a/app/controllers/HomeController.php b/app/controllers/HomeController.php index 33bd974e5e..e97bf24bdc 100644 --- a/app/controllers/HomeController.php +++ b/app/controllers/HomeController.php @@ -33,7 +33,7 @@ class HomeController extends BaseController /** @var \FireflyIII\Shared\Preferences\PreferencesInterface $preferences */ $preferences = App::make('FireflyIII\Shared\Preferences\PreferencesInterface'); - $count = $acct->countAssetAccounts(); + $count = $acct->countAccountsByType(['Default account', 'Asset account']); $start = Session::get('start', Carbon::now()->startOfMonth()); $end = Session::get('end', Carbon::now()->endOfMonth()); @@ -42,7 +42,7 @@ class HomeController extends BaseController // get the preference for the home accounts to show: $frontPage = $preferences->get('frontPageAccounts', []); if ($frontPage->data == []) { - $accounts = $acct->getAssetAccounts(); + $accounts = $acct->getAccountsByType(['Default account', 'Asset account']); } else { $accounts = $acct->getByIds($frontPage->data); } @@ -77,8 +77,11 @@ class HomeController extends BaseController $preferences->set('viewRange', $range); Session::forget('range'); } - - return Redirect::intended('/'); + if (isset($_SERVER['HTTP_REFERER']) && (!strpos($_SERVER['HTTP_REFERER'], Config::get('app.url')) === false)) { + return Redirect::back(); + } else { + return Redirect::intended(); + } } /** @@ -88,7 +91,14 @@ class HomeController extends BaseController { Navigation::next(); - return Redirect::intended('/'); + if (isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], Config::get('app.url')) === 0) { + Log::debug('Redirect back'); + return Redirect::back(); + } else { + Log::debug('Redirect intended'); + return Redirect::intended(); + } + } /** @@ -98,6 +108,12 @@ class HomeController extends BaseController { Navigation::prev(); - return Redirect::intended('/'); + if (isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], Config::get('app.url')) === 0) { + Log::debug('Redirect back'); + return Redirect::back(); + } else { + Log::debug('Redirect intended'); + return Redirect::intended(); + } } } diff --git a/app/controllers/JsonController.php b/app/controllers/JsonController.php index fedc5768d2..a0e6f08262 100644 --- a/app/controllers/JsonController.php +++ b/app/controllers/JsonController.php @@ -36,7 +36,7 @@ class JsonController extends BaseController { /** @var \FireflyIII\Database\Account\Account $accounts */ $accounts = App::make('FireflyIII\Database\Account\Account'); - $list = $accounts->getExpenseAccounts(); + $list = $accounts->getAccountsByType(['Expense account', 'Beneficiary account']); $return = []; foreach ($list as $entry) { $return[] = $entry->name; @@ -53,7 +53,7 @@ class JsonController extends BaseController { /** @var \FireflyIII\Database\Account\Account $accounts */ $accounts = App::make('FireflyIII\Database\Account\Account'); - $list = $accounts->getRevenueAccounts(); + $list = $accounts->getAccountsByType(['Revenue account']); $return = []; foreach ($list as $entry) { $return[] = $entry->name; diff --git a/app/controllers/PiggybankController.php b/app/controllers/PiggybankController.php index 69222f22fa..673a2c31f0 100644 --- a/app/controllers/PiggybankController.php +++ b/app/controllers/PiggybankController.php @@ -8,9 +8,6 @@ use Illuminate\Support\Collection; /** * * @SuppressWarnings("CamelCase") // I'm fine with this. - * @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok. - * @SuppressWarnings("TooManyMethods") // I'm also fine with this. - * @SuppressWarnings("CouplingBetweenObjects") // There's only so much I can remove. * * * Class PiggyBankController @@ -62,7 +59,7 @@ class PiggyBankController extends BaseController $acct = App::make('FireflyIII\Database\Account\Account'); $periods = Config::get('firefly.piggy_bank_periods'); - $accounts = FFForm::makeSelectList($acct->getAssetAccounts()); + $accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account'])); $subTitle = 'Create new piggy bank'; $subTitleIcon = 'fa-plus'; @@ -96,6 +93,8 @@ class PiggyBankController extends BaseController } /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param PiggyBank $piggyBank * * @return $this @@ -107,7 +106,7 @@ class PiggyBankController extends BaseController $acct = App::make('FireflyIII\Database\Account\Account'); $periods = Config::get('firefly.piggy_bank_periods'); - $accounts = FFForm::makeSelectList($acct->getAssetAccounts()); + $accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account'])); $subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"'; $subTitleIcon = 'fa-pencil'; @@ -291,11 +290,12 @@ class PiggyBankController extends BaseController 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' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('piggy_banks.create')->withInput(); } @@ -335,10 +335,11 @@ class PiggyBankController extends BaseController 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 to update screen: - if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('piggy_banks.edit', $piggyBank->id)->withInput(); } diff --git a/app/controllers/PreferencesController.php b/app/controllers/PreferencesController.php index b1a5ca0fc7..d0d62d797d 100644 --- a/app/controllers/PreferencesController.php +++ b/app/controllers/PreferencesController.php @@ -3,7 +3,6 @@ /** * Class PreferencesController * - * @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok. * */ class PreferencesController extends BaseController @@ -29,7 +28,7 @@ class PreferencesController extends BaseController /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ $preferences = App::make('FireflyIII\Shared\Preferences\Preferences'); - $accounts = $acct->getAssetAccounts(); + $accounts = $acct->getAccountsByType(['Default account', 'Asset account']); $viewRange = $preferences->get('viewRange', '1M'); $viewRangeValue = $viewRange->data; $frontPage = $preferences->get('frontPageAccounts', []); diff --git a/app/controllers/ProfileController.php b/app/controllers/ProfileController.php index e9b397833c..8ac759f571 100644 --- a/app/controllers/ProfileController.php +++ b/app/controllers/ProfileController.php @@ -1,8 +1,7 @@ _validatePassword(Input::get('old'), Input::get('new1'), Input::get('new2')); + if (!($result === true)) { + Session::flash('error', $result); return View::make('profile.change-password'); } @@ -66,4 +55,31 @@ class ProfileController extends BaseController return Redirect::route('profile'); } + /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * + * @param string $old + * @param string $new1 + * @param string $new2 + * + * @return string|bool + */ + protected function _validatePassword($old, $new1, $new2) + { + if (strlen($new1) == 0 || strlen($new2) == 0) { + return 'Do fill in a password!'; + + } + if ($new1 == $old) { + return 'The idea is to change your password.'; + } + + if ($new1 !== $new2) { + return 'New passwords do not match!'; + } + + return true; + + } + } diff --git a/app/controllers/RelatedController.php b/app/controllers/RelatedController.php index 747dad5e3f..fb77ee320c 100644 --- a/app/controllers/RelatedController.php +++ b/app/controllers/RelatedController.php @@ -3,6 +3,8 @@ use FireflyIII\Helper\Related\RelatedInterface; use Illuminate\Support\Collection; /** + * @SuppressWarnings("CamelCase") // I'm fine with this. + * * Class RelatedController */ class RelatedController extends BaseController @@ -10,6 +12,9 @@ class RelatedController extends BaseController protected $_repository; + /** + * @param RelatedInterface $repository + */ public function __construct(RelatedInterface $repository) { $this->_repository = $repository; @@ -17,6 +22,8 @@ class RelatedController extends BaseController } /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param TransactionJournal $journal * * @return \Illuminate\Http\JsonResponse @@ -91,6 +98,8 @@ class RelatedController extends BaseController } /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param TransactionJournal $parentJournal * @param TransactionJournal $childJournal * diff --git a/app/controllers/RepeatedExpenseController.php b/app/controllers/RepeatedExpenseController.php index 652e255578..73494b0377 100644 --- a/app/controllers/RepeatedExpenseController.php +++ b/app/controllers/RepeatedExpenseController.php @@ -6,8 +6,6 @@ use FireflyIII\Exception\FireflyException; /** * @SuppressWarnings("CamelCase") // I'm fine with this. - * @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok. - * @SuppressWarnings("CouplingBetweenObjects") // There's only so much I can remove. * * Class RepeatedExpenseController */ @@ -34,7 +32,7 @@ class RepeatedExpenseController extends BaseController /** @var \FireflyIII\Database\Account\Account $acct */ $acct = App::make('FireflyIII\Database\Account\Account'); $periods = Config::get('firefly.piggy_bank_periods'); - $accounts = FFForm::makeSelectList($acct->getAssetAccounts()); + $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' @@ -79,7 +77,7 @@ class RepeatedExpenseController extends BaseController $acct = App::make('FireflyIII\Database\Account\Account'); $periods = Config::get('firefly.piggy_bank_periods'); - $accounts = FFForm::makeSelectList($acct->getAssetAccounts()); + $accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account'])); $subTitle = 'Edit repeated expense "' . e($repeatedExpense->name) . '"'; $subTitleIcon = 'fa-pencil'; @@ -137,7 +135,7 @@ class RepeatedExpenseController extends BaseController } /** - * + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. */ public function store() { @@ -152,7 +150,6 @@ class RepeatedExpenseController extends BaseController $data['remind_me'] = isset($data['remind_me']) ? 1 : 0; $data['order'] = 0; - // always validate: $messages = $this->_repository->validate($data); Session::flash('warnings', $messages['warnings']); @@ -160,11 +157,12 @@ class RepeatedExpenseController extends BaseController 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' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('repeated.create')->withInput(); } @@ -180,6 +178,8 @@ class RepeatedExpenseController extends BaseController } /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param PiggyBank $repeatedExpense * * @return $this @@ -196,7 +196,6 @@ class RepeatedExpenseController extends BaseController $data['remind_me'] = isset($data['remind_me']) ? 1 : 0; $data['user_id'] = Auth::user()->id; - // always validate: $messages = $this->_repository->validate($data); Session::flash('warnings', $messages['warnings']); @@ -204,10 +203,11 @@ class RepeatedExpenseController extends BaseController 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' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput(); } diff --git a/app/controllers/ReportController.php b/app/controllers/ReportController.php index 29be01240f..ed4821c449 100644 --- a/app/controllers/ReportController.php +++ b/app/controllers/ReportController.php @@ -48,13 +48,15 @@ class ReportController extends BaseController } catch (Exception $e) { return View::make('error')->with('message', 'Invalid date'); } - $date = new Carbon($year . '-' . $month . '-01'); - $dayEarly = clone $date; - $dayEarly = $dayEarly->subDay(); - $accounts = $this->_repository->getAccountListBudgetOverview($date); - $budgets = $this->_repository->getBudgetsForMonth($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('date', 'accounts', 'budgets', 'dayEarly')); + return View::make('reports.budget', compact('subTitle', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly')); } @@ -126,7 +128,8 @@ class ReportController extends BaseController $groupedExpenses = $this->_repository->expensesGroupedByAccount($date, $end, 15); return View::make( - 'reports.year', compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon') + 'reports.year', + compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon') ); } diff --git a/app/controllers/TransactionController.php b/app/controllers/TransactionController.php index a7c9b12e71..f4384d6d12 100644 --- a/app/controllers/TransactionController.php +++ b/app/controllers/TransactionController.php @@ -9,10 +9,6 @@ use Illuminate\Support\Collection; /** * * @SuppressWarnings("CamelCase") // I'm fine with this. - * @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok. - * @SuppressWarnings("CouplingBetweenObjects") // There's only so much I can remove. - * @SuppressWarnings("TooManyMethods") // I'm also fine with this. - * @SuppressWarnings("ExcessiveClassComplexity") * * Class TransactionController * @@ -166,6 +162,8 @@ class TransactionController extends BaseController } /** + * @SuppressWarnings("CyclomaticComplexity") // It's 7. More than 5 but alright. + * * @param $what * * @return $this @@ -198,7 +196,6 @@ class TransactionController extends BaseController } - /** * @param TransactionJournal $journal * @@ -235,6 +232,8 @@ class TransactionController extends BaseController } /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param $what * * @return $this|\Illuminate\Http\RedirectResponse @@ -243,35 +242,31 @@ class TransactionController extends BaseController public function store($what) { $data = Input::except('_token'); + $transactionType = $this->_repository->getJournalType($what); - $transactionCurrency = $this->_repository->getJournalCurrency('EUR'); + $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; - $data['currency'] = 'EUR'; - - // always validate: - $messages = $this->_repository->validate($data); + $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 to create screen: - if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { return Redirect::route('transactions.create', $data['what'])->withInput(); } - // store + 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. - /* - * Also trigger on both transactions. - */ + /** @var Transaction $transaction */ foreach ($journal->transactions as $transaction) { Event::fire('transaction.store', [$transaction]); @@ -295,10 +290,9 @@ class TransactionController extends BaseController public function update(TransactionJournal $journal) { $data = Input::except('_token'); - $data['currency'] = 'EUR'; $data['what'] = strtolower($journal->transactionType->type); $data['transaction_type_id'] = $journal->transaction_type_id; - $data['transaction_currency_id'] = $journal->transaction_currency_id; + $data['transaction_currency_id'] = intval($data['amount_currency_id']); $data['completed'] = 1; $messages = $this->_repository->validate($data); @@ -307,8 +301,10 @@ class TransactionController extends BaseController 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' || $messages['errors']->count() > 0) { + if ($data['post_submit_action'] == 'validate_only') { return Redirect::route('transactions.edit', $journal->id)->withInput(); } $this->_repository->update($journal, $data); diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php index 82309e2460..702ffe991b 100644 --- a/app/controllers/UserController.php +++ b/app/controllers/UserController.php @@ -77,7 +77,12 @@ class UserController extends BaseController $user = $repository->register(Input::all()); if ($user) { - $email->sendVerificationMail($user); + $result = $email->sendVerificationMail($user); + if ($result === false && Config::get('mail.pretend') === false) { + $user->delete(); + + return View::make('error')->with('message', 'The email message could not be send. See the log files.'); + } return View::make('user.verification-pending'); } @@ -121,6 +126,11 @@ class UserController extends BaseController */ 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'); } diff --git a/app/database/migrations/2014_06_27_163032_create_users_table.php b/app/database/migrations/2014_06_27_163032_create_users_table.php index 3c72c3ab6c..cd554148db 100644 --- a/app/database/migrations/2014_06_27_163032_create_users_table.php +++ b/app/database/migrations/2014_06_27_163032_create_users_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateUsersTable */ class CreateUsersTable extends Migration diff --git a/app/database/migrations/2014_06_27_163145_create_account_types_table.php b/app/database/migrations/2014_06_27_163145_create_account_types_table.php index 7d90098389..783ec4d15d 100644 --- a/app/database/migrations/2014_06_27_163145_create_account_types_table.php +++ b/app/database/migrations/2014_06_27_163145_create_account_types_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateAccountTypesTable * */ diff --git a/app/database/migrations/2014_06_27_163259_create_accounts_table.php b/app/database/migrations/2014_06_27_163259_create_accounts_table.php index 71d3cd8a37..3fb5541655 100644 --- a/app/database/migrations/2014_06_27_163259_create_accounts_table.php +++ b/app/database/migrations/2014_06_27_163259_create_accounts_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateAccountsTable * */ diff --git a/app/database/migrations/2014_06_27_163817_create_components_table.php b/app/database/migrations/2014_06_27_163817_create_components_table.php index 2c4852f02c..465b1ecaff 100644 --- a/app/database/migrations/2014_06_27_163817_create_components_table.php +++ b/app/database/migrations/2014_06_27_163817_create_components_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateComponentsTable * */ diff --git a/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php b/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php index 5ac466d43e..67d527a66d 100644 --- a/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php +++ b/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreatePiggybanksTable * */ diff --git a/app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php b/app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php index a6444da219..809a837bc9 100644 --- a/app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php +++ b/app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateTransactionCurrenciesTable * */ diff --git a/app/database/migrations/2014_06_27_164512_create_transaction_types_table.php b/app/database/migrations/2014_06_27_164512_create_transaction_types_table.php index 77a3d9924c..746f037a84 100644 --- a/app/database/migrations/2014_06_27_164512_create_transaction_types_table.php +++ b/app/database/migrations/2014_06_27_164512_create_transaction_types_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateTransactionTypesTable * */ diff --git a/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php b/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php index c3e9aea81b..724059c859 100644 --- a/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php +++ b/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateRecurringTransactionsTable * */ diff --git a/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php b/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php index b44af8769c..44ede35eb0 100644 --- a/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php +++ b/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateTransactionJournalsTable * */ diff --git a/app/database/migrations/2014_06_27_164836_create_transactions_table.php b/app/database/migrations/2014_06_27_164836_create_transactions_table.php index 74765c1910..66b2772534 100644 --- a/app/database/migrations/2014_06_27_164836_create_transactions_table.php +++ b/app/database/migrations/2014_06_27_164836_create_transactions_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateTransactionsTable * */ diff --git a/app/database/migrations/2014_06_27_165344_create_component_transaction_table.php b/app/database/migrations/2014_06_27_165344_create_component_transaction_table.php index d5f73f8444..6eee751926 100644 --- a/app/database/migrations/2014_06_27_165344_create_component_transaction_table.php +++ b/app/database/migrations/2014_06_27_165344_create_component_transaction_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateComponentTransactionTable * */ diff --git a/app/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php b/app/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php index 2069e961a9..e6de376c42 100644 --- a/app/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php +++ b/app/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateComponentTransactionJournalTable * */ diff --git a/app/database/migrations/2014_07_06_123842_create_preferences_table.php b/app/database/migrations/2014_07_06_123842_create_preferences_table.php index 61f12090a2..7cd7069c8e 100644 --- a/app/database/migrations/2014_07_06_123842_create_preferences_table.php +++ b/app/database/migrations/2014_07_06_123842_create_preferences_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreatePreferencesTable * */ diff --git a/app/database/migrations/2014_07_09_204843_create_session_table.php b/app/database/migrations/2014_07_09_204843_create_session_table.php index e09703979a..240f66ba88 100644 --- a/app/database/migrations/2014_07_09_204843_create_session_table.php +++ b/app/database/migrations/2014_07_09_204843_create_session_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateSessionTable * */ diff --git a/app/database/migrations/2014_07_17_183717_create_limits_table.php b/app/database/migrations/2014_07_17_183717_create_limits_table.php index fc39882c7b..f6c507216a 100644 --- a/app/database/migrations/2014_07_17_183717_create_limits_table.php +++ b/app/database/migrations/2014_07_17_183717_create_limits_table.php @@ -4,6 +4,9 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName)\ + * + * * Class CreateLimitsTable * */ diff --git a/app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php b/app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php index 1240cf3657..46edc87ac9 100644 --- a/app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php +++ b/app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateLimitRepeatTable * */ diff --git a/app/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php b/app/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php index 512387e29b..6105817f64 100644 --- a/app/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php +++ b/app/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateComponentRecurringTransactionTable * */ diff --git a/app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php b/app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php index d285d99487..341d36a9d8 100644 --- a/app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php +++ b/app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreatePiggyInstance * */ diff --git a/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php b/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php index 480f09d658..8eebf01388 100644 --- a/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php +++ b/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreatePiggybankEventsTable * */ diff --git a/app/database/migrations/2014_08_23_113221_create_reminders_table.php b/app/database/migrations/2014_08_23_113221_create_reminders_table.php index 8d231aac04..1aaa49fb0a 100644 --- a/app/database/migrations/2014_08_23_113221_create_reminders_table.php +++ b/app/database/migrations/2014_08_23_113221_create_reminders_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateRemindersTable * */ diff --git a/app/database/migrations/2014_11_10_172053_create_account_meta_table.php b/app/database/migrations/2014_11_10_172053_create_account_meta_table.php index 0cbc84ae4d..1febb05a1b 100644 --- a/app/database/migrations/2014_11_10_172053_create_account_meta_table.php +++ b/app/database/migrations/2014_11_10_172053_create_account_meta_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateAccountMetaTable * */ diff --git a/app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php b/app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php index acba3c84ce..c3d2e3af49 100644 --- a/app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php +++ b/app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php @@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * * Class CreateTransactionGroupsTable * */ diff --git a/app/database/migrations/2014_12_13_190730_changes_for_v321.php b/app/database/migrations/2014_12_13_190730_changes_for_v321.php index 4a9a743178..9d5242189d 100644 --- a/app/database/migrations/2014_12_13_190730_changes_for_v321.php +++ b/app/database/migrations/2014_12_13_190730_changes_for_v321.php @@ -5,6 +5,9 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; /** + * @SuppressWarnings(PHPMD.ShortMethodName) // method names are mandated by laravel. + * @SuppressWarnings("TooManyMethods") // I'm fine with this + * * Down: * 1. Create new Components based on Budgets. * 2. Create new Components based on Categories diff --git a/app/database/migrations/2014_12_24_191544_changes_for_v322.php b/app/database/migrations/2014_12_24_191544_changes_for_v322.php index 0714ea25fe..5b5e7abff2 100644 --- a/app/database/migrations/2014_12_24_191544_changes_for_v322.php +++ b/app/database/migrations/2014_12_24_191544_changes_for_v322.php @@ -4,6 +4,10 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; /** + * @SuppressWarnings(PHPMD.ShortMethodName) + * @SuppressWarnings("MethodLength") // I don't mind this in case of migrations. + + * * Class ChangesForV322 */ class ChangesForV322 extends Migration diff --git a/app/database/migrations/2015_01_18_082406_changes_for_v325.php b/app/database/migrations/2015_01_18_082406_changes_for_v325.php new file mode 100644 index 0000000000..5015a35e21 --- /dev/null +++ b/app/database/migrations/2015_01_18_082406_changes_for_v325.php @@ -0,0 +1,71 @@ +dropIndex('unique_ci_combo'); + $table->dropUnique('unique_ci_combi'); + + } + ); + } catch (QueryException $e) { + // don't care. + } catch (PDOException $e) { + // don't care. + } catch (\Exception $e) { + // don't care either. + } + + // allow journal descriptions to be encrypted. + Schema::table( + 'transaction_journals', function (Blueprint $table) { + $table->boolean('encrypted')->default(0); + + } + ); + try { + DB::update('ALTER TABLE `transaction_journals` MODIFY `description` VARCHAR(1024)'); + } catch (QueryException $e) { + // don't care. + } catch (PDOException $e) { + // don't care. + } catch (\Exception $e) { + // don't care either. + } + + } + +} diff --git a/app/database/seeds/AccountTypeSeeder.php b/app/database/seeds/AccountTypeSeeder.php index f0fd27b341..93523755ac 100644 --- a/app/database/seeds/AccountTypeSeeder.php +++ b/app/database/seeds/AccountTypeSeeder.php @@ -10,31 +10,14 @@ class AccountTypeSeeder extends Seeder { DB::table('account_types')->delete(); - AccountType::create( - ['type' => 'Default account', 'editable' => true] - ); - AccountType::create( - ['type' => 'Cash account', 'editable' => false] - ); - AccountType::create( - ['type' => 'Asset account', 'editable' => true] - ); - AccountType::create( - ['type' => 'Expense account', 'editable' => true] - ); - AccountType::create( - ['type' => 'Revenue account', 'editable' => true] - ); - AccountType::create( - ['type' => 'Initial balance account', 'editable' => false] - ); - AccountType::create( - ['type' => 'Beneficiary account', 'editable' => true] - ); - - AccountType::create( - ['type' => 'Import account', 'editable' => false] - ); + AccountType::create(['type' => 'Default account', 'editable' => true]); + AccountType::create(['type' => 'Cash account', 'editable' => false]); + AccountType::create(['type' => 'Asset account', 'editable' => true]); + AccountType::create(['type' => 'Expense account', 'editable' => true]); + AccountType::create(['type' => 'Revenue account', 'editable' => true]); + AccountType::create(['type' => 'Initial balance account', 'editable' => false]); + AccountType::create(['type' => 'Beneficiary account', 'editable' => true]); + AccountType::create(['type' => 'Import account', 'editable' => false]); } diff --git a/app/database/seeds/DatabaseSeeder.php b/app/database/seeds/DatabaseSeeder.php index 29319ca38c..f357dfd6ec 100644 --- a/app/database/seeds/DatabaseSeeder.php +++ b/app/database/seeds/DatabaseSeeder.php @@ -18,8 +18,10 @@ class DatabaseSeeder extends Seeder $this->call('AccountTypeSeeder'); $this->call('TransactionCurrencySeeder'); $this->call('TransactionTypeSeeder'); - $this->call('DefaultUserSeeder'); - $this->call('TestContentSeeder'); + + if (App::environment() == 'testing') { + $this->call('TestDataSeeder'); + } } } diff --git a/app/database/seeds/DefaultUserSeeder.php b/app/database/seeds/DefaultUserSeeder.php deleted file mode 100644 index 1b40e29097..0000000000 --- a/app/database/seeds/DefaultUserSeeder.php +++ /dev/null @@ -1,22 +0,0 @@ -delete(); - if (App::environment() == 'testing' || App::environment() == 'homestead') { - - User::create(['email' => 'thegrumpydictator@gmail.com', 'password' => 'james', 'reset' => null, 'remember_token' => null]); - User::create(['email' => 'acceptance@example.com', 'password' => 'acceptance', 'reset' => null, 'remember_token' => null]); - User::create(['email' => 'functional@example.com', 'password' => 'functional', 'reset' => null, 'remember_token' => null]); - User::create(['email' => 'reset@example.com', 'password' => 'functional', 'reset' => 'okokokokokokokokokokokokokokokok', 'remember_token' => null]); - - } - - } - -} diff --git a/app/database/seeds/TestContentSeeder.php b/app/database/seeds/TestDataSeeder.php similarity index 70% rename from app/database/seeds/TestContentSeeder.php rename to app/database/seeds/TestDataSeeder.php index e2cdebf7d7..6ef7c64842 100644 --- a/app/database/seeds/TestContentSeeder.php +++ b/app/database/seeds/TestDataSeeder.php @@ -1,14 +1,15 @@ first(); - - // create initial accounts and various other stuff: - $this->createAssetAccounts($user); - $this->createBudgets($user); - $this->createCategories($user); - $this->createPiggyBanks($user); - $this->createReminders($user); - $this->createRecurringTransactions($user); - $this->createBills($user); - $this->createExpenseAccounts($user); - $this->createRevenueAccounts($user); - - // get some objects from the database: - $checking = Account::whereName('Checking account')->orderBy('id', 'DESC')->first(); - $savings = Account::whereName('Savings account')->orderBy('id', 'DESC')->first(); - $landLord = Account::whereName('Land lord')->orderBy('id', 'DESC')->first(); - $utilities = Account::whereName('Utilities company')->orderBy('id', 'DESC')->first(); - $television = Account::whereName('TV company')->orderBy('id', 'DESC')->first(); - $phone = Account::whereName('Phone agency')->orderBy('id', 'DESC')->first(); - $employer = Account::whereName('Employer')->orderBy('id', 'DESC')->first(); + User::create(['email' => 'reset@example.com', 'password' => 'functional', 'reset' => 'okokokokokokokokokokokokokokokok', 'remember_token' => null]); + User::create(['email' => 'functional@example.com', 'password' => 'functional', 'reset' => null, 'remember_token' => null]); - $bills = Budget::whereName('Bills')->orderBy('id', 'DESC')->first(); - $groceries = Budget::whereName('Groceries')->orderBy('id', 'DESC')->first(); + $user = User::create(['email' => 'thegrumpydictator@gmail.com', 'password' => 'james', 'reset' => null, 'remember_token' => null]); + Log::debug('Created users.'); + // create initial accounts and various other stuff: + $this->createAssetAccounts($user); + Log::debug('Created asset accounts.'); + $this->createBudgets($user); + Log::debug('Created budgets.'); + $this->createCategories($user); + Log::debug('Created categories.'); + $this->createPiggyBanks($user); + Log::debug('Created piggy banks.'); + $this->createReminders($user); + Log::debug('Created reminders.'); + $this->createRecurringTransactions($user); + Log::debug('Created recurring transactions.'); + $this->createBills($user); + Log::debug('Created bills.'); + $this->createExpenseAccounts($user); + Log::debug('Created expense accounts.'); + $this->createRevenueAccounts($user); + Log::debug('Created revenue accounts.'); - $house = Category::whereName('House')->orderBy('id', 'DESC')->first(); + // get some objects from the database: + $checking = Account::whereName('Checking account')->orderBy('id', 'DESC')->first(); + Log::debug('Found checking: ' . json_encode($checking)); + $savings = Account::whereName('Savings account')->orderBy('id', 'DESC')->first(); + Log::debug('Found savings: ' . json_encode($savings)); + $landLord = Account::whereName('Land lord')->orderBy('id', 'DESC')->first(); + Log::debug('Found landlord: ' . json_encode($landLord)); + $utilities = Account::whereName('Utilities company')->orderBy('id', 'DESC')->first(); + Log::debug('Found utilities: ' . json_encode($utilities)); + $television = Account::whereName('TV company')->orderBy('id', 'DESC')->first(); + Log::debug('Found tv company: ' . json_encode($television)); + $phone = Account::whereName('Phone agency')->orderBy('id', 'DESC')->first(); + Log::debug('Found phone company: ' . json_encode($phone)); + $employer = Account::whereName('Employer')->orderBy('id', 'DESC')->first(); + Log::debug('Found employer: ' . json_encode($employer)); - $withdrawal = TransactionType::whereType('Withdrawal')->first(); - $deposit = TransactionType::whereType('Deposit')->first(); - $transfer = TransactionType::whereType('Transfer')->first(); + $bills = Budget::whereName('Bills')->orderBy('id', 'DESC')->first(); + Log::debug('Found bills budget: ' . json_encode($bills)); + $groceries = Budget::whereName('Groceries')->orderBy('id', 'DESC')->first(); + Log::debug('Found groceries budget: ' . json_encode($groceries)); - $euro = TransactionCurrency::whereCode('EUR')->first(); - - $rentBill = Bill::where('name', 'Rent')->first(); + $house = Category::whereName('House')->orderBy('id', 'DESC')->first(); + Log::debug('Found house category: ' . json_encode($checking)); - $current = clone $this->_yearAgoStartOfMonth; - while ($current <= $this->_startOfMonth) { - $cur = $current->format('Y-m-d'); - $formatted = $current->format('F Y'); + $withdrawal = TransactionType::whereType('Withdrawal')->first(); + Log::debug('Found withdrawal: ' . json_encode($withdrawal)); + $deposit = TransactionType::whereType('Deposit')->first(); + Log::debug('Found deposit: ' . json_encode($deposit)); + $transfer = TransactionType::whereType('Transfer')->first(); + Log::debug('Found transfer: ' . json_encode($transfer)); - // create expenses for rent, utilities, TV, phone on the 1st of the month. - $this->createTransaction($checking, $landLord, 800, $withdrawal, 'Rent for ' . $formatted, $cur, $euro, $bills, $house, $rentBill); - $this->createTransaction($checking, $utilities, 150, $withdrawal, 'Utilities for ' . $formatted, $cur, $euro, $bills, $house); - $this->createTransaction($checking, $television, 50, $withdrawal, 'TV for ' . $formatted, $cur, $euro, $bills, $house); - $this->createTransaction($checking, $phone, 50, $withdrawal, 'Phone bill for ' . $formatted, $cur, $euro, $bills, $house); + $euro = TransactionCurrency::whereCode('EUR')->first(); + Log::debug('Found euro: ' . json_encode($euro)); - // two transactions. One without a budget, one without a category. - $this->createTransaction($checking, $phone, 10, $withdrawal, 'Extra charges on phone bill for ' . $formatted, $cur, $euro, null, $house); - $this->createTransaction($checking, $television, 5, $withdrawal, 'Extra charges on TV bill for ' . $formatted, $cur, $euro, $bills, null); - - // income from job: - $this->createTransaction($employer, $checking, rand(3500, 4000), $deposit, 'Salary for ' . $formatted, $cur, $euro); - $this->createTransaction($checking, $savings, 2000, $transfer, 'Salary to savings account in ' . $formatted, $cur, $euro); - - $this->createGroceries($current); - $this->createBigExpense(clone $current); - - echo 'Created test-content for ' . $current->format('F Y') . "\n"; - $current->addMonth(); - } + $rentBill = Bill::where('name', 'Rent')->first(); + Log::debug('Found bill "rent": ' . json_encode($rentBill)); - // piggy bank event - // add money to this piggy bank - // create a piggy bank event to match: - $piggyBank = PiggyBank::whereName('New camera')->orderBy('id', 'DESC')->first(); - $intoPiggy = $this->createTransaction($checking, $savings, 100, $transfer, 'Money for piggy', $this->yaeom, $euro, $groceries, $house); - PiggyBankEvent::create( - [ - 'piggy_bank_id' => $piggyBank->id, - 'transaction_journal_id' => $intoPiggy->id, - 'date' => $this->yaeom, - 'amount' => 100 - ] - ); + $current = clone $this->_yearAgoStartOfMonth; + while ($current <= $this->_startOfMonth) { + $cur = $current->format('Y-m-d'); + $formatted = $current->format('F Y'); + Log::debug('Now at: ' . $cur); + + // create expenses for rent, utilities, TV, phone on the 1st of the month. + $this->createTransaction($checking, $landLord, 800, $withdrawal, 'Rent for ' . $formatted, $cur, $euro, $bills, $house, $rentBill); + Log::debug('Created rent.'); + $this->createTransaction($checking, $utilities, 150, $withdrawal, 'Utilities for ' . $formatted, $cur, $euro, $bills, $house); + Log::debug('Created utilities.'); + $this->createTransaction($checking, $television, 50, $withdrawal, 'TV for ' . $formatted, $cur, $euro, $bills, $house); + Log::debug('Created TV.'); + $this->createTransaction($checking, $phone, 50, $withdrawal, 'Phone bill for ' . $formatted, $cur, $euro, $bills, $house); + Log::debug('Created phone bill.'); + + // two transactions. One without a budget, one without a category. + $this->createTransaction($checking, $phone, 10, $withdrawal, 'Extra charges on phone bill for ' . $formatted, $cur, $euro, null, $house); + Log::debug('Created extra charges no budget.'); + $this->createTransaction($checking, $television, 5, $withdrawal, 'Extra charges on TV bill for ' . $formatted, $cur, $euro, $bills, null); + Log::debug('Created extra charges no category.'); + + // income from job: + $this->createTransaction($employer, $checking, rand(3500, 4000), $deposit, 'Salary for ' . $formatted, $cur, $euro); + Log::debug('Created income.'); + $this->createTransaction($checking, $savings, 2000, $transfer, 'Salary to savings account in ' . $formatted, $cur, $euro); + Log::debug('Created savings.'); + + $this->createGroceries($current); + Log::debug('Created groceries range.'); + $this->createBigExpense(clone $current); + Log::debug('Created big expense.'); + + echo 'Created test-content for ' . $current->format('F Y') . "\n"; + $current->addMonth(); } + + + // piggy bank event + // add money to this piggy bank + // create a piggy bank event to match: + $piggyBank = PiggyBank::whereName('New camera')->orderBy('id', 'DESC')->first(); + $intoPiggy = $this->createTransaction($checking, $savings, 100, $transfer, 'Money for piggy', $this->yaeom, $euro, $groceries, $house); + PiggyBankEvent::create( + [ + 'piggy_bank_id' => $piggyBank->id, + 'transaction_journal_id' => $intoPiggy->id, + 'date' => $this->yaeom, + 'amount' => 100 + ] + ); } /** @@ -181,6 +218,9 @@ class TestContentSeeder extends Seeder } /** + * @SuppressWarnings(PHPMD.ShortVariable) + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * * @param Account $from * @param Account $to * @param $amount @@ -202,15 +242,24 @@ class TestContentSeeder extends Seeder $user = User::whereEmail('thegrumpydictator@gmail.com')->first(); $billID = is_null($bill) ? null : $bill->id; - + Log::debug('String length of encrypted description ("'.$description.'") is: ' . strlen(Crypt::encrypt($description))); /** @var TransactionJournal $journal */ $journal = TransactionJournal::create( [ - 'user_id' => $user->id, 'transaction_type_id' => $type->id, 'transaction_currency_id' => $currency->id, 'bill_id' => $billID, - 'description' => $description, 'completed' => 1, 'date' => $date + 'user_id' => $user->id, + 'transaction_type_id' => $type->id, + 'transaction_currency_id' => $currency->id, + 'bill_id' => $billID, + 'description' => $description, + 'completed' => 1, + 'date' => $date ] ); + //Log::debug('Journal valid: ' . Steam::boolString($journal->isValid())); + //Log::debug('Journal errors: ' . json_encode($journal->getErrors())); + //Log::debug('Journal created: ' . json_encode($journal)); + Transaction::create(['account_id' => $from->id, 'transaction_journal_id' => $journal->id, 'amount' => $amount * -1]); Transaction::create(['account_id' => $to->id, 'transaction_journal_id' => $journal->id, 'amount' => $amount]); @@ -411,16 +460,8 @@ class TestContentSeeder extends Seeder { // bill Bill::create( - [ - 'user_id' => $user->id, 'name' => 'Rent', 'match' => 'rent,landlord', - 'amount_min' => 700, - 'amount_max' => 900, - 'date' => $this->som, - 'active' => 1, - 'automatch' => 1, - 'repeat_freq' => 'monthly', - 'skip' => 0, - ] + ['user_id' => $user->id, 'name' => 'Rent', 'match' => 'rent,landlord', 'amount_min' => 700, 'amount_max' => 900, 'date' => $this->som, + 'active' => 1, 'automatch' => 1, 'repeat_freq' => 'monthly', 'skip' => 0,] ); // bill @@ -429,13 +470,10 @@ class TestContentSeeder extends Seeder 'user_id' => $user->id, 'name' => 'Gas licht', 'match' => 'no,match', - 'amount_min' => 500, - 'amount_max' => 700, + 'amount_min' => 500, 'amount_max' => 700, 'date' => $this->som, - 'active' => 1, - 'automatch' => 1, - 'repeat_freq' => 'monthly', - 'skip' => 0, + 'active' => 1, 'automatch' => 1, + 'repeat_freq' => 'monthly', 'skip' => 0, ] ); @@ -557,5 +595,8 @@ class TestContentSeeder extends Seeder ); $group->transactionjournals()->save($one); $group->transactionjournals()->save($two); + $group->save(); } -} + + +} \ No newline at end of file diff --git a/app/lib/FireflyIII/Database/Account/Account.php b/app/lib/FireflyIII/Database/Account/Account.php index 368aeecac6..7562946ac8 100644 --- a/app/lib/FireflyIII/Database/Account/Account.php +++ b/app/lib/FireflyIII/Database/Account/Account.php @@ -41,47 +41,6 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte return $this->getUser()->accounts()->accountTypeIn($types)->count(); } - /** - * @return int - */ - public function countAssetAccounts() - { - return $this->countAccountsByType(['Default account', 'Asset account']); - } - - /** - * @return int - */ - public function countExpenseAccounts() - { - return $this->countAccountsByType(['Expense account', 'Beneficiary account']); - } - - /** - * Counts the number of total revenue accounts. Useful for DataTables. - * - * @return int - */ - public function countRevenueAccounts() - { - return $this->countAccountsByType(['Revenue account']); - } - - /** - * @param \Account $account - * - * @return \Account|null - */ - public function findInitialBalanceAccount(\Account $account) - { - /** @var \FireflyIII\Database\AccountType\AccountType $acctType */ - $acctType = \App::make('FireflyIII\Database\AccountType\AccountType'); - - $accountType = $acctType->findByWhat('initial'); - - return $this->getUser()->accounts()->where('account_type_id', $accountType->id)->where('name', 'LIKE', $account->name . '%')->first(); - } - /** * @param array $types * @@ -93,7 +52,7 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte * Basic query: */ $query = $this->getUser()->accounts()->accountTypeIn($types)->withMeta()->orderBy('name', 'ASC');; - $set = $query->get(['accounts.*']); + $set = $query->get(['accounts.*', 'account_meta.data as accountRole']); $set->each( function (\Account $account) { @@ -101,63 +60,13 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte * Get last activity date. */ $account->lastActivityDate = $this->getLastActivity($account); + $account->accountRole = \Config::get('firefly.accountRoles.' . json_decode($account->accountRole)); } ); return $set; } - /** - * Get all asset accounts. Optional JSON based parameters. - * - * @param array $metaFilter - * - * @return Collection - */ - public function getAssetAccounts($metaFilter = []) - { - $list = $this->getAccountsByType(['Default account', 'Asset account']); - $list->each( - function (\Account $account) { - - // get accountRole: - - /** @var \AccountMeta $entry */ - $accountRole = $account->accountmeta()->whereName('accountRole')->first(); - if (!$accountRole) { - $accountRole = new \AccountMeta; - $accountRole->account_id = $account->id; - $accountRole->name = 'accountRole'; - $accountRole->data = 'defaultExpense'; - $accountRole->save(); - - } - $account->accountRole = $accountRole->data; - } - ); - - return $list; - - } - - /** - * @return Collection - */ - public function getExpenseAccounts() - { - return $this->getAccountsByType(['Expense account', 'Beneficiary account']); - } - - /** - * Get all revenue accounts. - * - * @return Collection - */ - public function getRevenueAccounts() - { - return $this->getAccountsByType(['Revenue account']); - } - /** * @param \Account $account * @@ -180,51 +89,32 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte { $opposingData = ['name' => $account->name . ' Initial Balance', 'active' => 0, 'what' => 'initial']; $opposingAccount = $this->store($opposingData); - - /* - * Create a journal from opposing to account or vice versa. - */ - $balance = floatval($data['openingbalance']); - $date = new Carbon($data['openingbalancedate']); - /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $tj */ - $tj = \App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); + $balance = floatval($data['openingBalance']); + $date = new Carbon($data['openingBalanceDate']); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $journals */ + $journals = \App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); + $fromAccount = $opposingAccount; + $toAccount = $account; if ($balance < 0) { - // first transaction draws money from the new account to the opposing - $from = $account; - $to = $opposingAccount; - } else { - // first transaction puts money into account - $from = $opposingAccount; - $to = $account; + $fromAccount = $account; + $toAccount = $opposingAccount; } - // data for transaction journal: $balance = $balance < 0 ? $balance * -1 : $balance; - // find the account type: /** @var \FireflyIII\Database\TransactionType\TransactionType $typeRepository */ $typeRepository = \App::make('FireflyIII\Database\TransactionType\TransactionType'); $type = $typeRepository->findByWhat('opening'); + $currency = $journals->getJournalCurrencyById(intval($data['balance_currency_id'])); + //$currency = \Amount::getDefaultCurrency(); - // find the currency. - $currency = \Amount::getDefaultCurrency(); + $opening = ['transaction_type_id' => $type->id, 'transaction_currency_id' => $currency->id, 'amount' => $balance, 'from' => $fromAccount, + 'completed' => 0, 'what' => 'opening', 'to' => $toAccount, 'date' => $date, + 'description' => 'Opening balance for new account ' . $account->name,]; - $opening = [ - 'transaction_type_id' => $type->id, - 'transaction_currency_id' => $currency->id, - 'amount' => $balance, - 'from' => $from, - 'completed' => 0, - 'currency' => 'EUR', - 'what' => 'opening', - 'to' => $to, - 'date' => $date, - 'description' => 'Opening balance for new account ' . $account->name,]; - - - $validation = $tj->validate($opening); + $validation = $journals->validate($opening); if ($validation['errors']->count() == 0) { - $tj->store($opening); + $journals->store($opening); return true; } else { @@ -233,45 +123,68 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte \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) { - - // delete piggy banks - // delete journals: - $journals = \TransactionJournal::whereIn( + $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('id') - ->from('accounts') - ->where( - function (QueryBuilder $q) use ($model) { - $q->where('id', $model->id); - $q->orWhere( - function (QueryBuilder $q) use ($model) { - $q->where('accounts.name', 'LIKE', '%' . $model->name . '%'); - $q->where('accounts.account_type_id', 3); - $q->where('accounts.active', 0); - } - ); - } - )->where('accounts.user_id', $this->getUser()->id); - } - )->get(); + ->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(); - /* - * Get all transactions. - */ $transactions = []; /** @var \TransactionJournal $journal */ foreach ($journals as $journal) { @@ -281,25 +194,26 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte } $journal->delete(); } - // also delete transactions. if (count($transactions) > 0) { \Transaction::whereIn('id', $transactions)->delete(); } - - - /* - * Trigger deletion: - */ \Event::fire('account.destroy', [$model]); - // delete accounts: + // 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) { + function (EloquentBuilder $q) use ($model, $accountType) { $q->where('id', $model->id); $q->orWhere( - function (EloquentBuilder $q) use ($model) { + function (EloquentBuilder $q) use ($model, $accountType) { $q->where('accounts.name', 'LIKE', '%' . $model->name . '%'); - $q->where('accounts.account_type_id', 3); + $q->where('accounts.account_type_id', $accountType->id); $q->where('accounts.active', 0); } ); @@ -318,9 +232,6 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte public function store(array $data) { - /* - * Find account type. - */ /** @var \FireflyIII\Database\AccountType\AccountType $acctType */ $acctType = \App::make('FireflyIII\Database\AccountType\AccountType'); @@ -330,7 +241,6 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte $data['account_type_id'] = $accountType->id; $data['active'] = isset($data['active']) && $data['active'] === '1' ? 1 : 0; - $data = array_except($data, ['_token', 'what']); $account = new \Account($data); if (!$account->isValid()) { @@ -339,7 +249,7 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte \App::abort(500); } $account->save(); - if (isset($data['openingbalance']) && floatval($data['openingbalance']) != 0) { + if (isset($data['openingBalance']) && floatval($data['openingBalance']) != 0) { $this->storeInitialBalance($account, $data); } @@ -379,15 +289,15 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte $model->save(); - if (isset($data['openingbalance']) && isset($data['openingbalancedate']) && strlen($data['openingbalancedate']) > 0) { + if (isset($data['openingBalance']) && isset($data['openingBalanceDate']) && strlen($data['openingBalanceDate']) > 0) { /** @noinspection PhpParamsInspection */ $openingBalance = $this->openingBalanceTransaction($model); if (is_null($openingBalance)) { $this->storeInitialBalance($model, $data); } else { - $openingBalance->date = new Carbon($data['openingbalancedate']); + $openingBalance->date = new Carbon($data['openingBalanceDate']); $openingBalance->save(); - $amount = floatval($data['openingbalance']); + $amount = floatval($data['openingBalance']); /** @var \Transaction $transaction */ foreach ($openingBalance->transactions as $transaction) { if ($transaction->account_id == $model->id) { @@ -453,14 +363,14 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte * 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['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) { + if (isset($model['openingBalanceDate']) && strlen($model['openingBalanceDate']) > 0) { try { - new Carbon($model['openingbalancedate']); + new Carbon($model['openingBalanceDate']); } catch (\Exception $e) { - $errors->add('openingbalancedate', 'This date is invalid.'); + $errors->add('openingBalanceDate', 'This date is invalid.'); } } } @@ -469,11 +379,11 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte if (!$errors->has('name')) { $successes->add('name', 'OK'); } - if (!$errors->has('openingbalance')) { - $successes->add('openingbalance', 'OK'); + if (!$errors->has('openingBalance')) { + $successes->add('openingBalance', 'OK'); } - if (!$errors->has('openingbalancedate')) { - $successes->add('openingbalancedate', 'OK'); + if (!$errors->has('openingBalanceDate')) { + $successes->add('openingBalanceDate', 'OK'); } return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; @@ -492,6 +402,9 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @codeCoverageIgnore + * * @param $what * * @throws NotImplementedException @@ -507,6 +420,7 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte * * @return Collection * @throws NotImplementedException + * @codeCoverageIgnore */ public function get() { @@ -531,14 +445,14 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte */ public function firstExpenseAccountOrCreate($name) { - /** @var \FireflyIII\Database\AccountType\AccountType $accountTypeRepository */ - $accountTypeRepository = \App::make('FireflyIII\Database\AccountType\AccountType'); + /** @var \FireflyIII\Database\AccountType\AccountType $typeRepository */ + $typeRepository = \App::make('FireflyIII\Database\AccountType\AccountType'); - $accountType = $accountTypeRepository->findByWhat('expense'); + $accountType = $typeRepository->findByWhat('expense'); // if name is "", find cash account: if (strlen($name) == 0) { - $cashAccountType = $accountTypeRepository->findByWhat('cash'); + $cashAccountType = $typeRepository->findByWhat('cash'); // find or create cash account: return \Account::firstOrCreate( @@ -560,10 +474,20 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte */ public function firstRevenueAccountOrCreate($name) { - /** @var \FireflyIII\Database\AccountType\AccountType $accountTypeRepository */ - $accountTypeRepository = \App::make('FireflyIII\Database\AccountType\AccountType'); + /** @var \FireflyIII\Database\AccountType\AccountType $typeRepository */ + $typeRepository = \App::make('FireflyIII\Database\AccountType\AccountType'); - $accountType = $accountTypeRepository->findByWhat('revenue'); + $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]; @@ -571,57 +495,6 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte } - /** - * @param \Account $account - * @param int $limit - * - * @return \Illuminate\Pagination\Paginator - */ - public function getAllTransactionJournals(\Account $account, $limit = 50) - { - $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0; - $set = $this->getUser()->transactionJournals()->withRelevantData()->leftJoin( - 'transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id' - )->where('transactions.account_id', $account->id)->take($limit)->offset($offset)->orderBy('date', 'DESC')->get( - ['transaction_journals.*'] - ); - $count = $this->getUser()->transactionJournals()->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') - ->orderBy('date', 'DESC')->where('transactions.account_id', $account->id)->count(); - $items = []; - foreach ($set as $entry) { - $items[] = $entry; - } - - return \Paginator::make($items, $count, $limit); - - - } - - /** - * @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; - } - /** * @param \Account $account * @param int $limit @@ -656,24 +529,4 @@ class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInte } - /** - * @param \Account $account - * @param Carbon $start - * @param Carbon $end - * - * @return \Illuminate\Pagination\Paginator - */ - public function getTransactionJournalsInRange(\Account $account, Carbon $start, Carbon $end) - { - $set = $this->getUser()->transactionJournals()->transactionTypes(['Withdrawal'])->withRelevantData()->leftJoin( - 'transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id' - )->where('transactions.account_id', $account->id)->before($end)->after($start)->orderBy('date', 'DESC')->get( - ['transaction_journals.*'] - ); - - return $set; - - } - - } diff --git a/app/lib/FireflyIII/Database/Account/AccountInterface.php b/app/lib/FireflyIII/Database/Account/AccountInterface.php index 336df90401..c9d21ba229 100644 --- a/app/lib/FireflyIII/Database/Account/AccountInterface.php +++ b/app/lib/FireflyIII/Database/Account/AccountInterface.php @@ -21,34 +21,6 @@ interface AccountInterface */ public function countAccountsByType(array $types); - /** - * Counts the number of total asset accounts. Useful for DataTables. - * - * @return int - */ - public function countAssetAccounts(); - - /** - * Counts the number of total expense accounts. Useful for DataTables. - * - * @return int - */ - public function countExpenseAccounts(); - - /** - * Counts the number of total revenue accounts. Useful for DataTables. - * - * @return int - */ - public function countRevenueAccounts(); - - /** - * @param \Account $account - * - * @return \Account|null - */ - public function findInitialBalanceAccount(\Account $account); - /** * Get all accounts of the selected types. Is also capable of handling DataTables' parameters. * @@ -58,24 +30,6 @@ interface AccountInterface */ public function getAccountsByType(array $types); - /** - * Get all asset accounts. The parameters are optional and are provided by the DataTables plugin. - * - * @return Collection - */ - public function getAssetAccounts(); - - /** - * @return Collection - */ - public function getExpenseAccounts(); - - /** - * Get all revenue accounts. - * - * @return Collection - */ - public function getRevenueAccounts(); /** * @param \Account $account diff --git a/app/lib/FireflyIII/Database/AccountType/AccountType.php b/app/lib/FireflyIII/Database/AccountType/AccountType.php index 58f6cebb13..2b30ea3e25 100644 --- a/app/lib/FireflyIII/Database/AccountType/AccountType.php +++ b/app/lib/FireflyIII/Database/AccountType/AccountType.php @@ -19,9 +19,11 @@ class AccountType implements CUDInterface, CommonDatabaseCallsInterface /** * @param Eloquent $model + * @SuppressWarnings(PHPMD.UnusedFormalParameter) * * @return bool * @throws NotImplementedException + * @codeCoverageIgnore */ public function destroy(Eloquent $model) { @@ -30,9 +32,11 @@ class AccountType implements CUDInterface, CommonDatabaseCallsInterface /** * @param array $data + * @SuppressWarnings(PHPMD.UnusedFormalParameter) * * @return \Eloquent * @throws NotImplementedException + * @codeCoverageIgnore */ public function store(array $data) { @@ -42,9 +46,11 @@ class AccountType implements CUDInterface, CommonDatabaseCallsInterface /** * @param Eloquent $model * @param array $data + * @SuppressWarnings(PHPMD.UnusedFormalParameter) * * @return bool * @throws NotImplementedException + * @codeCoverageIgnore */ public function update(Eloquent $model, array $data) { @@ -52,6 +58,8 @@ class AccountType implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * Validates an array. Returns an array containing MessageBags * errors/warnings/successes. * @@ -59,6 +67,7 @@ class AccountType implements CUDInterface, CommonDatabaseCallsInterface * * @return array * @throws NotImplementedException + * @codeCoverageIgnore */ public function validate(array $model) { @@ -66,12 +75,15 @@ class AccountType implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * Returns an object with id $id. * * @param int $objectId * * @return \Eloquent * @throws NotImplementedException + * @codeCoverageIgnore */ public function find($objectId) { @@ -88,34 +100,27 @@ class AccountType implements CUDInterface, CommonDatabaseCallsInterface */ public function findByWhat($what) { - switch ($what) { - case 'expense': - return \AccountType::whereType('Expense account')->first(); - break; - case 'asset': - return \AccountType::whereType('Asset account')->first(); - break; - case 'revenue': - return \AccountType::whereType('Revenue account')->first(); - break; - case 'cash': - return \AccountType::whereType('Cash account')->first(); - break; - case 'initial': - return \AccountType::whereType('Initial balance account')->first(); - break; - default: - throw new FireflyException('Cannot find account type described as "' . e($what) . '".'); - break; - + $typeMap = [ + 'expense' => '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() { @@ -123,10 +128,13 @@ class AccountType implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param array $ids * * @return Collection * @throws NotImplementedException + * @codeCoverageIgnore */ public function getByIds(array $ids) { diff --git a/app/lib/FireflyIII/Database/Bill/Bill.php b/app/lib/FireflyIII/Database/Bill/Bill.php index 6e17ffe827..75b4800497 100644 --- a/app/lib/FireflyIII/Database/Bill/Bill.php +++ b/app/lib/FireflyIII/Database/Bill/Bill.php @@ -114,7 +114,7 @@ class Bill implements CUDInterface, CommonDatabaseCallsInterface, BillInterface $warnings = new MessageBag; $successes = new MessageBag; $errors = new MessageBag; - if (isset($model['amount_min']) && isset($model['amount_max']) && floatval($model['amount_min']) > floatval($model['amount_max'])) { + 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.'); } @@ -133,12 +133,15 @@ class Bill implements CUDInterface, CommonDatabaseCallsInterface, BillInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * Returns an object with id $id. * * @param int $objectId * * @return \Eloquent * @throws NotImplementedException + * @codeCoverageIgnore */ public function find($objectId) { @@ -146,12 +149,15 @@ class Bill implements CUDInterface, CommonDatabaseCallsInterface, BillInterface } /** + * @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) { @@ -169,39 +175,18 @@ class Bill implements CUDInterface, CommonDatabaseCallsInterface, BillInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) * @param array $ids * * @return Collection * @throws NotImplementedException + * @codeCoverageIgnore */ public function getByIds(array $ids) { throw new NotImplementedException; } - /** - * Returns all objects. - * - * @return Collection - */ - public function getActive() - { - return $this->getUser()->bills()->where('active', 1)->get(); - } - - /** - * @param \Bill $bill - * @param Carbon $start - * @param Carbon $end - * - * @return \TransactionJournal|null - */ - public function getJournalForBillInRange(\Bill $bill, Carbon $start, Carbon $end) - { - return $this->getUser()->transactionjournals()->where('bill_id', $bill->id)->after($start)->before($end)->first(); - - } - /** * @param \Bill $bill * @@ -218,15 +203,14 @@ class Bill implements CUDInterface, CommonDatabaseCallsInterface, BillInterface } /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param \Bill $bill * * @return Carbon|null */ public function nextExpectedMatch(\Bill $bill) { - /* - * The date Firefly tries to find. If this stays null, it's "unknown". - */ $finalDate = null; if ($bill->active == 0) { return $finalDate; @@ -238,10 +222,6 @@ class Bill implements CUDInterface, CommonDatabaseCallsInterface, BillInterface */ $today = \DateKit::addPeriod(new Carbon, $bill->repeat_freq, 0); - /* - * FF3 loops from the $start of the bill, and to make sure - * $skip works, it adds one (for modulo). - */ $skip = $bill->skip + 1; $start = \DateKit::startOfPeriod(new Carbon, $bill->repeat_freq); /* diff --git a/app/lib/FireflyIII/Database/Bill/BillInterface.php b/app/lib/FireflyIII/Database/Bill/BillInterface.php index f6dca6325f..ec75dd1167 100644 --- a/app/lib/FireflyIII/Database/Bill/BillInterface.php +++ b/app/lib/FireflyIII/Database/Bill/BillInterface.php @@ -11,18 +11,6 @@ use Carbon\Carbon; */ interface BillInterface { - /** - * @param \Bill $bill - * @param Carbon $start - * @param Carbon $end - * - * @return null|\TransactionJournal - * @internal param Carbon $current - * @internal param Carbon $currentEnd - * - */ - public function getJournalForBillInRange(\Bill $bill, Carbon $start, Carbon $end); - /** * @param \Bill $bill * diff --git a/app/lib/FireflyIII/Database/Budget/Budget.php b/app/lib/FireflyIII/Database/Budget/Budget.php index 05f712a259..86d3f0b5f8 100644 --- a/app/lib/FireflyIII/Database/Budget/Budget.php +++ b/app/lib/FireflyIII/Database/Budget/Budget.php @@ -8,9 +8,9 @@ use FireflyIII\Database\SwitchUser; use FireflyIII\Exception\FireflyException; use FireflyIII\Exception\NotImplementedException; use Illuminate\Database\Eloquent\Model as Eloquent; +use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Support\Collection; use Illuminate\Support\MessageBag; -use Illuminate\Database\Query\Builder as QueryBuilder; /** * Class Budget @@ -97,6 +97,71 @@ class Budget implements CUDInterface, CommonDatabaseCallsInterface, BudgetInterf 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. * @@ -110,12 +175,15 @@ class Budget implements CUDInterface, CommonDatabaseCallsInterface, BudgetInterf } /** + * @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) { @@ -135,10 +203,13 @@ class Budget implements CUDInterface, CommonDatabaseCallsInterface, BudgetInterf } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param array $ids * * @return Collection * @throws NotImplementedException + * @codeCoverageIgnore */ public function getByIds(array $ids) { @@ -190,116 +261,6 @@ class Budget implements CUDInterface, CommonDatabaseCallsInterface, BudgetInterf return $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']); } - /** - * @param \Budget $budget - * @param int $limit - * - * @return \Illuminate\Pagination\Paginator - */ - public function getTransactionJournals(\Budget $budget, $limit = 50) - { - $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0; - $set = $budget->transactionJournals()->withRelevantData()->take($limit)->offset($offset)->orderBy('date', 'DESC')->get(['transaction_journals.*']); - $count = $budget->transactionJournals()->count(); - $items = []; - foreach ($set as $entry) { - $items[] = $entry; - } - - return \Paginator::make($items, $count, $limit); - - } - - /** - * @param \Budget $budget - * @param \LimitRepetition $repetition - * @param int $limit - * - * @return \Illuminate\Pagination\Paginator - */ - public function getTransactionJournalsInRepetition(\Budget $budget, \LimitRepetition $repetition, $limit = 50) - { - $start = $repetition->startdate; - $end = $repetition->enddate; - - $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0; - $set = $budget->transactionJournals()->withRelevantData()->before($end)->after($start)->take($limit)->offset($offset)->orderBy('date', 'DESC')->get( - ['transaction_journals.*'] - ); - $count = $budget->transactionJournals()->before($end)->after($start)->count(); - $items = []; - foreach ($set as $entry) { - $items[] = $entry; - } - - return \Paginator::make($items, $count, $limit); - } - - /** - * 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.*']); - } - - /** - * @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; - } - /** * @param \Budget $budget * @param Carbon $date @@ -316,20 +277,6 @@ class Budget implements CUDInterface, CommonDatabaseCallsInterface, BudgetInterf return $sum; } - /** - * @param \Budget $budget - * @param Carbon $start - * @param Carbon $end - * - * @return float - */ - public function spentInPeriod(\Budget $budget, Carbon $start, Carbon $end) - { - $sum = floatval($budget->transactionjournals()->before($end)->after($start)->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. @@ -343,7 +290,7 @@ class Budget implements CUDInterface, CommonDatabaseCallsInterface, BudgetInterf */ public function updateLimitAmount(\Budget $budget, Carbon $date, $amount) { - /** @var \Limit $limit */ + /** @var \BudgetLimit $limit */ $limit = $this->limitOnStartingOnDate($budget, $date); if (!$limit) { // create one! @@ -381,7 +328,7 @@ class Budget implements CUDInterface, CommonDatabaseCallsInterface, BudgetInterf * @param \Budget $budget * @param Carbon $date * - * @return \Limit + * @return \BudgetLimit */ public function limitOnStartingOnDate(\Budget $budget, Carbon $date) { diff --git a/app/lib/FireflyIII/Database/Category/Category.php b/app/lib/FireflyIII/Database/Category/Category.php index 873ac9c312..7c94a818eb 100644 --- a/app/lib/FireflyIII/Database/Category/Category.php +++ b/app/lib/FireflyIII/Database/Category/Category.php @@ -99,12 +99,15 @@ class Category implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * Returns an object with id $id. * * @param int $objectId * * @return \Eloquent * @throws NotImplementedException + * @codeCoverageIgnore */ public function find($objectId) { @@ -112,12 +115,15 @@ class Category implements CUDInterface, CommonDatabaseCallsInterface } /** + * @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) { @@ -125,6 +131,8 @@ class Category implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * Returns all objects. * * @return Collection @@ -135,10 +143,13 @@ class Category implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param array $ids * * @return Collection * @throws NotImplementedException + * @codeCoverageIgnore */ public function getByIds(array $ids) { @@ -195,19 +206,6 @@ class Category implements CUDInterface, CommonDatabaseCallsInterface return $set; } - /** - * @param \Category $category - * @param Carbon $date - * - * @return null - * @throws NotImplementedException - * @internal param \Category $budget - */ - public function repetitionOnStartingOnDate(\Category $category, Carbon $date) - { - throw new NotImplementedException; - } - /** * @param \Category $category * @param Carbon $date diff --git a/app/lib/FireflyIII/Database/PiggyBank/PiggyBank.php b/app/lib/FireflyIII/Database/PiggyBank/PiggyBank.php index b77f9246bb..6490b96d9b 100644 --- a/app/lib/FireflyIII/Database/PiggyBank/PiggyBank.php +++ b/app/lib/FireflyIII/Database/PiggyBank/PiggyBank.php @@ -21,7 +21,6 @@ class PiggyBank extends PiggyBankShared implements CUDInterface, CommonDatabaseC * * @return mixed * @throws FireflyException - * @throws NotImplementedException */ public function findRepetitionByDate(\PiggyBank $piggyBank, Carbon $date) { @@ -30,13 +29,10 @@ class PiggyBank extends PiggyBankShared implements CUDInterface, CommonDatabaseC if ($reps->count() == 1) { return $reps->first(); } - if ($reps->count() == 0) { - throw new FireflyException('Should always find a piggy bank repetition.'); - } // should filter the one we need: $repetitions = $reps->filter( function (\PiggyBankRepetition $rep) use ($date) { - if ($date >= $rep->startdate && $date <= $rep->targetdate) { + if ($date->between($rep->startdate, $rep->targetdate)) { return $rep; } diff --git a/app/lib/FireflyIII/Database/PiggyBank/PiggyBankShared.php b/app/lib/FireflyIII/Database/PiggyBank/PiggyBankShared.php index 5a878e37f4..212e3b77db 100644 --- a/app/lib/FireflyIII/Database/PiggyBank/PiggyBankShared.php +++ b/app/lib/FireflyIII/Database/PiggyBank/PiggyBankShared.php @@ -58,12 +58,15 @@ class PiggyBankShared } /** + * @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) { @@ -75,14 +78,11 @@ class PiggyBankShared * * @return Collection * @throws NotImplementedException + * @codeCoverageIgnore */ public function getByIds(array $ids) { - return \PiggyBank:: - leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')->whereIn('piggy_banks.id', [$ids])->where( - 'accounts.user_id', $this->getUser()->id - ) - ->first(['piggy_banks.*']); + throw new NotImplementedException; } /** @@ -123,6 +123,8 @@ class PiggyBankShared /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param Eloquent $model * @param array $data * diff --git a/app/lib/FireflyIII/Database/PiggyBank/RepeatedExpense.php b/app/lib/FireflyIII/Database/PiggyBank/RepeatedExpense.php index 171b4c7a88..bf22ca509c 100644 --- a/app/lib/FireflyIII/Database/PiggyBank/RepeatedExpense.php +++ b/app/lib/FireflyIII/Database/PiggyBank/RepeatedExpense.php @@ -17,6 +17,8 @@ class RepeatedExpense extends PiggyBankShared implements CUDInterface, CommonDat { /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * Based on the piggy bank, the reminder-setting and * other variables this method tries to divide the piggy bank into equal parts. Each is * accommodated by a reminder (if everything goes to plan). diff --git a/app/lib/FireflyIII/Database/Transaction/Transaction.php b/app/lib/FireflyIII/Database/Transaction/Transaction.php index a92f110d2e..d8c2ea909d 100644 --- a/app/lib/FireflyIII/Database/Transaction/Transaction.php +++ b/app/lib/FireflyIII/Database/Transaction/Transaction.php @@ -22,9 +22,11 @@ class Transaction implements CUDInterface, CommonDatabaseCallsInterface /** * @param Eloquent $model + * @SuppressWarnings(PHPMD.UnusedFormalParameter) * * @return bool * @throws NotImplementedException + * @codeCoverageIgnore */ public function destroy(Eloquent $model) { @@ -59,11 +61,14 @@ class Transaction implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param Eloquent $model * @param array $data * * @return bool * @throws NotImplementedException + * @codeCoverageIgnore */ public function update(Eloquent $model, array $data) { @@ -92,12 +97,15 @@ class Transaction implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * Returns an object with id $id. * * @param int $objectId * * @return \Eloquent * @throws NotImplementedException + * @codeCoverageIgnore */ public function find($objectId) { @@ -105,12 +113,15 @@ class Transaction implements CUDInterface, CommonDatabaseCallsInterface } /** + * @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) { @@ -122,6 +133,7 @@ class Transaction implements CUDInterface, CommonDatabaseCallsInterface * * @return Collection * @throws NotImplementedException + * @codeCoverageIgnore */ public function get() { @@ -129,10 +141,13 @@ class Transaction implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param array $ids * * @return Collection * @throws NotImplementedException + * @codeCoverageIgnore */ public function getByIds(array $ids) { diff --git a/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrency.php b/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrency.php index 55b7c5f502..3eeb6eb5f9 100644 --- a/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrency.php +++ b/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrency.php @@ -89,23 +89,27 @@ class TransactionCurrency implements TransactionCurrencyInterface, CommonDatabas } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * Returns an object with id $id. * * @param int $objectId - * @throws NotImplementedException * * @return \Eloquent */ public function find($objectId) { - throw new NotImplementedException; + 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 */ @@ -125,8 +129,11 @@ class TransactionCurrency implements TransactionCurrencyInterface, CommonDatabas } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param array $objectIds * @throws NotImplementedException + * @codeCoverageIgnore * * @return Collection */ diff --git a/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournal.php b/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournal.php index beb7b13df2..b7feb1f15b 100644 --- a/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournal.php +++ b/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournal.php @@ -63,12 +63,13 @@ class TransactionJournal implements TransactionJournalInterface, CUDInterface, C */ public function store(array $data) { - $currency = $this->getJournalCurrency($data['currency']); - $journal = new \TransactionJournal( + $journal = new \TransactionJournal( [ 'transaction_type_id' => $data['transaction_type_id'], - 'transaction_currency_id' => $currency->id, 'user_id' => $this->getUser()->id, - 'description' => $data['description'], 'date' => $data['date'], 'completed' => 0] + 'transaction_currency_id' => $data['transaction_currency_id'], + 'user_id' => $this->getUser()->id, + 'description' => $data['description'], + 'date' => $data['date'], 'completed' => 0] ); $journal->save(); @@ -102,7 +103,7 @@ class TransactionJournal implements TransactionJournalInterface, CUDInterface, C public function update(Eloquent $model, array $data) { $journalType = $this->getJournalType($data['what']); - $currency = $this->getJournalCurrency($data['currency']); + $currency = $this->getJournalCurrencyById($data['transaction_currency_id']); $model->description = $data['description']; $model->date = $data['date']; @@ -117,9 +118,6 @@ class TransactionJournal implements TransactionJournalInterface, CUDInterface, C $this->storeBudget($data, $model); $this->storeCategory($data, $model); - /* - * Now we can update the transactions related to this journal. - */ $amount = floatval($data['amount']); /** @var \Transaction $transaction */ foreach ($model->transactions()->get() as $transaction) { @@ -164,109 +162,29 @@ class TransactionJournal implements TransactionJournalInterface, CUDInterface, C if (!isset($model['what'])) { $errors->add('description', 'Internal error: need to know type of transaction!'); } - /* - * Amount - */ - 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!'); - } else { - $successes->add('amount', 'OK'); + 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'); } } - /* - * Budget - */ - if (isset($model['budget_id']) && !ctype_digit($model['budget_id'])) { - $errors->add('budget_id', 'Invalid budget'); - } else { - $successes->add('budget_id', 'OK'); - } - - $successes->add('category', 'OK'); - - /* - * Many checks to catch invalid or not-existing accounts. - */ - 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.'); - } else { - $successes->add('account_id', 'OK'); - } - $successes->add('expense_account', 'OK'); - break; - case (isset($model['account_id']) && isset($model['revenue_account'])): - if (intval($model['account_id']) < 1) { - $errors->add('account_id', 'Invalid account.'); - } else { - $successes->add('account_id', 'OK'); - } - $successes->add('revenue_account', 'OK'); - break; - 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.'); - } else { - $successes->add('account_from_id', 'OK'); - $successes->add('account_to_id', 'OK'); - } - } - break; - - case (isset($model['to']) && isset($model['from'])): - if (is_object($model['to']) && is_object($model['from'])) { - $successes->add('from', 'OK'); - $successes->add('to', 'OK'); - } - break; - - default: - throw new FireflyException('Cannot validate accounts for transaction journal.'); - break; - } - - - /* - * Add "OK" - */ - if (!$errors->has('description')) { - $successes->add('description', 'OK'); - } - if (!$errors->has('date')) { - $successes->add('date', 'OK'); - } - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; } /** - * @param $currency + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. * - * @return null|\TransactionCurrency - */ - public function getJournalCurrency($currency) - { - /** @var \FireflyIII\Database\TransactionCurrency\TransactionCurrency $currencyRepository */ - $currencyRepository = \App::make('FireflyIII\Database\TransactionCurrency\TransactionCurrency'); - - return $currencyRepository->findByCode($currency); - } - - /** * @param array $data * * @return array @@ -377,25 +295,133 @@ class TransactionJournal implements TransactionJournalInterface, CUDInterface, C 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) { - return $this->getUser()->transactionjournals()->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) { @@ -406,11 +432,11 @@ class TransactionJournal implements TransactionJournalInterface, CUDInterface, C * Returns all objects. * * @return Collection + * @codeCoverageIgnore */ public function get() { - return $this->getUser()->transactionjournals()->with(['TransactionType', 'transactions', 'transactions.account', 'transactions.account.accountType']) - ->get(); + throw new NotImplementedException; } /** @@ -444,17 +470,6 @@ class TransactionJournal implements TransactionJournalInterface, CUDInterface, C return $this->getUser()->transactionjournals()->orderBy('date', 'ASC')->first(); } - /** - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function getInDateRange(Carbon $start, Carbon $end) - { - return $this->getuser()->transactionjournals()->withRelevantData()->before($end)->after($start)->get(); - } - /** * @param Carbon $date * @@ -539,6 +554,19 @@ class TransactionJournal implements TransactionJournalInterface, CUDInterface, C 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 * diff --git a/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournalInterface.php b/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournalInterface.php index 0268d53d81..264aeb5200 100644 --- a/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournalInterface.php +++ b/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournalInterface.php @@ -19,14 +19,6 @@ interface TransactionJournalInterface */ public function first(); - /** - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function getInDateRange(Carbon $start, Carbon $end); - /** * @param Carbon $date * diff --git a/app/lib/FireflyIII/Database/TransactionType/TransactionType.php b/app/lib/FireflyIII/Database/TransactionType/TransactionType.php index b3b5191de4..cd202a3c2d 100644 --- a/app/lib/FireflyIII/Database/TransactionType/TransactionType.php +++ b/app/lib/FireflyIII/Database/TransactionType/TransactionType.php @@ -20,10 +20,13 @@ class TransactionType implements CUDInterface, CommonDatabaseCallsInterface { /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param Eloquent $model * * @return bool * @throws NotImplementedException + * @codeCoverageIgnore */ public function destroy(Eloquent $model) { @@ -31,10 +34,13 @@ class TransactionType implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param array $data * * @return \Eloquent * @throws NotImplementedException + * @codeCoverageIgnore */ public function store(array $data) { @@ -42,11 +48,14 @@ class TransactionType implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param Eloquent $model * @param array $data * * @return bool * @throws NotImplementedException + * @codeCoverageIgnore */ public function update(Eloquent $model, array $data) { @@ -54,6 +63,8 @@ class TransactionType implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * Validates an array. Returns an array containing MessageBags * errors/warnings/successes. * @@ -61,6 +72,7 @@ class TransactionType implements CUDInterface, CommonDatabaseCallsInterface * * @return array * @throws NotImplementedException + * @codeCoverageIgnore */ public function validate(array $model) { @@ -68,12 +80,15 @@ class TransactionType implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * Returns an object with id $id. * * @param int $objectId * * @return \Eloquent * @throws NotImplementedException + * @codeCoverageIgnore */ public function find($objectId) { @@ -96,17 +111,21 @@ class TransactionType implements CUDInterface, CommonDatabaseCallsInterface 'withdrawal' => 'Withdrawal', 'deposit' => 'Deposit', ]; - if(!isset($translation[$what])) { + 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() { @@ -114,10 +133,13 @@ class TransactionType implements CUDInterface, CommonDatabaseCallsInterface } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param array $ids * * @return Collection * @throws NotImplementedException + * @codeCoverageIgnore */ public function getByIds(array $ids) { diff --git a/app/lib/FireflyIII/Event/Piggybank.php b/app/lib/FireflyIII/Event/Piggybank.php index 5c1960a170..9273f5c600 100644 --- a/app/lib/FireflyIII/Event/Piggybank.php +++ b/app/lib/FireflyIII/Event/Piggybank.php @@ -34,6 +34,8 @@ class PiggyBank } /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param \TransactionJournal $journal * * @throws \FireflyIII\Exception\FireflyException @@ -109,6 +111,8 @@ class PiggyBank */ /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param \TransactionJournal $journal * @param int $piggyBankId */ @@ -176,6 +180,8 @@ class PiggyBank } /** + * @SuppressWarnings("CyclomaticComplexity") // It's 6. More than 5 but alright. + * * Validates the presence of repetitions for all repeated expenses! */ public function validateRepeatedExpenses() @@ -185,32 +191,24 @@ class PiggyBank } /** @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) { - $start = $entry->startdate; - $target = $entry->targetdate; - // find a repetition on this date: - $count = $entry->piggyBankrepetitions()->starts($start)->targets($target)->count(); + $count = $entry->piggyBankrepetitions()->starts($entry->startdate)->targets($entry->targetdate)->count(); if ($count == 0) { $repetition = new \PiggyBankRepetition; $repetition->piggyBank()->associate($entry); - $repetition->startdate = $start; - $repetition->targetdate = $target; + $repetition->startdate = $entry->startdate; + $repetition->targetdate = $entry->targetdate; $repetition->currentamount = 0; $repetition->save(); } - // then continue and do something in the current relevant time frame. - - $currentTarget = clone $target; + $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); - // create if not exists: $count = $entry->piggyBankRepetitions()->starts($currentStart)->targets($currentTarget)->count(); if ($count == 0) { $repetition = new \PiggyBankRepetition; diff --git a/app/lib/FireflyIII/FF3ServiceProvider.php b/app/lib/FireflyIII/FF3ServiceProvider.php index 879313a2d2..5940441dda 100644 --- a/app/lib/FireflyIII/FF3ServiceProvider.php +++ b/app/lib/FireflyIII/FF3ServiceProvider.php @@ -32,6 +32,7 @@ class FF3ServiceProvider extends ServiceProvider /** * Return the services bla bla. * + * @CodeCoverageIgnore * @return array */ public function provides() diff --git a/app/lib/FireflyIII/Form/Form.php b/app/lib/FireflyIII/Form/Form.php index 68409ab2df..59a28f7828 100644 --- a/app/lib/FireflyIII/Form/Form.php +++ b/app/lib/FireflyIII/Form/Form.php @@ -24,169 +24,15 @@ class Form */ public static function ffAmount($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'; $options['min'] = '0.01'; - - return self::ffInput('amount', $name, $value, $options); - - } - - /** - * @param $type - * @param $name - * @param null $value - * @param array $options - * @param array $list - * - * @return string - * @throws FireflyException - */ - public static function ffInput($type, $name, $value = null, array $options = [], $list = []) - { - /* - * add some defaults to this method: - */ - $options['class'] = 'form-control'; - $options['id'] = 'ffInput_' . $name; - $options['autocomplete'] = 'off'; - $label = self::label($name, $options); - - /* - * Make label and placeholder look nice. - */ - $options['placeholder'] = ucfirst($name); - - /* - * Get pre filled value: - */ - if (\Session::has('preFilled')) { - $preFilled = \Session::get('preFilled'); - $value = isset($preFilled[$name]) && is_null($value) ? $preFilled[$name] : $value; - - } - - /* - * Get the value. - */ - if (!is_null(\Input::old($name))) { - /* - * Old value overrules $value. - */ - $value = \Input::old($name); - } - - /* - * Get errors, warnings and successes from session: - */ - /** @var MessageBag $errors */ - $errors = \Session::get('errors'); - - /** @var MessageBag $warnings */ - $warnings = \Session::get('warnings'); - - /** @var MessageBag $successes */ - $successes = \Session::get('successes'); - - - /* - * If errors, add some more classes. - */ - switch (true) { - case (!is_null($errors) && $errors->has($name)): - $classes = 'form-group has-error has-feedback'; - break; - case (!is_null($warnings) && $warnings->has($name)): - $classes = 'form-group has-warning has-feedback'; - break; - case (!is_null($successes) && $successes->has($name)): - $classes = 'form-group has-success has-feedback'; - break; - default: - $classes = 'form-group'; - break; - } - - /* - * Add some HTML. - */ - $html = '
'; - $html .= ''; - $html .= '
'; - - - /* - * Switch input type: - */ - unset($options['label']); - switch ($type) { - case 'text': - $html .= \Form::input('text', $name, $value, $options); - break; - case 'amount': - $html .= '
' . \Amount::getCurrencySymbol() . '
'; - $html .= \Form::input('number', $name, $value, $options); - $html .= '
'; - break; - case 'number': - $html .= \Form::input('number', $name, $value, $options); - break; - case 'checkbox': - $checked = $options['checked']; - unset($options['placeholder'], $options['autocomplete'], $options['class']); - $html .= '
'; - - - break; - case 'date': - $html .= \Form::input('date', $name, $value, $options); - break; - case 'select': - $html .= \Form::select($name, $list, $value, $options); - break; - default: - throw new FireflyException('Cannot handle type "' . $type . '" in FFFormBuilder.'); - break; - } - - /* - * If errors, respond to them: - */ - - if (!is_null($errors)) { - if ($errors->has($name)) { - $html .= ''; - $html .= '

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

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

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

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

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

'; - } - } - unset($successes); - - $html .= '
'; - $html .= '
'; + $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; @@ -204,12 +50,81 @@ class Form 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']; + '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 @@ -220,10 +135,15 @@ class Form */ 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'; - - return self::ffInput('amount', $name, $value, $options); - + $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; } /** @@ -238,8 +158,16 @@ class Form 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); - return self::ffInput('checkbox', $name, $value, $options); + unset($options['placeholder'], $options['autocomplete'], $options['class']); + + $html = \View::make('form.checkbox', compact('classes', 'name', 'label', 'value', 'options'))->render(); + + return $html; } /** @@ -252,7 +180,13 @@ class Form */ public static function ffDate($name, $value = null, array $options = []) { - return self::ffInput('date', $name, $value, $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; } /** @@ -265,9 +199,14 @@ class Form */ 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 self::ffInput('number', $name, $value, $options); + return $html; } @@ -284,57 +223,9 @@ class Form { $previousValue = \Input::old('post_submit_action'); $previousValue = is_null($previousValue) ? 'store' : $previousValue; - /* - * Store. - */ - switch ($type) { - case 'create': - $store = '
'; - $store .= '
'; - break; - case 'update': - $store = '
'; - $store .= '
'; - break; - default: - throw new FireflyException('Cannot create ffOptionsList for option (store) ' . $type); - break; - } + $html = \View::make('form.options', compact('type', 'name', 'previousValue'))->render(); - /* - * validate is always the same: - */ - $validate = '
'; - - /* - * Store & return: - */ - switch ($type) { - case 'create': - $return = '
'; - break; - case 'update': - $return = '
'; - break; - default: - throw new FireflyException('Cannot create ffOptionsList for option (store+return) ' . $type); - break; - } - - return $store . $validate . $return; + return $html; } /** @@ -344,11 +235,16 @@ class Form * @param array $options * * @return string - * @throws FireflyException */ public static function ffSelect($name, array $list = [], $selected = null, array $options = []) { - return self::ffInput('select', $name, $selected, $options, $list); + $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; } /** @@ -361,9 +257,14 @@ class Form */ 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 self::ffInput('text', $name, $value, $options); + return $html; } /** @@ -376,7 +277,13 @@ class Form */ public static function ffText($name, $value = null, array $options = []) { - return self::ffInput('text', $name, $value, $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 index 0627374e74..1732f638ad 100644 --- a/app/lib/FireflyIII/Helper/Related/Related.php +++ b/app/lib/FireflyIII/Helper/Related/Related.php @@ -56,14 +56,36 @@ class Related implements RelatedInterface } $exclude = array_unique($exclude); - $query = $this->getUser()->transactionjournals() - ->withRelevantData() - ->before($end) - ->after($start) - ->whereNotIn('id', $exclude) - ->where('description', 'LIKE', '%' . $query . '%') - ->get(); + /** @var Collection $collection */ + $collection = $this->getUser()->transactionjournals() + ->withRelevantData() + ->before($end) + ->where('encrypted', 0) + ->after($start) + ->whereNotIn('id', $exclude) + ->where('description', 'LIKE', '%' . $query . '%') + ->get(); - return $query; + // manually search encrypted entries: + /** @var Collection $encryptedCollection */ + $encryptedCollection = $this->getUser()->transactionjournals() + ->withRelevantData() + ->before($end) + ->where('encrypted', 1) + ->after($start) + ->whereNotIn('id', $exclude) + ->get(); + $encrypted = $encryptedCollection->filter( + function (\TransactionJournal $journal) use ($query) { + $strPos = strpos($journal->description, $query); + if ($strPos !== false) { + return $journal; + } + } + ); + $collected = $collection->merge($encrypted); + + + return $collected; } } diff --git a/app/lib/FireflyIII/Helper/TransactionJournal/Helper.php b/app/lib/FireflyIII/Helper/TransactionJournal/Helper.php index 304cef0c5d..90ef11060d 100644 --- a/app/lib/FireflyIII/Helper/TransactionJournal/Helper.php +++ b/app/lib/FireflyIII/Helper/TransactionJournal/Helper.php @@ -12,15 +12,6 @@ use Illuminate\Support\Collection; class Helper implements HelperInterface { - /** - * @param $what - * - * @return int - */ - public function getTransactionTypeIdByWhat($what) { - - } - /** * * Get the account_id, which is the asset account that paid for the transaction. @@ -49,7 +40,7 @@ class Helper implements HelperInterface /** @var \FireflyIII\Database\Account\Account $accountRepository */ $accountRepository = \App::make('FireflyIII\Database\Account\Account'); - return $accountRepository->getAssetAccounts(); + return $accountRepository->getAccountsByType(['Default account', 'Asset account']); } /** @@ -90,4 +81,5 @@ class Helper implements HelperInterface } + } diff --git a/app/lib/FireflyIII/Helper/TransactionJournal/HelperInterface.php b/app/lib/FireflyIII/Helper/TransactionJournal/HelperInterface.php index f49046a42a..06bcac0de7 100644 --- a/app/lib/FireflyIII/Helper/TransactionJournal/HelperInterface.php +++ b/app/lib/FireflyIII/Helper/TransactionJournal/HelperInterface.php @@ -22,13 +22,6 @@ interface HelperInterface */ public function getAssetAccount($what, Collection $transactions); - /** - * @param $what - * - * @return int - */ - public function getTransactionTypeIdByWhat($what); - /** * @return Collection */ diff --git a/app/lib/FireflyIII/Report/Report.php b/app/lib/FireflyIII/Report/Report.php index 56deca08ec..8355cfc602 100644 --- a/app/lib/FireflyIII/Report/Report.php +++ b/app/lib/FireflyIII/Report/Report.php @@ -7,12 +7,12 @@ use FireflyIII\Database\Account\Account as AccountRepository; use FireflyIII\Database\SwitchUser; use FireflyIII\Database\TransactionJournal\TransactionJournal as JournalRepository; use Illuminate\Database\Query\Builder; -use Illuminate\Database\Query\JoinClause; use Illuminate\Support\Collection; /** - * Class Report + * @SuppressWarnings("CamelCase") // I'm fine with this. * + * Class Report * * @package FireflyIII\Report */ @@ -45,6 +45,8 @@ class Report implements ReportInterface } /** + * This methods fails to take in account transfers FROM shared accounts. + * * @param Carbon $start * @param Carbon $end * @param int $limit @@ -115,7 +117,7 @@ class Report implements ReportInterface $accounts = []; /** @var \Account $account */ foreach ($list as $account) { - $id = intval($account->id); + $id = intval($account->id); /** @noinspection PhpParamsInspection */ $accounts[$id] = [ 'name' => $account->name, @@ -205,18 +207,18 @@ class Report implements ReportInterface $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']; - } +// $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); @@ -226,6 +228,10 @@ class Report implements ReportInterface } /** + * This method gets all incomes (journals) in a list. + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param Carbon $date * @param bool $shared * @@ -239,46 +245,48 @@ class Report implements ReportInterface $end->endOfMonth(); $userId = $this->_accounts->getUser()->id; + return $this->_queries->incomeByPeriod($start, $end); - $list = \TransactionJournal::leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id') - ->leftJoin( - 'account_meta', function (JoinClause $join) { - $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); - } - ) - ->transactionTypes(['Deposit']) - ->where('transaction_journals.user_id', $userId) - ->where('transactions.amount', '>', 0) - ->where('transaction_journals.user_id', \Auth::user()->id) - ->where('account_meta.data', '!=', '"sharedExpense"') - ->orderBy('date', 'ASC') - ->before($end)->after($start)->get(['transaction_journals.*']); + // $list = \TransactionJournal::leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + // ->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id') + // ->leftJoin( + // 'account_meta', function (JoinClause $join) { + // $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); + // } + // ) + // ->transactionTypes(['Deposit']) + // ->where('transaction_journals.user_id', $userId) + // ->where('transactions.amount', '>', 0) + // ->where('transaction_journals.user_id', \Auth::user()->id) + // ->where('account_meta.data', '!=', '"sharedExpense"') + // ->orderBy('date', 'ASC') + // ->before($end)->after($start)->get(['transaction_journals.*']); + // + // // incoming from a shared account: it's profit (income): + // $transfers = \TransactionJournal::withRelevantData() + // ->leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + // ->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id') + // ->leftJoin( + // 'account_meta', function (JoinClause $join) { + // $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); + // } + // ) + // ->transactionTypes(['Transfer']) + // ->where('transaction_journals.user_id', $userId) + // ->where('transactions.amount', '<', 0) + // ->where('account_meta.data', '=', '"sharedExpense"') + // ->orderBy('date', 'ASC') + // ->before($end)->after($start)->get(['transaction_journals.*']); + // + // $list = $list->merge($transfers); + // $list->sort( + // function (\TransactionJournal $journal) { + // return $journal->date->format('U'); + // } + // ); + // + // return $list; - // incoming from a shared account: it's profit (income): - $transfers = \TransactionJournal::withRelevantData() - ->leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id') - ->leftJoin( - 'account_meta', function (JoinClause $join) { - $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); - } - ) - ->transactionTypes(['Transfer']) - ->where('transaction_journals.user_id', $userId) - ->where('transactions.amount', '<', 0) - ->where('account_meta.data', '=', '"sharedExpense"') - ->orderBy('date', 'ASC') - ->before($end)->after($start)->get(['transaction_journals.*']); - - $list = $list->merge($transfers); - $list->sort( - function (\TransactionJournal $journal) { - return $journal->date->format('U'); - } - ); - - return $list; } /** @@ -295,21 +303,21 @@ class Report implements ReportInterface \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.*']); + ->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.*']); } @@ -353,6 +361,7 @@ class Report implements ReportInterface } /** + * * @param Carbon $start * @param Carbon $end * @param int $limit @@ -361,8 +370,7 @@ class Report implements ReportInterface */ public function revenueGroupedByAccount(Carbon $start, Carbon $end, $limit = 15) { - return $this->_queries->journalsByRevenueAccount($start, $end); - + return $this->_queries->journalsByRevenueAccount($start, $end, $limit); } @@ -387,7 +395,7 @@ class Report implements ReportInterface $sharedAccounts[] = $account->id; } - $accounts = $this->_accounts->getAssetAccounts()->filter( + $accounts = $this->_accounts->getAccountsByType(['Default account', 'Asset account'])->filter( function (\Account $account) use ($sharedAccounts) { if (!in_array($account->id, $sharedAccounts)) { return $account; diff --git a/app/lib/FireflyIII/Report/ReportQuery.php b/app/lib/FireflyIII/Report/ReportQuery.php index 1a143cbb44..113bcaaffe 100644 --- a/app/lib/FireflyIII/Report/ReportQuery.php +++ b/app/lib/FireflyIII/Report/ReportQuery.php @@ -68,16 +68,13 @@ class ReportQuery implements ReportQueryInterface } ) ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'otherJournals.id') - ->before($end) - ->after($start) + ->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('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') + ->whereNotNull('transaction_group_transaction_journal.transaction_group_id')->groupBy('transaction_journals.id') ->get( [ 'transaction_journals.id as transferId', @@ -202,6 +199,70 @@ class ReportQuery implements ReportQueryInterface } + /** + * 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. * @@ -278,6 +339,8 @@ class ReportQuery implements ReportQueryInterface * 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 * @@ -309,8 +372,25 @@ class ReportQuery implements ReportQueryInterface } ) ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->where('transaction_types.type', 'Withdrawal') - ->where('acm_from.data', '!=', '"sharedExpense"') + + ->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) @@ -324,10 +404,11 @@ class ReportQuery implements ReportQueryInterface * * @param Carbon $start * @param Carbon $end + * @param int $limit * * @return Collection */ - public function journalsByRevenueAccount(Carbon $start, Carbon $end) + public function journalsByRevenueAccount(Carbon $start, Carbon $end, $limit = 15) { return \TransactionJournal:: leftJoin( @@ -353,8 +434,22 @@ class ReportQuery implements ReportQueryInterface } ) ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->where('transaction_types.type', 'Deposit') - ->where('acm_to.data', '!=', '"sharedExpense"') + ->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') diff --git a/app/lib/FireflyIII/Report/ReportQueryInterface.php b/app/lib/FireflyIII/Report/ReportQueryInterface.php index a2097c6635..046835b843 100644 --- a/app/lib/FireflyIII/Report/ReportQueryInterface.php +++ b/app/lib/FireflyIII/Report/ReportQueryInterface.php @@ -117,6 +117,18 @@ interface ReportQueryInterface */ public function journalsByRevenueAccount(Carbon $start, Carbon $end); + /** + * 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); + /** * With an equally misleading name, this query returns are transfers to shared accounts. These are considered * expenses. diff --git a/app/lib/FireflyIII/Search/Search.php b/app/lib/FireflyIII/Search/Search.php index 859d83b7b4..4a5d429634 100644 --- a/app/lib/FireflyIII/Search/Search.php +++ b/app/lib/FireflyIII/Search/Search.php @@ -80,6 +80,8 @@ class Search } /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param array $words * * @return Collection diff --git a/app/lib/FireflyIII/Shared/Mail/Registration.php b/app/lib/FireflyIII/Shared/Mail/Registration.php index 4a8367c408..62f98eefe9 100644 --- a/app/lib/FireflyIII/Shared/Mail/Registration.php +++ b/app/lib/FireflyIII/Shared/Mail/Registration.php @@ -3,6 +3,8 @@ namespace FireflyIII\Shared\Mail; use Swift_RfcComplianceException; use Illuminate\Mail\Message; +use Swift_TransportException; + /** * Class Registration * @@ -57,7 +59,16 @@ class Registration implements RegistrationInterface } ); } 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; } @@ -84,7 +95,16 @@ class Registration implements RegistrationInterface } ); } 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/Toolkit/Date.php b/app/lib/FireflyIII/Shared/Toolkit/Date.php index 3f7b321216..65d1d49ab9 100644 --- a/app/lib/FireflyIII/Shared/Toolkit/Date.php +++ b/app/lib/FireflyIII/Shared/Toolkit/Date.php @@ -13,7 +13,7 @@ use FireflyIII\Exception\FireflyException; class Date { /** - * @param Carbon $theDate + * @param Carbon $theDate * @param $repeatFreq * @param $skip * @@ -25,41 +25,37 @@ class Date $date = clone $theDate; $add = ($skip + 1); - switch ($repeatFreq) { - default: - throw new FireflyException('Cannot do addPeriod for $repeat_freq "' . $repeatFreq . '"'); - break; - case 'daily': - $date->addDays($add); - break; - case 'week': - case 'weekly': - $date->addWeeks($add); - break; - case 'month': - case 'monthly': - $date->addMonths($add); - break; - case 'quarter': - case 'quarterly': - $months = $add * 3; - $date->addMonths($months); - break; - case 'half-year': - $months = $add * 6; - $date->addMonths($months); - break; - case 'year': - case 'yearly': - $date->addYears($add); - break; + $functionMap = [ + 'daily' => 'addDays', + 'weekly' => 'addWeeks', + 'week' => 'addWeeks', + 'month' => 'addMonths', + 'monthly' => 'addMonths', + 'quarter' => 'addMonths', + 'quarterly' => 'addMonths', + 'half-year' => 'addMonths', + 'year' => 'addYears', + 'yearly' => 'addYears', + ]; + $modifierMap = [ + 'quarter' => 3, + 'quarterly' => 3, + 'half-year' => 6, + ]; + if (!isset($functionMap[$repeatFreq])) { + throw new FireflyException('Cannot do addPeriod for $repeat_freq "' . $repeatFreq . '"'); } + if (isset($modifierMap[$repeatFreq])) { + $add = $add * $modifierMap[$repeatFreq]; + } + $function = $functionMap[$repeatFreq]; + $date->$function($add); return $date; } /** - * @param Carbon $theCurrentEnd + * @param Carbon $theCurrentEnd * @param $repeatFreq * * @return Carbon @@ -68,78 +64,81 @@ class Date public function endOfPeriod(Carbon $theCurrentEnd, $repeatFreq) { $currentEnd = clone $theCurrentEnd; - switch ($repeatFreq) { - default: - throw new FireflyException('Cannot do endOfPeriod for $repeat_freq ' . $repeatFreq); - break; - case 'daily': - $currentEnd->addDay(); - break; - case 'week': - case 'weekly': - $currentEnd->addWeek()->subDay(); - break; - case 'month': - case 'monthly': - $currentEnd->addMonth()->subDay(); - break; - case 'quarter': - case 'quarterly': - $currentEnd->addMonths(3)->subDay(); - break; - case 'half-year': - $currentEnd->addMonths(6)->subDay(); - break; - case 'year': - case 'yearly': - $currentEnd->addYear()->subDay(); - break; + + $functionMap = [ + 'daily' => 'addDay', + 'week' => 'addWeek', + 'weekly' => 'addWeek', + 'month' => 'addMonth', + 'monthly' => 'addMonth', + 'quarter' => 'addMonths', + 'quarterly' => 'addMonths', + 'half-year' => 'addMonths', + 'year' => 'addYear', + 'yearly' => 'addYear', + ]; + $modifierMap = [ + 'quarter' => 3, + 'quarterly' => 3, + 'half-year' => 6, + ]; + + $subDay = ['week', 'weekly', 'month', 'monthly', 'quarter', 'quarterly', 'half-year', 'year', 'yearly']; + + if (!isset($functionMap[$repeatFreq])) { + throw new FireflyException('Cannot do endOfPeriod for $repeat_freq ' . $repeatFreq); + } + $function = $functionMap[$repeatFreq]; + if (isset($modifierMap[$repeatFreq])) { + $currentEnd->$function($modifierMap[$repeatFreq]); + } else { + $currentEnd->$function(); + } + if (in_array($repeatFreq, $subDay)) { + $currentEnd->subDay(); } return $currentEnd; } /** - * @param Carbon $theCurrentEnd + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * + * @param Carbon $theCurrentEnd * @param $repeatFreq - * @param Carbon $maxDate + * @param Carbon $maxDate * * @return Carbon * @throws FireflyException */ public function endOfX(Carbon $theCurrentEnd, $repeatFreq, Carbon $maxDate) { + $functionMap = [ + 'daily' => 'endOfDay', + 'week' => 'endOfWeek', + 'weekly' => 'endOfWeek', + 'month' => 'endOfMonth', + 'monthly' => 'endOfMonth', + 'quarter' => 'lastOfQuarter', + 'quarterly' => 'lastOfQuarter', + 'year' => 'endOfYear', + 'yearly' => 'endOfYear', + ]; + $specials = ['mont', 'monthly']; + $currentEnd = clone $theCurrentEnd; - switch ($repeatFreq) { - default: - throw new FireflyException('Cannot do endOfPeriod for $repeat_freq ' . $repeatFreq); - break; - case 'daily': - $currentEnd->endOfDay(); - break; - case 'week': - case 'weekly': - $currentEnd->endOfWeek(); - break; - case 'month': - case 'monthly': - $currentEnd->endOfMonth(); - break; - case 'quarter': - case 'quarterly': - $currentEnd->lastOfQuarter(); - break; - case 'half-year': - $month = intval($theCurrentEnd->format('m')); - $currentEnd->endOfYear(); - if ($month <= 6) { - $currentEnd->subMonths(6); - } - break; - case 'year': - case 'yearly': - $currentEnd->endOfYear(); - break; + + if (isset($functionMap[$repeatFreq])) { + $function = $functionMap[$repeatFreq]; + $currentEnd->$function(); + + } + if (isset($specials[$repeatFreq])) { + $month = intval($theCurrentEnd->format('m')); + $currentEnd->endOfYear(); + if ($month <= 6) { + $currentEnd->subMonths(6); + } } if ($currentEnd > $maxDate) { return clone $maxDate; @@ -149,7 +148,7 @@ class Date } /** - * @param Carbon $date + * @param Carbon $date * @param $repeatFrequency * * @return string @@ -157,33 +156,25 @@ class Date */ public function periodShow(Carbon $date, $repeatFrequency) { - switch ($repeatFrequency) { - default: - throw new FireflyException('No date formats for frequency "' . $repeatFrequency . '"!'); - break; - case 'daily': - return $date->format('j F Y'); - break; - case 'week': - case 'weekly': - return $date->format('\W\e\e\k W, Y'); - break; - case 'quarter': - return $date->format('F Y'); - break; - case 'monthly': - case 'month': - return $date->format('F Y'); - break; - case 'year': - case 'yearly': - return $date->format('Y'); - break; + $formatMap = [ + 'daily' => 'j F Y', + 'week' => '\W\e\e\k W, Y', + 'weekly' => '\W\e\e\k W, Y', + 'quarter' => 'F Y', + 'month' => 'F Y', + 'monthly' => 'F Y', + 'year' => 'Y', + 'yearly' => 'Y', + + ]; + if (isset($formatMap[$repeatFrequency])) { + return $date->format($formatMap[$repeatFrequency]); } + throw new FireflyException('No date formats for frequency "' . $repeatFrequency . '"!'); } /** - * @param Carbon $theDate + * @param Carbon $theDate * @param $repeatFreq * * @return Carbon @@ -192,43 +183,38 @@ class Date public function startOfPeriod(Carbon $theDate, $repeatFreq) { $date = clone $theDate; - switch ($repeatFreq) { - default: - throw new FireflyException('Cannot do startOfPeriod for $repeat_freq ' . $repeatFreq); - break; - case 'daily': - $date->startOfDay(); - break; - case 'week': - case 'weekly': - $date->startOfWeek(); - break; - case 'month': - case 'monthly': - $date->startOfMonth(); - break; - case 'quarter': - case 'quarterly': - $date->firstOfQuarter(); - break; - case 'half-year': - $month = intval($date->format('m')); - $date->startOfYear(); - if ($month >= 7) { - $date->addMonths(6); - } - break; - case 'year': - case 'yearly': - $date->startOfYear(); - break; - } - return $date; + $functionMap = [ + 'daily' => 'startOfDay', + 'week' => 'startOfWeek', + 'weekly' => 'startOfWeek', + 'month' => 'startOfMonth', + 'monthly' => 'startOfMonth', + 'quarter' => 'firstOfQuarter', + 'quartly' => 'firstOfQuarter', + 'year' => 'startOfYear', + 'yearly' => 'startOfYear', + ]; + if (isset($functionMap[$repeatFreq])) { + $function = $functionMap[$repeatFreq]; + $date->$function(); + + return $date; + } + if ($repeatFreq == 'half-year') { + $month = intval($date->format('m')); + $date->startOfYear(); + if ($month >= 7) { + $date->addMonths(6); + } + + return $date; + } + throw new FireflyException('Cannot do startOfPeriod for $repeat_freq ' . $repeatFreq); } /** - * @param Carbon $theDate + * @param Carbon $theDate * @param $repeatFreq * @param int $subtract * @@ -238,38 +224,35 @@ class Date public function subtractPeriod(Carbon $theDate, $repeatFreq, $subtract = 1) { $date = clone $theDate; - switch ($repeatFreq) { - default: - throw new FireflyException('Cannot do subtractPeriod for $repeat_freq ' . $repeatFreq); - break; - case 'day': - case 'daily': - $date->subDays($subtract); - break; - case 'week': - case 'weekly': - $date->subWeeks($subtract); - break; - case 'month': - case 'monthly': - $date->subMonths($subtract); - break; - case 'quarter': - case 'quarterly': - $months = $subtract * 3; - $date->subMonths($months); - break; - case 'half-year': - $months = $subtract * 6; - $date->subMonths($months); - break; - case 'year': - case 'yearly': - $date->subYears($subtract); - break; + + $functionMap = [ + 'daily' => 'subDays', + 'week' => 'subWeeks', + 'weekly' => 'subWeeks', + 'month' => 'subMonths', + 'monthly' => 'subMonths', + 'year' => 'subYears', + 'yearly' => 'subYears', + ]; + $modifierMap = [ + 'quarter' => 3, + 'quarterly' => 3, + 'half-year' => 6, + ]; + if (isset($functionMap[$repeatFreq])) { + $function = $functionMap[$repeatFreq]; + $date->$function($subtract); + + return $date; + } + if (isset($modifierMap[$repeatFreq])) { + $subtract = $subtract * $modifierMap[$repeatFreq]; + $date->subMonths($subtract); + + return $date; } - return $date; + throw new FireflyException('Cannot do subtractPeriod for $repeat_freq ' . $repeatFreq); } } diff --git a/app/lib/FireflyIII/Shared/Toolkit/Filter.php b/app/lib/FireflyIII/Shared/Toolkit/Filter.php index 9be82e313a..70f0aef677 100644 --- a/app/lib/FireflyIII/Shared/Toolkit/Filter.php +++ b/app/lib/FireflyIII/Shared/Toolkit/Filter.php @@ -69,36 +69,29 @@ class Filter */ protected function updateStartDate($range, Carbon $start) { - switch ($range) { - default: - throw new FireflyException('updateStartDate cannot handle $range ' . $range); - break; - case '1D': - $start->startOfDay(); - break; - case '1W': - $start->startOfWeek(); - break; - case '1M': - $start->startOfMonth(); - break; - case '3M': - $start->firstOfQuarter(); - break; - case '6M': - if (intval($start->format('m')) >= 7) { - $start->startOfYear()->addMonths(6); - } else { - $start->startOfYear(); - } - break; - case '1Y': - $start->startOfYear(); - break; + $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; - + return $start; + } + throw new FireflyException('updateStartDate cannot handle $range ' . $range); } /** @@ -110,40 +103,36 @@ class Filter */ protected function updateEndDate($range, Carbon $start) { - $end = clone $start; - switch ($range) { - default: - throw new FireflyException('updateEndDate cannot handle $range ' . $range); - break; - case '1D': - $end->endOfDay(); - break; - case '1W': - $end->endOfWeek(); - break; - case '1M': - $end->endOfMonth(); - break; - case '3M': - $end->lastOfQuarter(); - break; - case '6M': - if (intval($start->format('m')) >= 7) { - $end->endOfYear(); - } else { - $end->startOfYear()->addMonths(6); - } - break; - case '1Y': - $end->endOfYear(); - break; + $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; + 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 * @@ -152,37 +141,28 @@ class Filter */ protected function periodName($range, Carbon $date) { - switch ($range) { - default: - throw new FireflyException('No _periodName() for range "' . $range . '"'); - break; - case '1D': - return $date->format('jS F Y'); - break; - case '1W': - return 'week ' . $date->format('W, Y'); - break; - case '1M': - return $date->format('F Y'); - break; - case '3M': - $month = intval($date->format('m')); - - return 'Q' . ceil(($month / 12) * 4) . ' ' . $date->format('Y'); - break; - case '6M': - $month = intval($date->format('m')); - $half = ceil(($month / 12) * 2); - $halfName = $half == 1 ? 'first' : 'second'; - - return $halfName . ' half of ' . $date->format('d-m-Y'); - break; - case '1Y': - return $date->format('Y'); - break; - - + $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 . '"'); } /** @@ -194,37 +174,35 @@ class Filter */ public function previous($range, Carbon $date) { - switch ($range) { - default: - throw new FireflyException('Cannot do _previous() on ' . $range); - break; - case '1D': - $date->startOfDay()->subDay(); - break; - case '1W': - $date->startOfWeek()->subWeek(); - break; - case '1M': - $date->startOfMonth()->subMonth(); - break; - case '3M': - $date->firstOfQuarter()->subMonths(3)->firstOfQuarter(); - break; - case '6M': - $month = intval($date->format('m')); - if ($month <= 6) { - $date->startOfYear()->subMonths(6); - } else { - $date->startOfYear(); - } - break; - case '1Y': - $date->startOfYear()->subYear(); - break; + $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; + 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); } /** diff --git a/app/lib/FireflyIII/Shared/Toolkit/Form.php b/app/lib/FireflyIII/Shared/Toolkit/Form.php index 55457dc7d5..1f51fe357a 100644 --- a/app/lib/FireflyIII/Shared/Toolkit/Form.php +++ b/app/lib/FireflyIII/Shared/Toolkit/Form.php @@ -12,6 +12,8 @@ use Illuminate\Support\Collection; class Form { /** + * @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 @@ -32,7 +34,7 @@ class Form $title = null; foreach ($fields as $field) { - if (is_null($title) && isset($entry->$field)) { + if (isset($entry->$field)) { $title = $entry->$field; } } diff --git a/app/lib/FireflyIII/Shared/Toolkit/Reminders.php b/app/lib/FireflyIII/Shared/Toolkit/Reminders.php index fe3b40ed9b..11b75259e1 100644 --- a/app/lib/FireflyIII/Shared/Toolkit/Reminders.php +++ b/app/lib/FireflyIII/Shared/Toolkit/Reminders.php @@ -15,6 +15,8 @@ class Reminders { /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * * @param \Reminder $reminder * * @return int @@ -62,6 +64,9 @@ class Reminders return $reminders; } + /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + */ public function updateReminders() { /** @var Collection $set */ diff --git a/app/lib/FireflyIII/Shared/Toolkit/Steam.php b/app/lib/FireflyIII/Shared/Toolkit/Steam.php index 2a2696372f..584fa13ee8 100644 --- a/app/lib/FireflyIII/Shared/Toolkit/Steam.php +++ b/app/lib/FireflyIII/Shared/Toolkit/Steam.php @@ -35,6 +35,7 @@ class Steam } /** + * @codeCoverageIgnore * @param $boolean * * @return string @@ -61,12 +62,18 @@ class Steam { $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(); diff --git a/app/lib/FireflyIII/Shared/Validation/FireflyValidator.php b/app/lib/FireflyIII/Shared/Validation/FireflyValidator.php index 544174a1c5..33795d563b 100644 --- a/app/lib/FireflyIII/Shared/Validation/FireflyValidator.php +++ b/app/lib/FireflyIII/Shared/Validation/FireflyValidator.php @@ -11,6 +11,8 @@ use Illuminate\Validation\Validator; class FireflyValidator extends Validator { /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * * @param $attribute * @param $value * @param $parameters diff --git a/app/models/Account.php b/app/models/Account.php index 667aae069e..ad2f43d875 100644 --- a/app/models/Account.php +++ b/app/models/Account.php @@ -1,10 +1,10 @@ ['required', 'between:1,100'], 'user_id' => 'required|exists:users,id', 'account_type_id' => 'required|exists:account_types,id', 'active' => 'required|boolean' ]; - protected $dates = ['deleted_at', 'created_at', 'updated_at']; - protected $fillable = ['name', 'user_id', 'account_type_id', 'active']; + protected $dates = ['deleted_at', 'created_at', 'updated_at']; + protected $fillable = ['name', 'user_id', 'account_type_id', 'active']; /** * Account type. @@ -67,7 +67,7 @@ class Account extends Eloquent /** * * @param EloquentBuilder $query - * @param array $types + * @param array $types */ public function scopeAccountTypeIn(EloquentBuilder $query, array $types) { @@ -82,9 +82,13 @@ class Account extends Eloquent * * @param EloquentBuilder $query */ - public function scopeWithMeta(EloquentBuilder $query) + public function scopeWithMeta(EloquentBuilder $query, $field = 'accountRole') { - $query->with(['accountmeta']); + $query->leftJoin( + 'account_meta', function (JoinClause $join) use ($field) { + $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', $field); + } + ); } /** diff --git a/app/models/Bill.php b/app/models/Bill.php index 00d7d2c1e4..bc5500ebe2 100644 --- a/app/models/Bill.php +++ b/app/models/Bill.php @@ -1,5 +1,4 @@ 'required|exists:transaction_types,id', 'transaction_currency_id' => 'required|exists:transaction_currencies,id', - 'description' => 'required|between:1,255', + 'description' => 'required|between:1,1024', 'date' => 'required|date', 'completed' => 'required|between:0,1']; @@ -82,6 +82,15 @@ class TransactionJournal extends Eloquent return ['created_at', 'updated_at', 'date']; } + public function getDescriptionAttribute($value) + { + if ($this->encrypted) { + return Crypt::decrypt($value); + } + + return $value; + } + /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ @@ -198,6 +207,12 @@ class TransactionJournal extends Eloquent ); } + public function setDescriptionAttribute($value) + { + $this->attributes['description'] = Crypt::encrypt($value); + $this->attributes['encrypted'] = true; + } + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/app/routes.php b/app/routes.php index 94f89f51b5..1f534f5811 100644 --- a/app/routes.php +++ b/app/routes.php @@ -204,7 +204,7 @@ Route::group( 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.noBudget']); + Route::get('/categories/list/noCategory', ['uses' => 'CategoryController@noCategory', 'as' => 'categories.noCategory']); // currency controller Route::get('/currency', ['uses' => 'CurrencyController@index', 'as' => 'currency.index']); @@ -222,11 +222,13 @@ Route::group( 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/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']); + 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/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 diff --git a/app/tests/TestCase.php b/app/tests/TestCase.php index e2e0cce790..3ad0086e9c 100644 --- a/app/tests/TestCase.php +++ b/app/tests/TestCase.php @@ -9,7 +9,9 @@ use League\FactoryMuffin\Facade as f; class TestCase extends Illuminate\Foundation\Testing\TestCase { /** - * Creates the application. + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * + * Creates the application.. * * @return \Symfony\Component\HttpKernel\HttpKernelInterface */ diff --git a/app/tests/factories/PiggyBank.php b/app/tests/factories/PiggyBank.php index 36f89debf8..aaab88cd71 100644 --- a/app/tests/factories/PiggyBank.php +++ b/app/tests/factories/PiggyBank.php @@ -15,8 +15,12 @@ League\FactoryMuffin\Facade::define( return $set[rand(0, count($set) - 1)]; }, - 'rep_every' => function() {return rand(0,3);}, - 'rep_times' => function() {return rand(0,3);}, + 'rep_every' => function () { + return rand(0, 3); + }, + 'rep_times' => function () { + return rand(0, 3); + }, 'reminder' => function () { $set = ['day', 'week', 'quarter', 'month', 'year']; diff --git a/app/tests/factories/Transaction.php b/app/tests/factories/Transaction.php index 9f812b8ce0..39f50f7ca5 100644 --- a/app/tests/factories/Transaction.php +++ b/app/tests/factories/Transaction.php @@ -5,8 +5,8 @@ League\FactoryMuffin\Facade::define( 'account_id' => 'factory|Account', 'transaction_journal_id' => 'factory|TransactionJournal', 'description' => 'sentence', - 'amount' => function() { - return round(rand(100,10000) / 100,2); + 'amount' => function () { + return round(rand(100, 10000) / 100, 2); } ] ); diff --git a/app/views/accounts/create.blade.php b/app/views/accounts/create.blade.php index 8fc3f78c5a..b8e6701b05 100644 --- a/app/views/accounts/create.blade.php +++ b/app/views/accounts/create.blade.php @@ -29,9 +29,9 @@
@if($what == 'asset') - {{Form::ffBalance('openingbalance')}} - {{Form::ffDate('openingbalancedate', date('Y-m-d'))}} - @endif + {{Form::ffBalance('openingBalance')}} + {{Form::ffDate('openingBalanceDate', date('Y-m-d'))}} + @endif {{Form::ffCheckbox('active','1',true)}} {{Form::ffSelect('account_role',Config::get('firefly.accountRoles'))}}
diff --git a/app/views/accounts/edit.blade.php b/app/views/accounts/edit.blade.php index 547068fae8..45737070a9 100644 --- a/app/views/accounts/edit.blade.php +++ b/app/views/accounts/edit.blade.php @@ -26,7 +26,7 @@
{{Form::ffCheckbox('active','1')}} @if($account->accounttype->type == 'Default account' || $account->accounttype->type == 'Asset account') - {{Form::ffBalance('openingBalance')}} + {{Form::ffBalance('openingBalance',null, ['currency' => $openingBalance->transactionCurrency])}} {{Form::ffDate('openingBalanceDate')}} {{Form::ffSelect('account_role',Config::get('firefly.accountRoles'))}} @endif diff --git a/app/views/accounts/show.blade.php b/app/views/accounts/show.blade.php index e5b4fc9e04..69d93d900b 100644 --- a/app/views/accounts/show.blade.php +++ b/app/views/accounts/show.blade.php @@ -6,6 +6,21 @@
{{{$account->name}}} + + + +
+
+ + +
+
diff --git a/app/views/budgets/show.blade.php b/app/views/budgets/show.blade.php index b6c35c646d..7378d42146 100644 --- a/app/views/budgets/show.blade.php +++ b/app/views/budgets/show.blade.php @@ -8,7 +8,7 @@ Overview
-
+
@@ -71,7 +71,8 @@ @stop @section('scripts') + + + + + + + + + + + + + + + + + + @@ -91,6 +109,7 @@ {{HTML::script('assets/javascript/metisMenu/jquery.metisMenu.min.js')}} {{HTML::script('assets/javascript/sb-admin/sb-admin-2.js')}} {{HTML::script('assets/javascript/firefly/help.js')}} +{{HTML::script('assets/javascript/firefly/firefly.js')}} @yield('scripts') diff --git a/app/views/layouts/guest.blade.php b/app/views/layouts/guest.blade.php index 6b5a7d023b..006619c34c 100644 --- a/app/views/layouts/guest.blade.php +++ b/app/views/layouts/guest.blade.php @@ -18,7 +18,23 @@ - + + + + + + + + + + + + + + + + + diff --git a/app/views/list/categories.blade.php b/app/views/list/categories.blade.php index 29e6d7e27f..c12a88762c 100644 --- a/app/views/list/categories.blade.php +++ b/app/views/list/categories.blade.php @@ -4,6 +4,11 @@ Name Last activity + +   + Without a category +   + @foreach($categories as $category) diff --git a/app/views/list/journals-small.blade.php b/app/views/list/journals-small.blade.php index 9bf33f4b0b..b1ba57dacf 100644 --- a/app/views/list/journals-small.blade.php +++ b/app/views/list/journals-small.blade.php @@ -9,24 +9,28 @@ transactions[1]->amount);?> @if($journal->transactiontype->type == 'Withdrawal') - {{Amount::formatTransaction($journal->transactions[1],false)}} + {{Amount::formatTransaction($journal->transactions[1],false)}} @endif @if($journal->transactiontype->type == 'Deposit') - {{Amount::formatTransaction($journal->transactions[1],false)}} + {{Amount::formatTransaction($journal->transactions[1],false)}} @endif @if($journal->transactiontype->type == 'Transfer') - {{Amount::formatTransaction($journal->transactions[1],false)}} + {{Amount::formatTransaction($journal->transactions[1],false)}} @endif {{$journal->date->format('j F Y')}} - @if($journal->transactions[1]->account->accounttype->description == 'Cash account') - (cash) - @else - {{{$journal->transactions[1]->account->name}}} - @endif + @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 @endforeach diff --git a/app/views/partials/menu.blade.php b/app/views/partials/menu.blade.php index 05ed6c3bbd..07c825d9e3 100644 --- a/app/views/partials/menu.blade.php +++ b/app/views/partials/menu.blade.php @@ -177,7 +177,7 @@ Transfer
  • - Bills + Bill
  • diff --git a/app/views/reports/month.blade.php b/app/views/reports/month.blade.php index c60d473d62..6943a09ba8 100644 --- a/app/views/reports/month.blade.php +++ b/app/views/reports/month.blade.php @@ -5,7 +5,41 @@
    Income
    - @include('list.journals-small',['journals' => $income]) + + + @foreach($income as $entry) + + + + + + + @endforeach + @if(isset($displaySum) && $displaySum === true) + + + + + + @endif +
    + {{{$entry->description}}} + + amount);?> + @if($entry->type == 'Withdrawal') + {{Amount::format($entry->amount,false)}} + @endif + @if($entry->type == 'Deposit') + {{Amount::format($entry->amount,false)}} + @endif + @if($entry->type == 'Transfer') + {{Amount::format($entry->amount,false)}} + @endif + + {{$entry->date->format('j F Y')}} + + {{{$entry->name}}} +
    Sum{{Amount::format($tableSum)}}
    diff --git a/app/views/reports/year.blade.php b/app/views/reports/year.blade.php index 130f29ec55..f82304d469 100644 --- a/app/views/reports/year.blade.php +++ b/app/views/reports/year.blade.php @@ -123,17 +123,22 @@ Expenses
    + @foreach($groupedExpenses as $id => $expense) + @endforeach + + + +
    {{{$expense['name']}}} {{Amount::format(floatval($expense['amount'])*-1)}}
    Sum{{Amount::format($sum)}}
    -
    @@ -141,12 +146,13 @@ Budgets
    - +
    + @stop @section('scripts') diff --git a/app/views/transactions/edit.blade.php b/app/views/transactions/edit.blade.php index 0b60dd357e..0996995257 100644 --- a/app/views/transactions/edit.blade.php +++ b/app/views/transactions/edit.blade.php @@ -36,7 +36,7 @@ @endif - {{Form::ffAmount('amount',$data['amount'])}} + {{Form::ffAmount('amount',$data['amount'],['currency' => $journal->transactionCurrency])}} {{Form::ffDate('date',$data['date'])}} diff --git a/build/logs/.gitignore b/build/logs/.gitignore new file mode 100644 index 0000000000..b81c7954b7 --- /dev/null +++ b/build/logs/.gitignore @@ -0,0 +1 @@ +*.xml \ No newline at end of file diff --git a/composer.json b/composer.json index cac222a065..f06c862101 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "require-dev": { "barryvdh/laravel-debugbar": "@stable", "barryvdh/laravel-ide-helper": "@stable", - "satooshi/php-coveralls": "dev-master", + "satooshi/php-coveralls": "*", "mockery/mockery": "@stable", "league/factory-muffin": "~2.1", "codeception/codeception": "*", @@ -41,7 +41,8 @@ "codeception/phpbuiltinserver": "*", "codeception/specify": "*", "codeception/verify": "*", - "fzaninotto/faker": "1.*" + "fzaninotto/faker": "1.*", + "codeclimate/php-test-reporter": "dev-master" }, diff --git a/favicon-full.png b/favicon-full.png new file mode 100644 index 0000000000..a3ff22c6fe Binary files /dev/null and b/favicon-full.png differ diff --git a/public/android-chrome-144x144.png b/public/android-chrome-144x144.png new file mode 100644 index 0000000000..cb899b91b9 Binary files /dev/null and b/public/android-chrome-144x144.png differ diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png new file mode 100644 index 0000000000..9c6c8b08a5 Binary files /dev/null and b/public/android-chrome-192x192.png differ diff --git a/public/android-chrome-36x36.png b/public/android-chrome-36x36.png new file mode 100644 index 0000000000..cfc31e42c3 Binary files /dev/null and b/public/android-chrome-36x36.png differ diff --git a/public/android-chrome-48x48.png b/public/android-chrome-48x48.png new file mode 100644 index 0000000000..d137a6d806 Binary files /dev/null and b/public/android-chrome-48x48.png differ diff --git a/public/android-chrome-72x72.png b/public/android-chrome-72x72.png new file mode 100644 index 0000000000..c65517d0af Binary files /dev/null and b/public/android-chrome-72x72.png differ diff --git a/public/android-chrome-96x96.png b/public/android-chrome-96x96.png new file mode 100644 index 0000000000..6268a69d57 Binary files /dev/null and b/public/android-chrome-96x96.png differ diff --git a/public/android-chrome-manifest.json b/public/android-chrome-manifest.json new file mode 100644 index 0000000000..b07eb63253 --- /dev/null +++ b/public/android-chrome-manifest.json @@ -0,0 +1,41 @@ +{ + "name": "My app", + "icons": [ + { + "src": "\/android-chrome-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": "\/android-chrome-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": "\/android-chrome-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "\/android-chrome-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + { + "src": "\/android-chrome-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": "3.0" + }, + { + "src": "\/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": "4.0" + } + ] +} diff --git a/public/apple-touch-icon-114x114.png b/public/apple-touch-icon-114x114.png new file mode 100644 index 0000000000..dd30aa6b84 Binary files /dev/null and b/public/apple-touch-icon-114x114.png differ diff --git a/public/apple-touch-icon-120x120.png b/public/apple-touch-icon-120x120.png new file mode 100644 index 0000000000..666bb9ea99 Binary files /dev/null and b/public/apple-touch-icon-120x120.png differ diff --git a/public/apple-touch-icon-144x144.png b/public/apple-touch-icon-144x144.png new file mode 100644 index 0000000000..cb899b91b9 Binary files /dev/null and b/public/apple-touch-icon-144x144.png differ diff --git a/public/apple-touch-icon-152x152.png b/public/apple-touch-icon-152x152.png new file mode 100644 index 0000000000..6ed26769ee Binary files /dev/null and b/public/apple-touch-icon-152x152.png differ diff --git a/public/apple-touch-icon-180x180.png b/public/apple-touch-icon-180x180.png new file mode 100644 index 0000000000..02dac915b3 Binary files /dev/null and b/public/apple-touch-icon-180x180.png differ diff --git a/public/apple-touch-icon-57x57.png b/public/apple-touch-icon-57x57.png new file mode 100644 index 0000000000..cb1900eb20 Binary files /dev/null and b/public/apple-touch-icon-57x57.png differ diff --git a/public/apple-touch-icon-60x60.png b/public/apple-touch-icon-60x60.png new file mode 100644 index 0000000000..4d45fcbed0 Binary files /dev/null and b/public/apple-touch-icon-60x60.png differ diff --git a/public/apple-touch-icon-72x72.png b/public/apple-touch-icon-72x72.png new file mode 100644 index 0000000000..c65517d0af Binary files /dev/null and b/public/apple-touch-icon-72x72.png differ diff --git a/public/apple-touch-icon-76x76.png b/public/apple-touch-icon-76x76.png new file mode 100644 index 0000000000..13639d6ee6 Binary files /dev/null and b/public/apple-touch-icon-76x76.png differ diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png new file mode 100644 index 0000000000..699993e810 Binary files /dev/null and b/public/apple-touch-icon-precomposed.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000000..02dac915b3 Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/assets/javascript/firefly/budgets.js b/public/assets/javascript/firefly/budgets.js index 968c17c0a8..e8a856cf4a 100644 --- a/public/assets/javascript/firefly/budgets.js +++ b/public/assets/javascript/firefly/budgets.js @@ -7,11 +7,11 @@ $(function () { $('.updateIncome').on('click', updateIncome); - if (typeof componentID != 'undefined' && typeof repetitionID == 'undefined') { - googleColumnChart('chart/budget/' + componentID + '/spending/' + year, 'componentOverview'); + if (typeof budgetID != 'undefined' && typeof repetitionID == 'undefined') { + googleColumnChart('chart/budget/' + budgetID + '/spending', 'budgetOverview'); } - if (typeof componentID != 'undefined' && typeof repetitionID != 'undefined') { - googleLineChart('chart/budget/' + componentID + '/' + repetitionID, 'componentOverview'); + if (typeof budgetID != 'undefined' && typeof repetitionID != 'undefined') { + googleLineChart('chart/budget/' + budgetID + '/' + repetitionID, 'budgetOverview'); } }); diff --git a/public/assets/javascript/firefly/firefly.js b/public/assets/javascript/firefly/firefly.js new file mode 100644 index 0000000000..871eb221b4 --- /dev/null +++ b/public/assets/javascript/firefly/firefly.js @@ -0,0 +1,24 @@ +$(function () { + + $('.currencySelect').click(currencySelect) + +}); + +function currencySelect(e) { + var target = $(e.target); + var symbol = target.data('symbol'); + var code = target.data('code'); + var id = target.data('id'); + var fieldType = target.data('field'); + var menu = $('.' + fieldType + 'CurrencyDropdown'); + + var symbolHolder = $('#' + fieldType + 'CurrentSymbol'); + symbolHolder.text(symbol); + $('input[name="' + fieldType + '_currency_id"]').val(id); + + // close dropdown (hack hack) + menu.click(); + + + return false; +} \ No newline at end of file diff --git a/public/assets/javascript/firefly/gcharts.js b/public/assets/javascript/firefly/gcharts.js index a7538fb977..92d1067fa4 100644 --- a/public/assets/javascript/firefly/gcharts.js +++ b/public/assets/javascript/firefly/gcharts.js @@ -1,7 +1,8 @@ +var google = google || {}; google.load('visualization', '1.1', {'packages': ['corechart', 'bar', 'sankey', 'table']}); -function googleLineChart(URL, container, options) { - if ($('#' + container).length == 1) { +function googleChart(chartType, URL, container, options) { + if ($('#' + container).length === 1) { $.getJSON(URL).success(function (data) { /* Get the data from the JSON @@ -16,19 +17,45 @@ function googleLineChart(URL, container, options) { groupingSymbol: '.', prefix: currencyCode + ' ' }); - for (i = 1; i < gdata.getNumberOfColumns(); i++) { + for (var i = 1; i < gdata.getNumberOfColumns(); i++) { money.format(gdata, i); } /* Create a new google charts object. */ - var chart = new google.visualization.LineChart(document.getElementById(container)); + var chart = false + var options = false; + if (chartType === 'line') { + chart = new google.visualization.LineChart(document.getElementById(container)); + options = options || defaultLineChartOptions; + } + if (chartType === 'column') { + chart = new google.charts.Bar(document.getElementById(container)); + options = options || defaultColumnChartOptions; + } + if (chartType === 'pie') { + chart = new google.visualization.PieChart(document.getElementById(container)); + options = options || defaultPieChartOptions; + } + if (chartType === 'bar') { + chart = new google.charts.Bar(document.getElementById(container)); + options = options || defaultBarChartOptions; + } + if (chartType === 'stackedColumn') { + chart = new google.visualization.ColumnChart(document.getElementById(container)); + options = options || defaultStackedColumnChartOptions; + } + if (chartType === 'combo') { + chart = new google.visualization.ComboChart(document.getElementById(container)); + options = options || defaultComboChartOptions; + } - /* - Draw it: - */ - chart.draw(gdata, options || defaultLineChartOptions); + if (chart === false) { + alert('Cannot draw chart of type "' + chartType + '".'); + } else { + chart.draw(gdata, options); + } }).fail(function () { $('#' + container).addClass('google-chart-error'); @@ -38,152 +65,27 @@ function googleLineChart(URL, container, options) { } } + +function googleLineChart(URL, container, options) { + return googleChart('line', URL, container, options); +} + function googleBarChart(URL, container, options) { - if ($('#' + container).length == 1) { - $.getJSON(URL).success(function (data) { - /* - Get the data from the JSON - */ - gdata = new google.visualization.DataTable(data); - - /* - Format as money - */ - var money = new google.visualization.NumberFormat({ - decimalSymbol: ',', - groupingSymbol: '.', - prefix: currencyCode + ' ' - }); - for (i = 1; i < gdata.getNumberOfColumns(); i++) { - money.format(gdata, i); - } - - /* - Create a new google charts object. - */ - var chart = new google.charts.Bar(document.getElementById(container)); - - /* - Draw it: - */ - chart.draw(gdata, options || defaultBarChartOptions); - - }).fail(function () { - $('#' + container).addClass('google-chart-error'); - }); - } else { - console.log('No container found called "' + container + '"'); - } + return googleChart('bar', URL, container, options); } function googleColumnChart(URL, container, options) { - if ($('#' + container).length == 1) { - $.getJSON(URL).success(function (data) { - /* - Get the data from the JSON - */ - gdata = new google.visualization.DataTable(data); + return googleChart('column', URL, container, options); +} - /* - Format as money - */ - var money = new google.visualization.NumberFormat({ - decimalSymbol: ',', - groupingSymbol: '.', - prefix: currencyCode + ' ' - }); - for (i = 1; i < gdata.getNumberOfColumns(); i++) { - money.format(gdata, i); - } - - /* - Create a new google charts object. - */ - var chart = new google.charts.Bar(document.getElementById(container)); - /* - Draw it: - */ - chart.draw(gdata, options || defaultColumnChartOptions); - - }).fail(function () { - $('#' + container).addClass('google-chart-error'); - }); - } else { - console.log('No container found called "' + container + '"'); - } +function googleStackedColumnChart(URL, container, options) { + return googleChart('stackedColumn', URL, container, options); } function googleComboChart(URL, container, options) { - if ($('#' + container).length == 1) { - $.getJSON(URL).success(function (data) { - /* - Get the data from the JSON - */ - gdata = new google.visualization.DataTable(data); - - /* - Format as money - */ - var money = new google.visualization.NumberFormat({ - decimalSymbol: ',', - groupingSymbol: '.', - prefix: currencyCode + ' ' - }); - for (i = 1; i < gdata.getNumberOfColumns(); i++) { - money.format(gdata, i); - } - - /* - Create a new google charts object. - */ - var chart = new google.visualization.ComboChart(document.getElementById(container)); - /* - Draw it: - */ - chart.draw(gdata, options || defaultComboChartOptions); - - }).fail(function () { - $('#' + container).addClass('google-chart-error'); - }); - } else { - console.log('No container found called "' + container + '"'); - } + return googleChart('combo', URL, container, options); } function googlePieChart(URL, container, options) { - if ($('#' + container).length == 1) { - $.getJSON(URL).success(function (data) { - /* - Get the data from the JSON - */ - gdata = new google.visualization.DataTable(data); - - /* - Format as money - */ - var money = new google.visualization.NumberFormat({ - decimalSymbol: ',', - groupingSymbol: '.', - prefix: currencyCode + ' ' - }); - for (i = 1; i < gdata.getNumberOfColumns(); i++) { - money.format(gdata, i); - } - - /* - Create a new google charts object. - */ - var chart = new google.visualization.PieChart(document.getElementById(container)); - - /* - Draw it: - */ - chart.draw(gdata, options || defaultPieChartOptions); - - }).fail(function () { - $('#' + container).addClass('google-chart-error'); - }); - } else { - console.log('No container found called "' + container + '"'); - } + return googleChart('pie', URL, container, options); } diff --git a/public/assets/javascript/firefly/gcharts.options.js b/public/assets/javascript/firefly/gcharts.options.js index 3c1ec5a131..4efba8ffd1 100644 --- a/public/assets/javascript/firefly/gcharts.options.js +++ b/public/assets/javascript/firefly/gcharts.options.js @@ -96,20 +96,11 @@ var defaultStackedColumnChartOptions = { width: '85%', height: '80%' }, - vAxis: {format: '\u20AC #'}, legend: { position: 'none' }, isStacked: true, colors: ["#4285f4", "#db4437", "#f4b400", "#0f9d58", "#ab47bc", "#00acc1", "#ff7043", "#9e9d24", "#5c6bc0", "#f06292", "#00796b", "#c2185b"], - vAxis: { - textStyle: { - color: '#838383', - fontName: 'Roboto2', - fontSize: '12' - }, - format: '\u20AC #' - }, hAxis: { textStyle: { color: '#838383', @@ -120,6 +111,14 @@ var defaultStackedColumnChartOptions = { color: 'transparent' } }, + vAxis: { + textStyle: { + color: '#838383', + fontName: 'Roboto2', + fontSize: '12' + }, + format: '\u20AC #' + } }; var defaultPieChartOptions = { diff --git a/public/assets/javascript/firefly/reports.js b/public/assets/javascript/firefly/reports.js index 3ef9f9326d..4dee6cbbdd 100644 --- a/public/assets/javascript/firefly/reports.js +++ b/public/assets/javascript/firefly/reports.js @@ -3,5 +3,7 @@ if (typeof(google) != 'undefined') { function drawChart() { googleColumnChart('chart/reports/income-expenses/' + year, 'income-expenses-chart'); googleColumnChart('chart/reports/income-expenses-sum/' + year, 'income-expenses-sum-chart') + + googleStackedColumnChart('chart/budgets/spending/' + year, 'budgets'); } } \ No newline at end of file diff --git a/public/browserconfig.xml b/public/browserconfig.xml new file mode 100644 index 0000000000..587f54d577 --- /dev/null +++ b/public/browserconfig.xml @@ -0,0 +1,12 @@ + + + + + + + + + #2b5797 + + + diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 0000000000..08abefd086 Binary files /dev/null and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png new file mode 100644 index 0000000000..fddcf169ef Binary files /dev/null and b/public/favicon-32x32.png differ diff --git a/public/favicon-96x96.png b/public/favicon-96x96.png new file mode 100644 index 0000000000..6268a69d57 Binary files /dev/null and b/public/favicon-96x96.png differ diff --git a/public/favicon.ico b/public/favicon.ico index e69de29bb2..9b084caf61 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/mstile-144x144.png b/public/mstile-144x144.png new file mode 100644 index 0000000000..8de5d12a7c Binary files /dev/null and b/public/mstile-144x144.png differ diff --git a/public/mstile-150x150.png b/public/mstile-150x150.png new file mode 100644 index 0000000000..4a01bc08e4 Binary files /dev/null and b/public/mstile-150x150.png differ diff --git a/public/mstile-310x150.png b/public/mstile-310x150.png new file mode 100644 index 0000000000..6e7fa3a485 Binary files /dev/null and b/public/mstile-310x150.png differ diff --git a/public/mstile-310x310.png b/public/mstile-310x310.png new file mode 100644 index 0000000000..42bafce4b6 Binary files /dev/null and b/public/mstile-310x310.png differ diff --git a/public/mstile-70x70.png b/public/mstile-70x70.png new file mode 100644 index 0000000000..d0766d378b Binary files /dev/null and b/public/mstile-70x70.png differ diff --git a/tests/functional/AccountControllerCest.php b/tests/functional/AccountControllerCest.php index 35ea055806..8848523ed6 100644 --- a/tests/functional/AccountControllerCest.php +++ b/tests/functional/AccountControllerCest.php @@ -114,6 +114,21 @@ class AccountControllerCest $I->seeRecord('accounts', ['name' => 'New through tests.']); } + /** + * @param FunctionalTester $I + */ + public function storeOpeningBalance(FunctionalTester $I) + { + $I->amOnPage('/accounts/create/asset'); + $I->wantTo('store a new asset account with a balance'); + $I->see('Create a new asset account'); + $I->submitForm('#store', ['name' => 'New through tests with balance.', + 'openingBalance' => 10, + 'openingBalanceDate' => '2015-01-01', + 'what' => 'asset', 'account_role' => 'defaultExpense', 'post_submit_action' => 'store']); + $I->seeRecord('accounts', ['name' => 'New through tests with balance.']); + } + /** * @param FunctionalTester $I */ diff --git a/tests/functional/BudgetControllerCest.php b/tests/functional/BudgetControllerCest.php index a81c7e0b33..35c97692e1 100644 --- a/tests/functional/BudgetControllerCest.php +++ b/tests/functional/BudgetControllerCest.php @@ -105,6 +105,16 @@ class BudgetControllerCest $I->see('Budgets'); } + /** + * @param FunctionalTester $I + */ + public function indexNoBudget(FunctionalTester $I) + { + $I->wantTo('see transactions without a budget'); + $I->amOnPage('/budgets/list/noBudget'); + $I->see('Transactions without a budget in'); + } + /** * @param FunctionalTester $I */ diff --git a/tests/functional/CategoryControllerCest.php b/tests/functional/CategoryControllerCest.php index 3a7b5d10ba..cef60dee22 100644 --- a/tests/functional/CategoryControllerCest.php +++ b/tests/functional/CategoryControllerCest.php @@ -86,6 +86,15 @@ class CategoryControllerCest $I->wantTo('show all categories'); $I->amOnPage('/categories'); } + /** + * @param FunctionalTester $I + */ + public function indexNoCategory(FunctionalTester $I) + { + $I->wantTo('see transactions without a category'); + $I->amOnPage('/categories/list/noCategory'); + $I->see('Transactions without a category in'); + } /** * @param FunctionalTester $I diff --git a/tests/functional/GoogleChartControllerCest.php b/tests/functional/GoogleChartControllerCest.php index 578204b153..a570d9214d 100644 --- a/tests/functional/GoogleChartControllerCest.php +++ b/tests/functional/GoogleChartControllerCest.php @@ -108,23 +108,11 @@ class GoogleChartControllerCest */ public function budgetsAndSpending(FunctionalTester $I) { - $year = date('Y'); $I->wantTo('see the chart for a budget in a specific year'); - $I->amOnPage('/chart/budget/1/spending/'.$year); + $I->amOnPage('/chart/budget/1/spending'); $I->seeResponseCodeIs(200); } - /** - * @param FunctionalTester $I - */ - public function budgetsAndSpendingInvalidYear(FunctionalTester $I) - { - $I->wantTo('see the chart for a budget in an invalid year'); - $I->amOnPage('/chart/budget/1/spending/XXXX'); - $I->seeResponseCodeIs(200); - $I->see('Invalid year'); - } - /** * @param FunctionalTester $I */ diff --git a/tests/functional/PiggyBankControllerCest.php b/tests/functional/PiggyBankControllerCest.php index fc00a93005..c0651993e8 100644 --- a/tests/functional/PiggyBankControllerCest.php +++ b/tests/functional/PiggyBankControllerCest.php @@ -193,6 +193,30 @@ class PiggyBankControllerCest 'account_id' => 1, 'targetamount' => 1000] ); $I->see('Piggy bank "Some new piggy bank" stored.'); + $I->seeRecord('piggy_banks', ['name' => 'Some new piggy bank']); + } + + /** + * @param FunctionalTester $I + */ + public function storeValidate(FunctionalTester $I) + { + $I->wantTo('validate a new piggy bank'); + $I->amOnPage('/piggy_banks/create'); + $I->see('Create new piggy bank'); + $I->submitForm( + '#store', ['name' => 'Some new piggy bank validated', + 'rep_every' => 0, + 'reminder_skip' => 0, + 'remind_me' => 0, + 'order' => 3, + 'post_submit_action' => 'validate_only', + 'account_id' => 1, + 'targetamount' => 1000] + ); + $I->see('OK'); + $I->seeInSession('successes'); + $I->dontSeeRecord('piggy_banks', ['name' => 'Some new piggy bank validated']); } /** diff --git a/tests/functional/RepeatedExpenseControllerCest.php b/tests/functional/RepeatedExpenseControllerCest.php index 58d2392ee2..b93ff8263b 100644 --- a/tests/functional/RepeatedExpenseControllerCest.php +++ b/tests/functional/RepeatedExpenseControllerCest.php @@ -117,6 +117,33 @@ class RepeatedExpenseControllerCest $I->see('Piggy bank "TestRepeatedExpense" stored.'); } + /** + * @param FunctionalTester $I + */ + public function storeValidate(FunctionalTester $I) + { + $I->wantTo('validate a repeated expense'); + $I->amOnPage('/repeatedexpenses/create'); + $I->submitForm( + '#store', [ + 'name' => 'TestRepeatedExpenseXX', + 'account_id' => 1, + 'targetamount' => 1000, + 'targetdate' => Carbon::now()->format('Y-m-d'), + 'rep_length' => 'month', + 'rep_every' => 0, + 'rep_times' => 0, + 'remind_me' => 1, + 'reminder' => 'month', + 'post_submit_action' => 'validate_only', + ] + ); + + $I->see('TestRepeatedExpenseXX'); + $I->see('OK'); + $I->seeInSession('successes'); + } + /** * @param FunctionalTester $I */ @@ -192,6 +219,33 @@ class RepeatedExpenseControllerCest $I->see('Repeated expense "' . $repeatedExpense->name . '!" updated.'); } + /** + * @param FunctionalTester $I + */ + public function updateValidate(FunctionalTester $I) + { + $repeatedExpense = PiggyBank::where('repeats', 1)->first(); + $I->wantTo('validate an updated repeated expense'); + $I->amOnPage('/repeatedexpenses/edit/' . $repeatedExpense->id); + $I->submitForm( + '#update', [ + 'name' => $repeatedExpense->name . 'ABCD', + 'account_id' => 2, + 'targetamount' => 1000.00, + 'targetdate' => $repeatedExpense->targetdate->format('Y-m-d'), + 'rep_length' => 'month', + 'rep_every' => 0, + 'rep_times' => 0, + 'remind_me' => 1, + 'reminder' => 'month', + 'post_submit_action' => 'validate_only', + ] + ); + $I->see($repeatedExpense->name . 'ABCD'); + $I->see('OK'); + $I->seeInSession('successes'); + } + /** * @param FunctionalTester $I */ diff --git a/tests/functional/TransactionControllerCest.php b/tests/functional/TransactionControllerCest.php index fa7caccfd5..f9e40d8062 100644 --- a/tests/functional/TransactionControllerCest.php +++ b/tests/functional/TransactionControllerCest.php @@ -29,7 +29,11 @@ class TransactionControllerCest public function deleteWithdrawal(FunctionalTester $I) { - $journal = TransactionJournal::where('description', 'LIKE', '%Rent for %')->first(); + // get withdrawal transaction type id: + $type = TransactionType::whereType('Withdrawal')->first(); + + // get a journal + $journal = TransactionJournal::where('transaction_type_id', $type->id)->first(); $I->wantTo('delete a transaction'); $I->amOnPage('/transaction/delete/' . $journal->id); $I->see('Delete withdrawal "' . $journal->description . '"'); @@ -37,7 +41,11 @@ class TransactionControllerCest public function destroyDeposit(FunctionalTester $I) { - $journal = TransactionJournal::where('description', 'LIKE', '%Salary for %')->first(); + // get withdrawal transaction type id: + $type = TransactionType::whereType('Deposit')->first(); + + // get a journal + $journal = TransactionJournal::where('transaction_type_id', $type->id)->first(); $I->wantTo('destroy a deposit'); $I->amOnPage('/transaction/delete/' . $journal->id); $I->submitForm('#destroy', []); @@ -47,9 +55,13 @@ class TransactionControllerCest public function destroyTransfer(FunctionalTester $I) { - $I->wantTo('destroy a transfer'); + // get withdrawal transaction type id: + $type = TransactionType::whereType('Transfer')->first(); - $journal = TransactionJournal::where('description', 'LIKE', '%Money for big expense in%')->first(); + // get a journal + $journal = TransactionJournal::where('transaction_type_id', $type->id)->first(); + + $I->wantTo('destroy a transfer'); $I->amOnPage('/transaction/delete/' . $journal->id); $I->submitForm('#destroy', []); @@ -59,7 +71,12 @@ class TransactionControllerCest public function destroyWithdrawal(FunctionalTester $I) { - $journal = TransactionJournal::where('description', 'LIKE', '%Rent for %')->first(); + // get withdrawal transaction type id: + $type = TransactionType::whereType('Withdrawal')->first(); + + // get a journal + $journal = TransactionJournal::where('transaction_type_id', $type->id)->first(); + $I->wantTo('destroy a withdrawal'); $I->amOnPage('/transaction/delete/' . $journal->id); $I->submitForm('#destroy', []); @@ -69,10 +86,15 @@ class TransactionControllerCest public function edit(FunctionalTester $I) { - $journal = TransactionJournal::whereDescription('Money for piggy')->first(); + // get withdrawal transaction type id: + $type = TransactionType::whereType('Transfer')->first(); + + // get a journal + $journal = TransactionJournal::where('transaction_type_id', $type->id)->first(); + $I->wantTo('edit a transaction'); $I->amOnPage('/transaction/edit/' . $journal->id); - $I->see('Edit transfer "Money for piggy"'); + $I->see('Edit transfer "' . $journal->description . '"'); } public function index(FunctionalTester $I) @@ -98,7 +120,11 @@ class TransactionControllerCest public function show(FunctionalTester $I) { - $journal = TransactionJournal::where('description', 'LIKE', '%Rent for %')->first(); + // get withdrawal transaction type id: + $type = TransactionType::whereType('Withdrawal')->first(); + + // get a journal + $journal = TransactionJournal::where('transaction_type_id', $type->id)->first(); $I->wantTo('see a transaction'); $I->amOnPage('/transaction/show/' . $journal->id); @@ -106,15 +132,22 @@ class TransactionControllerCest $I->see(intval($journal->getAmount())); } + /** + * @param FunctionalTester $I + */ public function showGroupedJournal(FunctionalTester $I) { - $journal = TransactionJournal::where('description', 'LIKE', 'Big expense in %')->first(); + $groupRow = DB::table('transaction_group_transaction_journal')->select('transaction_journal_id')->first(['transaction_journal_id']); + + $id = $groupRow->transaction_journal_id; + + // get a grouped journal: + $journal = TransactionJournal::find($id); $I->wantTo('see a grouped transaction'); $I->amOnPage('/transaction/show/' . $journal->id); $I->see($journal->description); - $I->see('Money for '.$journal->description); } public function store(FunctionalTester $I) @@ -177,9 +210,35 @@ class TransactionControllerCest $I->see('Transaction "Test" stored.'); } + public function storeValidate(FunctionalTester $I) + { + $I->wantTo('validate a transaction'); + $I->amOnPage('/transactions/create/withdrawal'); + $I->submitForm( + '#store', [ + 'reminder' => '', + 'description' => 'TestValidateMe', + 'account_id' => 1, + 'expense_account' => 'Zomaar', + 'amount' => 100, + 'date' => '2014-12-30', + 'budget_id' => 3, + 'category' => 'CategorrXXXXr', + 'post_submit_action' => 'validate_only' + ] + ); + $I->see('OK'); + $I->seeInSession('successes'); + $I->dontSeeRecord('transaction_journals', ['description' => 'TestValidateMe']); + } + public function update(FunctionalTester $I) { - $journal = TransactionJournal::where('description', 'LIKE', '%Salary for %')->first(); + // get withdrawal transaction type id: + $type = TransactionType::whereType('Deposit')->first(); + + // get a journal + $journal = TransactionJournal::where('transaction_type_id', $type->id)->first(); $I->wantTo('update a transaction'); $I->amOnPage('/transaction/edit/' . $journal->id); @@ -201,7 +260,11 @@ class TransactionControllerCest public function updateAndFail(FunctionalTester $I) { - $journal = TransactionJournal::where('description', 'LIKE', '%Salary for %')->first(); + // get withdrawal transaction type id: + $type = TransactionType::whereType('Deposit')->first(); + + // get a journal + $journal = TransactionJournal::where('transaction_type_id', $type->id)->first(); $I->wantTo('update a transaction and fail'); $I->amOnPage('/transaction/edit/' . $journal->id); @@ -223,7 +286,11 @@ class TransactionControllerCest public function updateAndReturn(FunctionalTester $I) { - $journal = TransactionJournal::where('description', 'LIKE', '%Salary for %')->first(); + // get withdrawal transaction type id: + $type = TransactionType::whereType('Deposit')->first(); + + // get a journal + $journal = TransactionJournal::where('transaction_type_id', $type->id)->first(); $I->wantTo('update a transaction and return to the edit screen'); $I->amOnPage('/transaction/edit/' . $journal->id); $I->see($journal->description); @@ -242,5 +309,33 @@ class TransactionControllerCest $I->see($journal->description . '!'); } + public function updateValidate(FunctionalTester $I) + { + // get withdrawal transaction type id: + $type = TransactionType::whereType('Deposit')->first(); + + // get a journal + $journal = TransactionJournal::where('transaction_type_id', $type->id)->first(); + + $I->wantTo('validate an updated transaction'); + $I->amOnPage('/transaction/edit/' . $journal->id); + $I->see($journal->description); + $I->submitForm( + '#update', [ + 'description' => $journal->description . 'XYZ', + 'account_id' => 1, + 'expense_account' => 'Portaal', + 'amount' => 500, + 'date' => $journal->date->format('Y-m-d'), + 'budget_id' => is_null($journal->budgets()->first()) ? 0 : $journal->budgets()->first()->id, + 'category' => is_null($journal->categories()->first()) ? '' : $journal->categories()->first()->id, + 'post_submit_action' => 'validate_only' + ] + ); + $I->see($journal->description . 'XYZ'); + $I->see('OK'); + $I->seeInSession('successes'); + } + }