Compare commits

..

186 Commits
3.2.1 ... 3.2.5

Author SHA1 Message Date
James Cole
b243ed93aa Merge branch 'release/3.2.5' 2015-01-31 06:35:37 +01:00
James Cole
3c76da7132 Update version in readme file. 2015-01-31 06:35:19 +01:00
James Cole
3254565c09 Seed only in test [skip ci] 2015-01-31 06:34:31 +01:00
James Cole
cd0033791f New SQL reference for 3.2.5 [skip ci] 2015-01-31 06:34:10 +01:00
James Cole
2427ee44a5 Updated travis to handle SSL errors when communicating with Code climate. 2015-01-31 06:29:45 +01:00
James Cole
ff0e617b2a This triggers CC 2015-01-31 06:21:40 +01:00
James Cole
e6cfe040b5 Clean up some javascript, small fix for the test reporter 2015-01-31 06:11:55 +01:00
James Cole
94e2f9b6dc Updated tests to understand encrypted database content. 2015-01-30 22:43:52 +01:00
James Cole
512b81ad93 Fixed some tests. 2015-01-30 22:32:12 +01:00
James Cole
fc0e76f431 Some new seeds and the ability to search encrypted transaction journals. 2015-01-30 22:24:02 +01:00
James Cole
9da69358e2 Included code for code climate. 2015-01-30 22:09:47 +01:00
James Cole
aa246b0b2b New full set of favicon. 2015-01-30 21:40:37 +01:00
James Cole
6ed649bc8a Update list of what currency support there is in Firefly. 2015-01-30 18:40:30 +01:00
James Cole
725f5b7110 Creating and editing an account now allows the opening balance to be set in a certain currency. Issue #37 2015-01-30 18:22:55 +01:00
James Cole
5a890c5c3a It is now possible to select a different currency if desired (issue #37). 2015-01-30 18:09:13 +01:00
James Cole
7752329b94 Fixed a bug where the rules where too tight in transaction journal. 2015-01-29 18:21:56 +01:00
James Cole
5f48f13890 Exceptions for stupid sqlite. 2015-01-29 17:44:13 +01:00
James Cole
a734e04561 Default value and rename for encrypted field values. 2015-01-29 17:31:18 +01:00
James Cole
5aa1db293f 3.2.5 will once again be capable of encrypting journal descriptions (and more, in the future). 2015-01-29 05:23:31 +01:00
James Cole
f89aee37f5 Fixed a bug where the referer might not be picked up correctly. 2015-01-29 05:11:00 +01:00
James Cole
538018fed1 Should fix query [skip ci] 2015-01-27 19:22:54 +01:00
James Cole
a2327c50ec Should fix query [skip ci] 2015-01-27 19:19:44 +01:00
James Cole
c2711023e2 Updated query, lets see what happens [skip ci] 2015-01-27 18:52:59 +01:00
James Cole
cac30f0b4c Updated code coverage. 2015-01-25 15:29:09 +01:00
James Cole
4bb17019a4 Test transaction views for transactions without budgets and categories. 2015-01-25 13:17:32 +01:00
James Cole
ba2a40bdf3 Removed unused methods. 2015-01-25 12:21:56 +01:00
James Cole
f3460cca49 Ignore methods in code coverage that are not implemented. 2015-01-25 11:36:34 +01:00
James Cole
64ce53ac30 Test for opening balance. 2015-01-25 10:55:15 +01:00
James Cole
a43238360c Update caps. 2015-01-25 10:50:44 +01:00
James Cole
b2cbadf5d8 New chart route. 2015-01-25 10:06:31 +01:00
James Cole
81640ba06d Revamped and simplified form code. 2015-01-25 10:06:19 +01:00
James Cole
9327430484 Small optimalizations. 2015-01-25 08:28:59 +01:00
James Cole
a24c90eae8 Other redirects [skip ci] 2015-01-24 21:27:07 +01:00
James Cole
1d3987ece6 Fixed the tests. 2015-01-24 17:58:03 +01:00
James Cole
83f5b5e293 New budget charts for year report. 2015-01-24 08:54:33 +01:00
James Cole
f231263085 Updated chart, closed magic number issue. 2015-01-24 08:43:35 +01:00
James Cole
4ad67a87f1 Fixed budget charts. 2015-01-24 07:46:57 +01:00
James Cole
b766d93d9a Fixed the account role view. 2015-01-24 07:15:03 +01:00
James Cole
0905ceb1d5 Codeception will not run in hhvm [skip ci] 2015-01-24 07:00:58 +01:00
James Cole
2fbf837354 Closed #40 [skip ci] 2015-01-24 06:56:02 +01:00
James Cole
4bd79c880c Build in hack. 2015-01-24 06:55:42 +01:00
James Cole
4af041e015 Let's see what happens when we run Hack. 2015-01-24 06:52:22 +01:00
James Cole
8dc3e3ec93 Add an actions menu to the account view. 2015-01-23 06:50:40 +01:00
James Cole
f4b68d26d6 Fixed a bug where a deposit would not get linked to a cash account. 2015-01-23 06:45:20 +01:00
James Cole
1887977b92 Small experimental cleaning up. 2015-01-19 07:21:44 +01:00
James Cole
8eb84acf4f Show the view for transactions without a category. 2015-01-19 06:33:30 +01:00
James Cole
1b685da3e3 Code cleanup and query optimisation. 2015-01-18 21:40:00 +01:00
James Cole
406b658801 Code cleanup. 2015-01-18 21:07:40 +01:00
James Cole
bba1ee1264 Last attempt. 2015-01-18 11:18:06 +01:00
James Cole
02b6191d47 Another attempt at catching the sqlite error. 2015-01-18 11:12:17 +01:00
James Cole
c5a3de09cd Catch a sqlite error. 2015-01-18 10:33:01 +01:00
James Cole
0afe2a680e Gave report a subtitle. 2015-01-18 09:50:51 +01:00
James Cole
03e0510c4f Fixed a bug where certain reports would not show incomes from shared accounts. 2015-01-18 09:49:53 +01:00
James Cole
1068dcb8a4 Cleanup and refactor 2015-01-18 09:49:32 +01:00
James Cole
10a93df653 Clean up test data seeder 2015-01-18 09:48:58 +01:00
James Cole
79ff67852f Deleted an old unique index. 2015-01-18 09:48:48 +01:00
James Cole
a36cab969f Code cleanup. 2015-01-18 09:48:36 +01:00
James Cole
45447646fa Code cleanup. 2015-01-18 09:48:29 +01:00
James Cole
8a0f76ab68 Code cleanup. 2015-01-18 09:48:24 +01:00
James Cole
037135e764 A complete gamble on my side to fix a bug where transfers FROM shared accounts were not counted as income. 2015-01-18 00:10:57 +01:00
James Cole
21e89c3b64 Remove composer.lock when running Travis. 2015-01-17 11:31:12 +01:00
James Cole
bd11ec69fa Reinstated test data seeder, fixed the tests. 2015-01-17 10:41:29 +01:00
James Cole
9e2b34bc12 Various cleanup. 2015-01-17 10:06:12 +01:00
James Cole
0faebc290f Suppress warnings. 2015-01-17 10:05:51 +01:00
James Cole
fc0ef4b79d Small optimizations. 2015-01-17 10:05:43 +01:00
James Cole
027b954b50 Cleanup various factories and libraries. 2015-01-17 08:58:49 +01:00
James Cole
33c830a432 Cleaned up seeders. 2015-01-17 08:58:30 +01:00
James Cole
a7887f1e25 Added inspections for all migrations. 2015-01-17 08:58:19 +01:00
James Cole
fa7a59572a Code cleanup for all controllers. 2015-01-17 08:57:55 +01:00
James Cole
d9c2df5b0d Removed unused methods. 2015-01-17 07:33:43 +01:00
James Cole
a854b2c17e Some code cleanup in the account code. 2015-01-17 07:25:44 +01:00
James Cole
7d4006b205 Fixed some bugs while registering users. 2015-01-17 07:14:01 +01:00
James Cole
86ecca6011 Removed weird config values. 2015-01-16 07:11:03 +01:00
James Cole
0ea5cf2caa Merge branch 'master' of github.com:JC5/firefly-iii
Conflicts:
	app/config/app.php
2015-01-16 07:09:46 +01:00
James Cole
a950e02e9b Revert "Cleanup in preparation of an overhaul."
This reverts commit 5662a02a36.
2015-01-16 07:08:56 +01:00
James Cole
9eec6641dd Cleanup in preparation of an overhaul. 2015-01-16 07:08:56 +01:00
James Cole
18f46676fd Bug fix in new accounts. 2015-01-16 07:08:56 +01:00
James Cole
9735ef6d41 Revert "Cleanup in preparation of an overhaul."
This reverts commit 5662a02a36.
2015-01-16 07:07:57 +01:00
James Cole
d3e8ceee00 Cleanup in preparation of an overhaul. 2015-01-14 12:24:08 +01:00
James Cole
144e329eca Merge branch 'release/3.2.4'
Conflicts:
	app/config/app.php
2015-01-13 20:44:40 +01:00
James Cole
21d5420b2a Bug fix in new accounts. 2015-01-13 20:43:54 +01:00
James Cole
3011b5074d Merge branch 'release/3.2.3' 2015-01-13 19:08:33 +01:00
James Cole
83190572c7 New composer.lock 2015-01-10 18:07:39 +01:00
James Cole
9cf9e5f865 Added a missing field. 2015-01-05 20:22:39 +01:00
James Cole
5bdef7f1c7 Added a missing field. 2015-01-05 20:22:19 +01:00
James Cole
ba285a2d2d Added a missing field. 2015-01-05 20:21:43 +01:00
James Cole
0dff371e62 Added a missing field. 2015-01-05 20:20:03 +01:00
James Cole
ce4a2a5851 Added a missing field. 2015-01-05 20:19:34 +01:00
James Cole
2c978dc89a Removed experimental routes. 2015-01-05 17:53:38 +01:00
James Cole
4b8b819109 Redirect update. 2015-01-04 20:50:35 +01:00
James Cole
c230b3a806 This broke the tests. 2015-01-03 18:09:44 +01:00
James Cole
df08b9c5c6 Updated composer.lock 2015-01-03 13:46:53 +01:00
James Cole
eca65376a3 Fixed a route. 2015-01-03 09:25:40 +01:00
James Cole
88e3705636 Do some redirection. 2015-01-02 22:47:34 +01:00
James Cole
5476509ef5 Disabled some seeds, updated some routes. 2015-01-02 22:44:25 +01:00
James Cole
0bd6636453 SQL reference file [skip ci] 2015-01-02 20:04:26 +01:00
James Cole
105894e00d Small bug in budget helper [skip ci] 2015-01-02 19:53:09 +01:00
James Cole
230a319510 Removed files no longer used [skip ci] 2015-01-02 18:52:55 +01:00
James Cole
ae16a2b14f Routes and views for transactions without a budget / category [skip ci] 2015-01-02 18:48:06 +01:00
James Cole
da0c0742bf Covered some more lines of code. 2015-01-02 13:57:40 +01:00
James Cole
61d60a9048 Updated read me [skip ci] 2015-01-02 12:56:07 +01:00
James Cole
3e28e9a016 Merge branch 'release/3.2.2' 2015-01-02 12:53:44 +01:00
James Cole
423f9fefa9 Removed todo entries and made issues instead. [skip ci] 2015-01-02 12:42:29 +01:00
James Cole
5707dc7579 Lots of cleaning up. 2015-01-02 12:38:13 +01:00
James Cole
3be1cdb249 Some cleaning up in the reports. [skip ci] 2015-01-02 11:04:51 +01:00
James Cole
426d3d948c Added newlines [skip ci] 2015-01-02 10:55:59 +01:00
James Cole
9a3aed8038 Moved code to relate transfers to another class. Still needs some work. 2015-01-02 10:53:18 +01:00
James Cole
fb58bf1bf5 Cleaned up some todo entries [skip ci] 2015-01-02 10:01:33 +01:00
James Cole
a6dbd912c6 Code cleanup. 2015-01-02 09:06:44 +01:00
James Cole
65ce277a20 Updated models [skip ci] 2015-01-02 08:59:16 +01:00
James Cole
0b2d423c87 Updated ignore file. 2015-01-02 06:26:57 +01:00
James Cole
da056092fb Code cleanup [skip ci] 2015-01-02 06:26:04 +01:00
James Cole
45aa85d690 Added new lines [skip ci] 2015-01-02 06:24:48 +01:00
James Cole
5c35fee0c2 New lines at end of file [skip ci] 2015-01-02 06:16:49 +01:00
James Cole
24bdc319dd Some refactoring [skip ci] 2015-01-02 06:05:40 +01:00
James Cole
f1dcc41e42 Removed invalid composer.json entry [skip ci] 2015-01-02 06:00:14 +01:00
James Cole
550f301ba2 Code cleanup [skip ci] 2015-01-02 05:52:38 +01:00
James Cole
d9bf4d1c0d Removed c3.php from lib. [skip ci] 2015-01-02 05:37:25 +01:00
James Cole
c3c1a6eb22 Changed permissions [skip ci] 2015-01-02 05:36:49 +01:00
James Cole
2c4454418e Remove possible xsrf [skip ci] 2015-01-02 05:36:05 +01:00
James Cole
e44de572f5 Code cleanup [skip ci] 2015-01-01 23:12:12 +01:00
James Cole
f27919f91b Fixed transaction journal test. 2015-01-01 22:57:15 +01:00
James Cole
ba9968bde0 Fixed a bug in "number between" tests. 2015-01-01 22:53:03 +01:00
James Cole
05ea8216ff Fixed transaction coverage. 2015-01-01 22:51:38 +01:00
James Cole
fa1695672a Cleaning up. 2015-01-01 22:32:25 +01:00
James Cole
ac6f98fc47 First attempt to make the year charts and month reports report the same thing [skip ci] 2015-01-01 21:35:05 +01:00
James Cole
1a1f89f555 First attempt to make the year charts and month reports report the same thing [skip ci] 2015-01-01 21:27:51 +01:00
James Cole
6c3262e176 First attempt to make the year charts and month reports report the same thing [skip ci] 2015-01-01 21:26:40 +01:00
James Cole
b4bdb48f1e First attempt to make the year charts and month reports report the same thing [skip ci] 2015-01-01 21:23:12 +01:00
James Cole
823afe877b First attempt to make the year charts and month reports report the same thing [skip ci] 2015-01-01 21:20:41 +01:00
James Cole
cb8e082414 Fixed the bill tests. 2015-01-01 21:06:24 +01:00
James Cole
98c1fcc68f New content and tests ensure the coverage of all code. 2015-01-01 20:53:36 +01:00
James Cole
8c439a2852 Added debug information [skip ci] 2015-01-01 20:02:02 +01:00
James Cole
50c6109be7 Fixed broken tests. 2015-01-01 19:50:36 +01:00
James Cole
6e362663b5 Clean up content seeder and tests. 2015-01-01 19:35:10 +01:00
James Cole
74c9feb53f More tests! 2015-01-01 13:43:34 +01:00
James Cole
402e8588cf Even more tests! 2015-01-01 13:32:31 +01:00
James Cole
778a42bcc0 More unit tests. 2015-01-01 13:12:05 +01:00
James Cole
584f7ced84 New tests and new configuration for tests. 2015-01-01 12:33:07 +01:00
James Cole
8e892e7ea5 New unit tests to cover missed methods. 2015-01-01 12:06:42 +01:00
James Cole
3386c8b455 More spelling checks and small clean ups. 2014-12-31 17:15:59 +01:00
James Cole
6fa73ee28d Complexity cleanup [skip ci] 2014-12-31 16:45:12 +01:00
James Cole
8ec8042045 Some spell checking [skip ci] 2014-12-31 16:17:43 +01:00
James Cole
cddc123539 Removed dead code. 2014-12-31 09:02:36 +01:00
James Cole
4c2938c5cd New content and a fix for the bill controller. 2014-12-31 08:31:18 +01:00
James Cole
6d03ddadcc Covered the final lines. 2014-12-31 08:11:00 +01:00
James Cole
64311da4b4 Full coverage for home controller 2014-12-31 07:43:33 +01:00
James Cole
0cbb50ae9d Full coverage for user controller. 2014-12-31 07:17:33 +01:00
James Cole
7e96054dc2 Covered everything in the user controller except configuration controlled statements. 2014-12-31 00:57:12 +01:00
James Cole
578298580e Last tests for transaction controller. 2014-12-31 00:25:17 +01:00
James Cole
ee5afaa6bc First tests for transaction controller. 2014-12-30 22:25:30 +01:00
James Cole
15b023d116 Updated composer.lock [skip ci] 2014-12-30 21:04:01 +01:00
James Cole
1ef96c0b4d Finally updated the transaction controller to have some more sensible code. 2014-12-30 21:03:42 +01:00
James Cole
8c3ae40de1 Some refactoring. 2014-12-30 18:44:58 +01:00
James Cole
94fcfacec4 Tests for search [skip ci] 2014-12-30 18:44:49 +01:00
James Cole
ba7c01c6bc Fixed the tests. 2014-12-30 18:25:38 +01:00
James Cole
9f92e1b7bd Some tests and a rename. 2014-12-30 17:55:46 +01:00
James Cole
1f0e692ee2 New tests for the repeated expenses. 2014-12-30 17:27:31 +01:00
James Cole
0acd75a24f Updated tests for help controller. 2014-12-30 15:55:21 +01:00
James Cole
eedf27f8a5 Fixed the tests [skip ci] 2014-12-30 15:24:10 +01:00
James Cole
b451e207e2 Finally implemented repeated expenses properly. [skip ci] 2014-12-30 15:17:01 +01:00
James Cole
c0c37eec7b Most views now show the transaction the current journal/transaction is set in, even if it's not the current default currency. See issue #37 2014-12-30 06:30:20 +01:00
James Cole
89363ecfa3 Tests for reminders. 2014-12-29 21:49:43 +01:00
James Cole
593e799ca1 New and matching icon for bills [skip ci] #38 2014-12-29 20:39:27 +01:00
James Cole
8fc055cad9 Renamed a container [skip ci] #38 2014-12-29 20:36:56 +01:00
James Cole
75f86462e2 All code for issue #38. 2014-12-29 20:28:17 +01:00
James Cole
40892ccfa7 Some small updates to piggy banks. 2014-12-28 18:03:35 +01:00
James Cole
87fbf9c1a5 Added the ability to see cash accounts. [skip ci] 2014-12-28 09:00:22 +01:00
James Cole
4944b233b6 Greatly expanded report functionality. 2014-12-28 08:54:53 +01:00
James Cole
9f23462c42 Expanded reports. 2014-12-27 17:21:15 +01:00
James Cole
84a24f0333 Something with migrations. 2014-12-27 05:38:33 +01:00
James Cole
7a885bfc3c Fixed various bugs that made tests fail. 2014-12-26 22:59:13 +01:00
James Cole
3ba0cf1454 Expanded summary [skip ci] 2014-12-26 21:14:45 +01:00
James Cole
2d67a3159d Expanded reports 2014-12-26 21:08:44 +01:00
James Cole
290f25f1a0 First attempt at new month report. 2014-12-25 09:50:01 +01:00
James Cole
1659904f81 Various cleanup and spelling fixes. 2014-12-25 08:07:17 +01:00
James Cole
230bd6e40a Tests for the recurring transaction controller. 2014-12-25 08:00:09 +01:00
James Cole
ce27e97b92 More tests! Yay! 2014-12-25 00:42:31 +01:00
James Cole
18c1223c7b Tests for the profile controller 2014-12-24 22:52:14 +01:00
James Cole
8ef659f5de Tests for preferences controller. 2014-12-24 22:39:23 +01:00
James Cole
037452e525 Spelling errors fixed. 2014-12-24 21:20:47 +01:00
James Cole
e3482011d5 Updated two views. 2014-12-24 21:07:20 +01:00
James Cole
62748fa255 Migrations for future version 3.2.2 2014-12-24 20:56:05 +01:00
James Cole
7a9df05f6b A giant rename action in preparation of v3.2.2 2014-12-24 20:55:42 +01:00
James Cole
335279e728 Renamed lots of "piggybank" to "piggyBank". 2014-12-24 19:13:15 +01:00
James Cole
0332104738 Expanded tests for piggy banks. 2014-12-24 19:00:31 +01:00
402 changed files with 11816 additions and 9038 deletions

4
.gitignore vendored
View File

@@ -3,7 +3,6 @@
composer.phar
.env.*.php
.env.php
.DS_Store
Thumbs.db
.idea/
tests/_output/*
@@ -23,3 +22,6 @@ tests/unit/UnitTester.php
pi.php
tests/_data/db.sqlite
tests/_data/dump.sql
db.sqlite_snapshot
c3.php
db.sqlite-journal

View File

@@ -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"

View File

@@ -1,9 +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)
@@ -34,12 +37,13 @@ Everything is organised:
- Easy navigation through your records;
- Browse back and forth to see previous months or even years;
- Lots of charts because we all love them.
- Financial reporting showing you how well you are doing;
## Changes
Firefly III will feature, but does not feature yet:
- Financial reporting showing you how well you are doing;
- More control over other resources outside of personal finance
- Accounts shared with a partner (household accounts)
- Debts

View File

@@ -0,0 +1,606 @@
# ************************************************************
# Sequel Pro SQL dump
# Version 4096
#
# http://www.sequelpro.com/
# http://code.google.com/p/sequel-pro/
#
# Host: 127.0.0.1 (MySQL 5.6.19-0ubuntu0.14.04.1)
# Database: homestead
# Generation Time: 2015-01-02 19:01:30 +0000
# ************************************************************
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
# Dump of table account_meta
# ------------------------------------------------------------
DROP TABLE IF EXISTS `account_meta`;
CREATE TABLE `account_meta` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`account_id` int(10) unsigned NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`data` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `account_meta_account_id_name_unique` (`account_id`,`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table account_types
# ------------------------------------------------------------
DROP TABLE IF EXISTS `account_types`;
CREATE TABLE `account_types` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`type` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
`editable` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `account_types_type_unique` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `account_types` WRITE;
/*!40000 ALTER TABLE `account_types` DISABLE KEYS */;
INSERT INTO `account_types` (`id`, `created_at`, `updated_at`, `type`, `editable`)
VALUES
(1,'2015-01-02 19:00:13','2015-01-02 19:00:13','Default account',1),
(2,'2015-01-02 19:00:13','2015-01-02 19:00:13','Cash account',0),
(3,'2015-01-02 19:00:13','2015-01-02 19:00:13','Asset account',1),
(4,'2015-01-02 19:00:13','2015-01-02 19:00:13','Expense account',1),
(5,'2015-01-02 19:00:13','2015-01-02 19:00:13','Revenue account',1),
(6,'2015-01-02 19:00:13','2015-01-02 19:00:13','Initial balance account',0),
(7,'2015-01-02 19:00:13','2015-01-02 19:00:13','Beneficiary account',1),
(8,'2015-01-02 19:00:13','2015-01-02 19:00:13','Import account',0);
/*!40000 ALTER TABLE `account_types` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table accounts
# ------------------------------------------------------------
DROP TABLE IF EXISTS `accounts`;
CREATE TABLE `accounts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`user_id` int(10) unsigned NOT NULL,
`account_type_id` int(10) unsigned NOT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`active` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `accounts_user_id_account_type_id_name_unique` (`user_id`,`account_type_id`,`name`),
KEY `accounts_account_type_id_foreign` (`account_type_id`),
CONSTRAINT `accounts_account_type_id_foreign` FOREIGN KEY (`account_type_id`) REFERENCES `account_types` (`id`) ON DELETE CASCADE,
CONSTRAINT `accounts_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table bills
# ------------------------------------------------------------
DROP TABLE IF EXISTS `bills`;
CREATE TABLE `bills` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(10) unsigned NOT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`match` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`amount_min` decimal(10,2) NOT NULL,
`amount_max` decimal(10,2) NOT NULL,
`date` date NOT NULL,
`active` tinyint(1) NOT NULL,
`automatch` tinyint(1) NOT NULL,
`repeat_freq` enum('daily','weekly','monthly','quarterly','half-year','yearly') COLLATE utf8_unicode_ci NOT NULL,
`skip` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uid_name_unique` (`user_id`,`name`),
CONSTRAINT `bills_uid_for` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table budget_limits
# ------------------------------------------------------------
DROP TABLE IF EXISTS `budget_limits`;
CREATE TABLE `budget_limits` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`budget_id` int(10) unsigned DEFAULT NULL,
`startdate` date NOT NULL,
`amount` decimal(10,2) NOT NULL,
`repeats` tinyint(1) NOT NULL,
`repeat_freq` enum('daily','weekly','monthly','quarterly','half-year','yearly') COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_ci_combi` (`startdate`,`repeat_freq`),
UNIQUE KEY `unique_bl_combi` (`budget_id`,`startdate`,`repeat_freq`),
CONSTRAINT `bid_foreign` FOREIGN KEY (`budget_id`) REFERENCES `budgets` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table budget_transaction_journal
# ------------------------------------------------------------
DROP TABLE IF EXISTS `budget_transaction_journal`;
CREATE TABLE `budget_transaction_journal` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`budget_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `budid_tjid_unique` (`budget_id`,`transaction_journal_id`),
KEY `budget_transaction_journal_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `budget_transaction_journal_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE,
CONSTRAINT `budget_transaction_journal_budget_id_foreign` FOREIGN KEY (`budget_id`) REFERENCES `budgets` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table budgets
# ------------------------------------------------------------
DROP TABLE IF EXISTS `budgets`;
CREATE TABLE `budgets` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `budgets_user_id_name_unique` (`user_id`,`name`),
CONSTRAINT `budgets_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table categories
# ------------------------------------------------------------
DROP TABLE IF EXISTS `categories`;
CREATE TABLE `categories` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `categories_user_id_name_unique` (`user_id`,`name`),
CONSTRAINT `categories_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table category_transaction_journal
# ------------------------------------------------------------
DROP TABLE IF EXISTS `category_transaction_journal`;
CREATE TABLE `category_transaction_journal` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`category_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `catid_tjid_unique` (`category_id`,`transaction_journal_id`),
KEY `category_transaction_journal_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `category_transaction_journal_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE,
CONSTRAINT `category_transaction_journal_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table components
# ------------------------------------------------------------
DROP TABLE IF EXISTS `components`;
CREATE TABLE `components` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(10) unsigned NOT NULL,
`class` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `components_user_id_class_name_unique` (`user_id`,`class`,`name`),
CONSTRAINT `components_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table limit_repetitions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `limit_repetitions`;
CREATE TABLE `limit_repetitions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`budget_limit_id` int(10) unsigned NOT NULL,
`startdate` date NOT NULL,
`enddate` date NOT NULL,
`amount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `limit_repetitions_limit_id_startdate_enddate_unique` (`budget_limit_id`,`startdate`,`enddate`),
CONSTRAINT `limit_repetitions_limit_id_foreign` FOREIGN KEY (`budget_limit_id`) REFERENCES `budget_limits` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table migrations
# ------------------------------------------------------------
DROP TABLE IF EXISTS `migrations`;
CREATE TABLE `migrations` (
`migration` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`batch` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `migrations` WRITE;
/*!40000 ALTER TABLE `migrations` DISABLE KEYS */;
INSERT INTO `migrations` (`migration`, `batch`)
VALUES
('2014_06_27_163032_create_users_table',1),
('2014_06_27_163145_create_account_types_table',1),
('2014_06_27_163259_create_accounts_table',1),
('2014_06_27_163817_create_components_table',1),
('2014_06_27_163818_create_piggybanks_table',1),
('2014_06_27_164042_create_transaction_currencies_table',1),
('2014_06_27_164512_create_transaction_types_table',1),
('2014_06_27_164619_create_recurring_transactions_table',1),
('2014_06_27_164620_create_transaction_journals_table',1),
('2014_06_27_164836_create_transactions_table',1),
('2014_06_27_165344_create_component_transaction_table',1),
('2014_07_05_171326_create_component_transaction_journal_table',1),
('2014_07_06_123842_create_preferences_table',1),
('2014_07_09_204843_create_session_table',1),
('2014_07_17_183717_create_limits_table',1),
('2014_07_19_055011_create_limit_repeat_table',1),
('2014_08_06_044416_create_component_recurring_transaction_table',1),
('2014_08_12_173919_create_piggybank_repetitions_table',1),
('2014_08_18_100330_create_piggybank_events_table',1),
('2014_08_23_113221_create_reminders_table',1),
('2014_11_10_172053_create_account_meta_table',1),
('2014_11_29_135749_create_transaction_groups_table',1),
('2014_11_29_140217_create_transaction_group_transaction_journal_table',1),
('2014_12_13_190730_changes_for_v321',1),
('2014_12_24_191544_changes_for_v322',1);
/*!40000 ALTER TABLE `migrations` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table piggy_bank_events
# ------------------------------------------------------------
DROP TABLE IF EXISTS `piggy_bank_events`;
CREATE TABLE `piggy_bank_events` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`piggy_bank_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned DEFAULT NULL,
`date` date NOT NULL,
`amount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
KEY `piggybank_events_piggybank_id_foreign` (`piggy_bank_id`),
KEY `piggybank_events_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `piggybank_events_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE SET NULL,
CONSTRAINT `piggybank_events_piggybank_id_foreign` FOREIGN KEY (`piggy_bank_id`) REFERENCES `piggy_banks` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table piggy_bank_repetitions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `piggy_bank_repetitions`;
CREATE TABLE `piggy_bank_repetitions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`piggy_bank_id` int(10) unsigned NOT NULL,
`startdate` date DEFAULT NULL,
`targetdate` date DEFAULT NULL,
`currentamount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `piggybank_repetitions_piggybank_id_startdate_targetdate_unique` (`piggy_bank_id`,`startdate`,`targetdate`),
CONSTRAINT `piggybank_repetitions_piggybank_id_foreign` FOREIGN KEY (`piggy_bank_id`) REFERENCES `piggy_banks` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table piggy_banks
# ------------------------------------------------------------
DROP TABLE IF EXISTS `piggy_banks`;
CREATE TABLE `piggy_banks` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`account_id` int(10) unsigned NOT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`targetamount` decimal(10,2) NOT NULL,
`startdate` date DEFAULT NULL,
`targetdate` date DEFAULT NULL,
`repeats` tinyint(1) NOT NULL,
`rep_length` enum('day','week','quarter','month','year') COLLATE utf8_unicode_ci DEFAULT NULL,
`rep_every` smallint(5) unsigned NOT NULL,
`rep_times` smallint(5) unsigned DEFAULT NULL,
`reminder` enum('day','week','quarter','month','year') COLLATE utf8_unicode_ci DEFAULT NULL,
`reminder_skip` smallint(5) unsigned NOT NULL,
`remind_me` tinyint(1) NOT NULL,
`order` int(10) unsigned NOT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `piggybanks_account_id_name_unique` (`account_id`,`name`),
CONSTRAINT `piggybanks_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table preferences
# ------------------------------------------------------------
DROP TABLE IF EXISTS `preferences`;
CREATE TABLE `preferences` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(10) unsigned NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`data` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `preferences_user_id_name_unique` (`user_id`,`name`),
CONSTRAINT `preferences_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table reminders
# ------------------------------------------------------------
DROP TABLE IF EXISTS `reminders`;
CREATE TABLE `reminders` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(10) unsigned NOT NULL,
`startdate` date NOT NULL,
`enddate` date DEFAULT NULL,
`active` tinyint(1) NOT NULL,
`notnow` tinyint(1) NOT NULL DEFAULT '0',
`remindersable_id` int(10) unsigned DEFAULT NULL,
`remindersable_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `reminders_user_id_foreign` (`user_id`),
CONSTRAINT `reminders_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table sessions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `sessions`;
CREATE TABLE `sessions` (
`id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`payload` text COLLATE utf8_unicode_ci NOT NULL,
`last_activity` int(11) NOT NULL,
UNIQUE KEY `sessions_id_unique` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_currencies
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_currencies`;
CREATE TABLE `transaction_currencies` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`code` varchar(3) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(48) COLLATE utf8_unicode_ci DEFAULT NULL,
`symbol` varchar(8) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `transaction_currencies_code_unique` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `transaction_currencies` WRITE;
/*!40000 ALTER TABLE `transaction_currencies` DISABLE KEYS */;
INSERT INTO `transaction_currencies` (`id`, `created_at`, `updated_at`, `deleted_at`, `code`, `name`, `symbol`)
VALUES
(1,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'EUR','Euro','€'),
(2,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'USD','US Dollar','$'),
(3,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'HUF','Hungarian forint','Ft');
/*!40000 ALTER TABLE `transaction_currencies` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table transaction_group_transaction_journal
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_group_transaction_journal`;
CREATE TABLE `transaction_group_transaction_journal` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`transaction_group_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `tt_joined` (`transaction_group_id`,`transaction_journal_id`),
KEY `tr_trj_id` (`transaction_journal_id`),
CONSTRAINT `tr_trj_id` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE,
CONSTRAINT `tr_grp_id` FOREIGN KEY (`transaction_group_id`) REFERENCES `transaction_groups` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_groups
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_groups`;
CREATE TABLE `transaction_groups` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`user_id` int(10) unsigned NOT NULL,
`relation` enum('balance') COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `transaction_groups_user_id_foreign` (`user_id`),
CONSTRAINT `transaction_groups_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_journals
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_journals`;
CREATE TABLE `transaction_journals` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`user_id` int(10) unsigned NOT NULL,
`transaction_type_id` int(10) unsigned NOT NULL,
`bill_id` int(10) unsigned DEFAULT NULL,
`transaction_currency_id` int(10) unsigned NOT NULL,
`description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`completed` tinyint(1) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`id`),
KEY `transaction_journals_user_id_foreign` (`user_id`),
KEY `transaction_journals_transaction_type_id_foreign` (`transaction_type_id`),
KEY `transaction_journals_transaction_currency_id_foreign` (`transaction_currency_id`),
KEY `bill_id_foreign` (`bill_id`),
CONSTRAINT `bill_id_foreign` FOREIGN KEY (`bill_id`) REFERENCES `bills` (`id`) ON DELETE SET NULL,
CONSTRAINT `transaction_journals_transaction_currency_id_foreign` FOREIGN KEY (`transaction_currency_id`) REFERENCES `transaction_currencies` (`id`) ON DELETE CASCADE,
CONSTRAINT `transaction_journals_transaction_type_id_foreign` FOREIGN KEY (`transaction_type_id`) REFERENCES `transaction_types` (`id`) ON DELETE CASCADE,
CONSTRAINT `transaction_journals_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_types
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_types`;
CREATE TABLE `transaction_types` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`type` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `transaction_types_type_unique` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `transaction_types` WRITE;
/*!40000 ALTER TABLE `transaction_types` DISABLE KEYS */;
INSERT INTO `transaction_types` (`id`, `created_at`, `updated_at`, `deleted_at`, `type`)
VALUES
(1,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Withdrawal'),
(2,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Deposit'),
(3,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Transfer'),
(4,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Opening balance');
/*!40000 ALTER TABLE `transaction_types` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table transactions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transactions`;
CREATE TABLE `transactions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`account_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
`description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`amount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
KEY `transactions_account_id_foreign` (`account_id`),
KEY `transactions_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `transactions_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE,
CONSTRAINT `transactions_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table users
# ------------------------------------------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`reset` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`remember_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

View File

@@ -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 */;

View File

@@ -18,8 +18,8 @@ Breadcrumbs::register(
Breadcrumbs::register(
'accounts.index', function (Generator $breadcrumbs, $what) {
$breadcrumbs->parent('home');
$breadcrumbs->push(ucfirst($what) . ' accounts', route('accounts.index', $what));
}
$breadcrumbs->push(ucfirst(e($what)) . ' accounts', route('accounts.index', $what));
}
);
Breadcrumbs::register(
'accounts.show', function (Generator $breadcrumbs, \Account $account) {
@@ -31,6 +31,9 @@ Breadcrumbs::register(
case 'Asset account':
$what = 'asset';
break;
case 'Cash account':
$what = 'cash';
break;
case 'Expense account':
case 'Beneficiary account':
$what = 'expense';
@@ -40,21 +43,21 @@ Breadcrumbs::register(
break;
}
$breadcrumbs->parent('accounts.index', $what);
$breadcrumbs->push($account->name, route('accounts.show', $account->id));
}
$breadcrumbs->push(e($account->name), route('accounts.show', $account->id));
}
);
Breadcrumbs::register(
'accounts.delete', function (Generator $breadcrumbs, \Account $account) {
$breadcrumbs->parent('accounts.show', $account);
$breadcrumbs->push('Delete ' . $account->name, route('accounts.delete', $account->id));
}
$breadcrumbs->push('Delete ' . e($account->name), route('accounts.delete', $account->id));
}
);
Breadcrumbs::register(
'accounts.edit', function (Generator $breadcrumbs, \Account $account) {
$breadcrumbs->parent('accounts.show', $account);
$breadcrumbs->push('Edit ' . $account->name, route('accounts.edit', $account->id));
}
$breadcrumbs->push('Edit ' . e($account->name), route('accounts.edit', $account->id));
}
);
// budgets.
@@ -62,38 +65,38 @@ Breadcrumbs::register(
'budgets.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Budgets', route('budgets.index'));
}
}
);
Breadcrumbs::register(
'budgets.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('budgets.index');
$breadcrumbs->push('Create new budget', route('budgets.create'));
}
}
);
Breadcrumbs::register(
'budgets.edit', function (Generator $breadcrumbs, Budget $budget) {
$breadcrumbs->parent('budgets.show', $budget);
$breadcrumbs->push('Edit ' . $budget->name, route('budgets.edit', $budget->id));
}
$breadcrumbs->push('Edit ' . e($budget->name), route('budgets.edit', $budget->id));
}
);
Breadcrumbs::register(
'budgets.delete', function (Generator $breadcrumbs, Budget $budget) {
$breadcrumbs->parent('budgets.show', $budget);
$breadcrumbs->push('Delete ' . $budget->name, route('budgets.delete', $budget->id));
}
$breadcrumbs->push('Delete ' . e($budget->name), route('budgets.delete', $budget->id));
}
);
Breadcrumbs::register(
'budgets.show', function (Generator $breadcrumbs, Budget $budget, LimitRepetition $repetition = null) {
$breadcrumbs->parent('budgets.index');
$breadcrumbs->push($budget->name, route('budgets.show', $budget->id));
$breadcrumbs->push(e($budget->name), route('budgets.show', $budget->id));
if (!is_null($repetition)) {
$breadcrumbs->push(
DateKit::periodShow($repetition->startdate, $repetition->budgetlimit->repeat_freq), route('budgets.show', $budget->id, $repetition->id)
);
}
}
}
);
// categories
@@ -101,70 +104,70 @@ Breadcrumbs::register(
'categories.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Categories', route('categories.index'));
}
}
);
Breadcrumbs::register(
'categories.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('categories.index');
$breadcrumbs->push('Create new category', route('categories.create'));
}
}
);
Breadcrumbs::register(
'categories.edit', function (Generator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.show', $category);
$breadcrumbs->push('Edit ' . $category->name, route('categories.edit', $category->id));
}
$breadcrumbs->push('Edit ' . e($category->name), route('categories.edit', $category->id));
}
);
Breadcrumbs::register(
'categories.delete', function (Generator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.show', $category);
$breadcrumbs->push('Delete ' . $category->name, route('categories.delete', $category->id));
}
$breadcrumbs->push('Delete ' . e($category->name), route('categories.delete', $category->id));
}
);
Breadcrumbs::register(
'categories.show', function (Generator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.index');
$breadcrumbs->push($category->name, route('categories.show', $category->id));
$breadcrumbs->push(e($category->name), route('categories.show', $category->id));
}
}
);
// piggy banks
Breadcrumbs::register(
'piggybanks.index', function (Generator $breadcrumbs) {
'piggyBanks.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Piggy banks', route('piggybanks.index'));
}
$breadcrumbs->push('Piggy banks', route('piggyBanks.index'));
}
);
Breadcrumbs::register(
'piggybanks.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('piggybanks.index');
$breadcrumbs->push('Create new piggy bank', route('piggybanks.create'));
}
'piggyBanks.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('piggyBanks.index');
$breadcrumbs->push('Create new piggy bank', route('piggyBanks.create'));
}
);
Breadcrumbs::register(
'piggybanks.edit', function (Generator $breadcrumbs, Piggybank $piggybank) {
$breadcrumbs->parent('piggybanks.show', $piggybank);
$breadcrumbs->push('Edit ' . $piggybank->name, route('piggybanks.edit', $piggybank->id));
}
'piggyBanks.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggyBanks.show', $piggyBank);
$breadcrumbs->push('Edit ' . e($piggyBank->name), route('piggyBanks.edit', $piggyBank->id));
}
);
Breadcrumbs::register(
'piggybanks.delete', function (Generator $breadcrumbs, Piggybank $piggybank) {
$breadcrumbs->parent('piggybanks.show', $piggybank);
$breadcrumbs->push('Delete ' . $piggybank->name, route('piggybanks.delete', $piggybank->id));
}
'piggyBanks.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggyBanks.show', $piggyBank);
$breadcrumbs->push('Delete ' . e($piggyBank->name), route('piggyBanks.delete', $piggyBank->id));
}
);
Breadcrumbs::register(
'piggybanks.show', function (Generator $breadcrumbs, Piggybank $piggybank) {
$breadcrumbs->parent('piggybanks.index');
$breadcrumbs->push($piggybank->name, route('piggybanks.show', $piggybank->id));
'piggyBanks.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggyBanks.index');
$breadcrumbs->push(e($piggyBank->name), route('piggyBanks.show', $piggyBank->id));
}
}
);
// preferences
@@ -173,7 +176,7 @@ Breadcrumbs::register(
$breadcrumbs->parent('home');
$breadcrumbs->push('Preferences', route('preferences'));
}
}
);
// profile
@@ -182,49 +185,49 @@ Breadcrumbs::register(
$breadcrumbs->parent('home');
$breadcrumbs->push('Profile', route('profile'));
}
}
);
Breadcrumbs::register(
'change-password', function (Generator $breadcrumbs) {
$breadcrumbs->parent('profile');
$breadcrumbs->push('Change your password', route('change-password'));
}
}
);
// recurring transactions
// bills
Breadcrumbs::register(
'recurring.index', function (Generator $breadcrumbs) {
'bills.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Recurring transactions', route('recurring.index'));
}
$breadcrumbs->push('Bills', route('bills.index'));
}
);
Breadcrumbs::register(
'recurring.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('recurring.index');
$breadcrumbs->push('Create new recurring transaction', route('recurring.create'));
}
'bills.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('bills.index');
$breadcrumbs->push('Create new bill', route('bills.create'));
}
);
Breadcrumbs::register(
'recurring.edit', function (Generator $breadcrumbs, RecurringTransaction $recurring) {
$breadcrumbs->parent('recurring.show', $recurring);
$breadcrumbs->push('Edit ' . $recurring->name, route('recurring.edit', $recurring->id));
}
'bills.edit', function (Generator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.show', $bill);
$breadcrumbs->push('Edit ' . e($bill->name), route('bills.edit', $bill->id));
}
);
Breadcrumbs::register(
'recurring.delete', function (Generator $breadcrumbs, RecurringTransaction $recurring) {
$breadcrumbs->parent('recurring.show', $recurring);
$breadcrumbs->push('Delete ' . $recurring->name, route('recurring.delete', $recurring->id));
}
'bills.delete', function (Generator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.show', $bill);
$breadcrumbs->push('Delete ' . e($bill->name), route('bills.delete', $bill->id));
}
);
Breadcrumbs::register(
'recurring.show', function (Generator $breadcrumbs, RecurringTransaction $recurring) {
$breadcrumbs->parent('recurring.index');
$breadcrumbs->push($recurring->name, route('recurring.show', $recurring->id));
'bills.show', function (Generator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.index');
$breadcrumbs->push(e($bill->name), route('bills.show', $bill->id));
}
}
);
// reminders
@@ -233,7 +236,7 @@ Breadcrumbs::register(
$breadcrumbs->parent('home');
$breadcrumbs->push('Reminder #' . $reminder->id, route('reminders.show', $reminder->id));
}
}
);
// repeated expenses
@@ -241,34 +244,34 @@ Breadcrumbs::register(
'repeated.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Repeated expenses', route('repeated.index'));
}
}
);
Breadcrumbs::register(
'repeated.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('repeated.index');
$breadcrumbs->push('Create new repeated expense', route('repeated.create'));
}
}
);
Breadcrumbs::register(
'repeated.edit', function (Generator $breadcrumbs, Piggybank $piggybank) {
$breadcrumbs->parent('repeated.show', $piggybank);
$breadcrumbs->push('Edit ' . $piggybank->name, route('repeated.edit', $piggybank->id));
}
'repeated.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('repeated.show', $piggyBank);
$breadcrumbs->push('Edit ' . e($piggyBank->name), route('repeated.edit', $piggyBank->id));
}
);
Breadcrumbs::register(
'repeated.delete', function (Generator $breadcrumbs, Piggybank $piggybank) {
$breadcrumbs->parent('repeated.show', $piggybank);
$breadcrumbs->push('Delete ' . $piggybank->name, route('repeated.delete', $piggybank->id));
}
'repeated.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('repeated.show', $piggyBank);
$breadcrumbs->push('Delete ' . e($piggyBank->name), route('repeated.delete', $piggyBank->id));
}
);
Breadcrumbs::register(
'repeated.show', function (Generator $breadcrumbs, Piggybank $piggybank) {
'repeated.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('repeated.index');
$breadcrumbs->push($piggybank->name, route('repeated.show', $piggybank->id));
$breadcrumbs->push(e($piggyBank->name), route('repeated.show', $piggyBank->id));
}
}
);
// reports
@@ -276,33 +279,36 @@ Breadcrumbs::register(
'reports.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Reports', route('reports.index'));
}
}
);
Breadcrumbs::register(
'reports.year', function (Generator $breadcrumbs, Carbon $date) {
$breadcrumbs->parent('reports.index');
$breadcrumbs->push($date->format('Y'), route('reports.year', $date->format('Y')));
}
}
);
Breadcrumbs::register(
'reports.budgets', function (Generator $breadcrumbs, Carbon $date) {
'reports.month', function (Generator $breadcrumbs, Carbon $date) {
$breadcrumbs->parent('reports.index');
$breadcrumbs->push('Budgets in ' . $date->format('F Y'), route('reports.budgets', $date->format('Y')));
}
$breadcrumbs->push('Monthly report for ' . $date->format('F Y'), route('reports.month', $date));
}
);
Breadcrumbs::register(
'reports.unbalanced', function (Generator $breadcrumbs, Carbon $date) {
'reports.budget', function (Generator $breadcrumbs, Carbon $date) {
$breadcrumbs->parent('reports.index');
$breadcrumbs->push('Unbalanced transactions in ' . $date->format('F Y'), route('reports.unbalanced', $date->format('Y')));
}
$breadcrumbs->push('Budget report for ' . $date->format('F Y'), route('reports.budget', $date));
}
);
// search
Breadcrumbs::register(
'search', function (Generator $breadcrumbs, $query) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Search for "' . e($query) . '"', route('search'));
}
}
);
// transactions
@@ -327,37 +333,37 @@ Breadcrumbs::register(
$subTitle = 'Opening balances';
break;
default:
throw new FireflyException('Cannot handle $what "'.e($what).'" in bread crumbs');
throw new FireflyException('Cannot handle $what "' . e($what) . '" in bread crumbs');
}
$breadcrumbs->push($subTitle, route('transactions.index', $what));
}
}
);
Breadcrumbs::register(
'transactions.create', function (Generator $breadcrumbs, $what) {
$breadcrumbs->parent('transactions.index', $what);
$breadcrumbs->push('Create new ' . $what, route('transactions.create', $what));
}
$breadcrumbs->push('Create new ' .e($what), route('transactions.create', $what));
}
);
Breadcrumbs::register(
'transactions.edit', function (Generator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.show', $journal);
$breadcrumbs->push('Edit ' . $journal->description, route('transactions.edit', $journal ->id));
}
$breadcrumbs->push('Edit ' . e($journal->description), route('transactions.edit', $journal->id));
}
);
Breadcrumbs::register(
'transactions.delete', function (Generator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.show', $journal);
$breadcrumbs->push('Delete ' . $journal->description, route('transactions.delete', $journal->id));
}
$breadcrumbs->push('Delete ' . e($journal->description), route('transactions.delete', $journal->id));
}
);
Breadcrumbs::register(
'transactions.show', function (Generator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.index', strtolower($journal->transactionType->type));
$breadcrumbs->push($journal->description, route('transactions.show', $journal->id));
$breadcrumbs->push(e($journal->description), route('transactions.show', $journal->id));
}
}
);

View File

@@ -1,8 +1,6 @@
<?php
use Illuminate\Console\Command;
//use Symfony\Component\Console\Input\InputArgument;
//use Symfony\Component\Console\Input\InputOption;
/**
* Class Cleanup
@@ -43,7 +41,7 @@ class Cleanup extends Command
$this->info('Cleared compiled...');
Artisan::call('ide-helper:generate');
$this->info('IDE helper, done...');
Artisan::call('ide-helper:models', ['nowrite']);
Artisan::call('ide-helper:models');
$this->info('IDE models, done...');
Artisan::call('optimize');
$this->info('Optimized...');

View File

@@ -3,7 +3,7 @@
return [
'index_periods' => ['1D', '1W', '1M', '3M', '6M', '1Y', 'custom'],
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
'piggybank_periods' => [
'piggy_bank_periods' => [
'week' => 'Week',
'month' => 'Month',
'quarter' => 'Quarter',

0
app/config/queue.php Executable file → Normal file
View File

View File

@@ -0,0 +1,2 @@
<?php
return ['log_level' => 'debug',];

View File

@@ -0,0 +1,8 @@
<?php
return [
'verify_mail' => false,
'verify_reset' => true,
'allow_register' => true
];

View File

@@ -0,0 +1,3 @@
<?php
return ['driver' => 'array',];

View File

@@ -0,0 +1,12 @@
<?php
return [
'default' => 'sqlite',
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => ''
]
]
];

View File

@@ -0,0 +1,13 @@
<?php
return [
'driver' => 'smtp',
'host' => '',
'port' => 587,
'from' => ['address' => '', 'name' => 'Firefly III'],
'encryption' => 'tls',
'username' => '',
'password' => '',
'sendmail' => '/usr/sbin/sendmail -bs',
'pretend' => true,
];

View File

@@ -0,0 +1,3 @@
<?php
return ['driver' => 'array',];

View File

@@ -28,6 +28,7 @@ class AccountController extends BaseController
'Expense account' => 'expense',
'Beneficiary account' => 'expense',
'Revenue account' => 'revenue',
'Cash account' => 'cash',
];
/** @var array */
@@ -36,6 +37,7 @@ class AccountController extends BaseController
'asset' => 'fa-money',
'Asset account' => 'fa-money',
'Default account' => 'fa-money',
'Cash account' => 'fa-money',
'expense' => 'fa-shopping-cart',
'Expense account' => 'fa-shopping-cart',
'Beneficiary account' => 'fa-shopping-cart',
@@ -68,7 +70,7 @@ class AccountController extends BaseController
public function create($what)
{
$subTitleIcon = $this->_subIconsByIdentifier[$what];
$subTitle = 'Create a new ' . $what . ' account';
$subTitle = 'Create a new ' . e($what) . ' account';
return View::make('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
}
@@ -80,7 +82,7 @@ class AccountController extends BaseController
*/
public function delete(Account $account)
{
$subTitle = 'Delete ' . strtolower($account->accountType->type) . ' "' . $account->name . '"';
$subTitle = 'Delete ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
return View::make('accounts.delete', compact('account', 'subTitle'));
}
@@ -99,7 +101,7 @@ class AccountController extends BaseController
$this->_repository->destroy($account);
Session::flash('success', 'The ' . $typeName . ' account "' . e($name) . '" was deleted.');
Session::flash('success', 'The ' . e($typeName) . ' account "' . e($name) . '" was deleted.');
return Redirect::route('accounts.index', $typeName);
}
@@ -114,7 +116,7 @@ class AccountController extends BaseController
$openingBalance = $this->_repository->openingBalanceTransaction($account);
$subTitleIcon = $this->_subIconsByIdentifier[$account->accountType->type];
$subTitle = 'Edit ' . strtolower($account->accountType->type) . ' "' . $account->name . '"';
$subTitle = 'Edit ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
// pre fill some useful values.
$preFilled = [
@@ -155,7 +157,7 @@ class AccountController extends BaseController
$subTitleIcon = $this->_subIconsByIdentifier[$account->accountType->type];
$what = $this->_shortNamesByFullName[$account->accountType->type];
$journals = $this->_repository->getTransactionJournals($account, 50, $range);
$subTitle = 'Details for ' . strtolower($account->accountType->type) . ' "' . $account->name . '"';
$subTitle = 'Details for ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
return View::make('accounts.show', compact('account', 'what', 'range', 'subTitleIcon', 'journals', 'subTitle'));
}
@@ -182,17 +184,17 @@ class AccountController extends BaseController
// return to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('accounts.create', $data['what'])->withInput();
return Redirect::route('accounts.create', e($data['what']))->withInput();
}
// store:
// store
$this->_repository->store($data);
Session::flash('success', 'Account "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('accounts.index', $data['what']);
return Redirect::route('accounts.index', e($data['what']));
}
return Redirect::route('accounts.create', $data['what'])->withInput();
return Redirect::route('accounts.create', e($data['what']))->withInput();
}
/**
@@ -229,7 +231,7 @@ class AccountController extends BaseController
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('accounts.index', $data['what']);
return Redirect::route('accounts.index', e($data['what']));
}
// go back to update screen.

View File

@@ -0,0 +1,215 @@
<?php
use FireflyIII\Database\Bill\Bill as Repository;
use FireflyIII\Exception\FireflyException;
/**
*
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class BillController
*
*/
class BillController extends BaseController
{
/** @var Repository */
protected $_repository;
/**
* @param Repository $repository
*/
public function __construct(Repository $repository)
{
$this->_repository = $repository;
View::share('title', 'Bills');
View::share('mainTitleIcon', 'fa-calendar-o');
}
/**
* @return $this
*/
public function create()
{
$periods = \Config::get('firefly.periods_to_text');
return View::make('bills.create')->with('periods', $periods)->with('subTitle', 'Create new');
}
/**
* @param Bill $bill
*
* @return $this
*/
public function delete(Bill $bill)
{
return View::make('bills.delete')->with('bill', $bill)->with(
'subTitle', 'Delete "' . e($bill->name) . '"'
);
}
/**
* @param Bill $bill
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Bill $bill)
{
$this->_repository->destroy($bill);
Session::flash('success', 'The bill was deleted.');
return Redirect::route('bills.index');
}
/**
* @param Bill $bill
*
* @return $this
*/
public function edit(Bill $bill)
{
$periods = \Config::get('firefly.periods_to_text');
return View::make('bills.edit')->with('periods', $periods)->with('bill', $bill)->with(
'subTitle', 'Edit "' . e($bill->name) . '"'
);
}
/**
* @return $this
*/
public function index()
{
$bills = $this->_repository->get();
$bills->each(
function (Bill $bill) {
$bill->nextExpectedMatch = $this->_repository->nextExpectedMatch($bill);
$bill->lastFoundMatch = $this->_repository->lastFoundMatch($bill);
}
);
return View::make('bills.index', compact('bills'));
}
/**
* @param Bill $bill
*
* @return mixed
*/
public function rescan(Bill $bill)
{
if (intval($bill->active) == 0) {
Session::flash('warning', 'Inactive bills cannot be scanned.');
return Redirect::intended('/');
}
$this->_repository->scanEverything($bill);
Session::flash('success', 'Rescanned everything.');
return Redirect::intended('/');
}
/**
* @param Bill $bill
*
* @return mixed
*/
public function show(Bill $bill)
{
$journals = $bill->transactionjournals()->withRelevantData()->orderBy('date', 'DESC')->get();
$bill->nextExpectedMatch = $this->_repository->nextExpectedMatch($bill);
$hideBill = true;
return View::make('bills.show', compact('journals', 'hideBill', 'bill'))->with(
'subTitle', e($bill->name)
);
}
/**
* @return $this
* @throws FireflyException
*/
public function store()
{
$data = Input::except(['_token', 'post_submit_action']);
$data['user_id'] = Auth::user()->id;
// always validate:
$messages = $this->_repository->validate($data);
// flash messages:
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
Session::flash('error', 'Could not store bill: ' . $messages['errors']->first());
return Redirect::route('bills.create')->withInput();
}
// return to create screen:
if (Input::get('post_submit_action') == 'validate_only') {
return Redirect::route('bills.create')->withInput();
}
// store
$this->_repository->store($data);
Session::flash('success', 'Bill "' . e($data['name']) . '" stored.');
if (Input::get('post_submit_action') == 'store') {
return Redirect::route('bills.index');
}
return Redirect::route('bills.create')->withInput();
}
/**
* @param Bill $bill
*
* @return $this
* @throws FireflyException
*/
public function update(Bill $bill)
{
$data = Input::except('_token');
$data['active'] = intval(Input::get('active'));
$data['automatch'] = intval(Input::get('automatch'));
$data['user_id'] = Auth::user()->id;
// always validate:
$messages = $this->_repository->validate($data);
// flash messages:
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
Session::flash('error', 'Could not update bill: ' . $messages['errors']->first());
return Redirect::route('bills.edit', $bill->id)->withInput();
}
// return to update screen:
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('bills.edit', $bill->id)->withInput();
}
// update
$this->_repository->update($bill, $data);
Session::flash('success', 'Bill "' . e($data['name']) . '" updated.');
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('bills.index');
}
// go back to update screen.
return Redirect::route('bills.edit', $bill->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
}

View File

@@ -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]);
}
@@ -99,7 +96,6 @@ class BudgetController extends BaseController
/**
* The index of the budget controller contains all budgets and the current relevant limit repetition.
* TODO move currentRep to the repository.
*
* @return $this
*/
@@ -125,6 +121,19 @@ class BudgetController extends BaseController
return View::make('budgets.index', compact('budgetMaximum', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount'));
}
/**
* @return \Illuminate\View\View
*/
public function noBudget()
{
$start = \Session::get('start', Carbon::now()->startOfMonth());
$end = \Session::get('end', Carbon::now()->startOfMonth());
$list = $this->_repository->journalsNoBudget($start, $end);
$subTitle = 'Transactions without a budget in ' . $start->format('F Y');
return View::make('budgets.noBudget', compact('list', 'subTitle'));
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
@@ -136,6 +145,8 @@ class BudgetController extends BaseController
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param Budget $budget
* @param LimitRepetition $repetition
*
@@ -172,14 +183,15 @@ 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 to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('budgets.create')->withInput();
}
// store:
// return to create screen:
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('budgets.create')->withInput();
}
// store
$this->_repository->store($data);
Session::flash('success', 'Budget "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
@@ -190,7 +202,6 @@ class BudgetController extends BaseController
return Redirect::route('budgets.create')->withInput();
}
/**
* @param Budget $budget
*
@@ -211,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();
}

View File

@@ -1,11 +1,11 @@
<?php
use Carbon\Carbon;
use FireflyIII\Database\Category\Category as CategoryRepository;
use FireflyIII\Exception\FireflyException;
/**
*
* @SuppressWarnings("CamelCase") // I'm fine with this.
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
*
* Class CategoryController
*/
@@ -34,6 +34,19 @@ class CategoryController extends BaseController
return View::make('categories.create')->with('subTitle', 'Create a new category');
}
/**
* @return \Illuminate\View\View
*/
public function noCategory()
{
$start = \Session::get('start', Carbon::now()->startOfMonth());
$end = \Session::get('end', Carbon::now()->startOfMonth());
$list = $this->_repository->journalsNoCategory($start, $end);
$subTitle = 'Transactions without a category in ' . $start->format('F Y');
return View::make('categories.noCategory', compact('list', 'subTitle'));
}
/**
* @param Category $category
*
@@ -41,7 +54,7 @@ class CategoryController extends BaseController
*/
public function delete(Category $category)
{
return View::make('categories.delete')->with('category', $category)->with('subTitle', 'Delete category "' . $category->name . '"');
return View::make('categories.delete')->with('category', $category)->with('subTitle', 'Delete category "' . e($category->name) . '"');
}
/**
@@ -65,7 +78,7 @@ class CategoryController extends BaseController
*/
public function edit(Category $category)
{
return View::make('categories.edit')->with('category', $category)->with('subTitle', 'Edit category "' . $category->name . '"');
return View::make('categories.edit')->with('category', $category)->with('subTitle', 'Edit category "' . e($category->name) . '"');
}
/**
@@ -92,6 +105,7 @@ class CategoryController extends BaseController
}
/**
*
* @return $this
* @throws FireflyException
*/
@@ -109,14 +123,15 @@ 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 to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('categories.create')->withInput();
}
// store:
// return to create screen:
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('categories.create')->withInput();
}
// store
$this->_repository->store($data);
Session::flash('success', 'Category "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
@@ -127,6 +142,7 @@ class CategoryController extends BaseController
}
/**
*
* @param Category $category
*
* @return $this
@@ -146,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();
}

View File

@@ -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
*/
@@ -61,6 +60,8 @@ class CurrencyController extends BaseController
/**
* @param TransactionCurrency $currency
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/
public function delete(TransactionCurrency $currency)
{
@@ -74,6 +75,11 @@ class CurrencyController extends BaseController
return View::make('currency.delete', compact('currency'));
}
/**
* @param TransactionCurrency $currency
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(TransactionCurrency $currency)
{
Session::flash('success', 'Currency "' . e($currency->name) . '" deleted');
@@ -98,6 +104,9 @@ class CurrencyController extends BaseController
}
/**
* @return \Illuminate\View\View
*/
public function index()
{
$currencies = $this->_repository->get();
@@ -112,6 +121,11 @@ class CurrencyController extends BaseController
return View::make('currency.index', compact('currencies', 'defaultCurrency'));
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function store()
{
$data = Input::except('_token');
@@ -132,7 +146,7 @@ class CurrencyController extends BaseController
return Redirect::route('currency.create')->withInput();
}
// store:
// store
$this->_repository->store($data);
Session::flash('success', 'Currency "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
@@ -143,6 +157,11 @@ class CurrencyController extends BaseController
}
/**
* @param TransactionCurrency $currency
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function update(TransactionCurrency $currency)
{
$data = Input::except('_token');
@@ -156,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();
}

View File

@@ -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,8 +42,8 @@ class GoogleChartController extends BaseController
{
$this->_chart->addColumn('Day of month', 'date');
$this->_chart->addColumn('Balance for ' . $account->name, 'number');
$this->_chart->addCertainty(1);
// TODO this can be combined in some method, it's coming up quite often, is it?
$start = $this->_start;
$end = $this->_end;
$count = $account->transactions()->count();
@@ -62,12 +58,11 @@ class GoogleChartController extends BaseController
$start = new Carbon($first->date);
$end = new Carbon($last->date);
}
// todo until this part.
$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();
}
@@ -78,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()
{
@@ -86,22 +81,29 @@ class GoogleChartController extends BaseController
/** @var \FireflyIII\Shared\Preferences\Preferences $preferences */
$preferences = App::make('FireflyIII\Shared\Preferences\Preferences');
$pref = $preferences->get('frontpageAccounts', []);
$pref = $preferences->get('frontPageAccounts', []);
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
$accounts = count($pref->data) > 0 ? $acct->getByIds($pref->data) : $acct->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];
$certain = $current < $today;
foreach ($accounts as $account) {
$row[] = Steam::balance($account, $current);
$row[] = $certain;
}
$this->_chart->addRowArray($row);
$current->addDay();
@@ -113,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
*/
@@ -122,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();
@@ -131,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;
@@ -155,7 +193,7 @@ class GoogleChartController extends BaseController
}
}
$noBudgetSet = $bdt->transactionsWithoutBudgetInDateRange($this->_start, $this->_end);
$noBudgetSet = $bdt->expenseNoBudget($this->_start, $this->_end);
$sum = $noBudgetSet->sum('amount') * -1;
$this->_chart->addRow('No budget', 0, $sum);
$this->_chart->generate();
@@ -186,7 +224,75 @@ class GoogleChartController extends BaseController
}
/**
* TODO still in use?
* @param Bill $bill
*
* @return \Illuminate\Http\JsonResponse
*/
public function billOverview(Bill $bill)
{
$this->_chart->addColumn('Date', 'date');
$this->_chart->addColumn('Max amount', 'number');
$this->_chart->addColumn('Min amount', 'number');
$this->_chart->addColumn('Current entry', 'number');
// get first transaction or today for start:
$first = $bill->transactionjournals()->orderBy('date', 'ASC')->first();
if ($first) {
$start = $first->date;
} else {
$start = new Carbon;
}
$end = new Carbon;
while ($start <= $end) {
$result = $bill->transactionjournals()->before($end)->after($start)->first();
if ($result) {
$amount = $result->getAmount();
} else {
$amount = 0;
}
unset($result);
$this->_chart->addRow(clone $start, $bill->amount_max, $bill->amount_min, $amount);
$start = DateKit::addPeriod($start, $bill->repeat_freq, 0);
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
*
* @return \Illuminate\Http\JsonResponse
* @throws \FireflyIII\Exception\FireflyException
*/
public function billsOverview()
{
$paid = ['items' => [], 'amount' => 0];
$unpaid = ['items' => [], 'amount' => 0];
$this->_chart->addColumn('Name', 'string');
$this->_chart->addColumn('Amount', 'number');
$set = $this->_repository->getBillsSummary($this->_start, $this->_end);
foreach ($set as $entry) {
if (intval($entry->journalId) == 0) {
$unpaid['items'][] = $entry->name;
$unpaid['amount'] += floatval($entry->averageAmount);
} else {
$paid['items'][] = $entry->description;
$paid['amount'] += floatval($entry->actualAmount);
}
}
$this->_chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
$this->_chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
*
* @param Budget $budget
* @param LimitRepetition $repetition
@@ -220,46 +326,57 @@ class GoogleChartController extends BaseController
}
/**
* TODO still in use?
*
* @param Budget $component
* @param $year
* @param Budget $budget
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetsAndSpending(Budget $component, $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 $repos */
$repos = App::make('FireflyIII\Database\Budget\Budget');
/** @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();
}
$start = new Carbon('01-01-' . $year);
// grab the last budget limit ever:
$lastLimit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first();
if ($lastLimit) {
$end = new Carbon($lastLimit->startdate);
} else {
$end = Carbon::now()->endOfYear();
}
} else {
$start = Carbon::createFromDate(intval($year), 1, 1);
$end = clone $start;
$end->endOfYear();
}
while ($start <= $end) {
$spent = $repos->spentInMonth($component, $start);
$repetition = $repos->repetitionOnStartingOnDate($component, $start);
$spent = $budgetRepository->spentInMonth($budget, $start);
$repetition = $budgetRepository->repetitionOnStartingOnDate($budget, $start);
if ($repetition) {
$budgeted = floatval($repetition->amount);
\Log::debug('Found a repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name . '!');
} else {
\Log::debug('No repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name);
$budgeted = null;
}
$this->_chart->addRow(clone $start, $budgeted, $spent);
$start->addMonth();
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
@@ -268,7 +385,6 @@ class GoogleChartController extends BaseController
}
/**
* TODO still in use?
*
* @param Category $component
* @param $year
@@ -283,8 +399,8 @@ class GoogleChartController extends BaseController
return View::make('error')->with('message', 'Invalid year.');
}
/** @var \FireflyIII\Database\Category\Category $repos */
$repos = App::make('FireflyIII\Database\Category\Category');
/** @var \FireflyIII\Database\Category\Category $categoryRepository */
$categoryRepository = App::make('FireflyIII\Database\Category\Category');
$this->_chart->addColumn('Month', 'date');
$this->_chart->addColumn('Budgeted', 'number');
@@ -295,7 +411,7 @@ class GoogleChartController extends BaseController
$end->endOfYear();
while ($start <= $end) {
$spent = $repos->spentInMonth($component, $start);
$spent = $categoryRepository->spentInMonth($component, $start);
$budgeted = null;
$this->_chart->addRow(clone $start, $budgeted, $spent);
@@ -312,16 +428,16 @@ class GoogleChartController extends BaseController
}
/**
* @param Piggybank $piggybank
* @param PiggyBank $piggyBank
*
* @return \Illuminate\Http\JsonResponse
*/
public function piggyBankHistory(\Piggybank $piggybank)
public function piggyBankHistory(\PiggyBank $piggyBank)
{
$this->_chart->addColumn('Date', 'date');
$this->_chart->addColumn('Balance', 'number');
$set = \DB::table('piggy_bank_events')->where('piggybank_id', $piggybank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
$set = \DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
foreach ($set as $entry) {
$this->_chart->addRow(new Carbon($entry->date), floatval($entry->sum));
@@ -334,77 +450,6 @@ class GoogleChartController extends BaseController
}
/**
* @param RecurringTransaction $recurring
*
* @return \Illuminate\Http\JsonResponse
*/
public function recurringOverview(RecurringTransaction $recurring)
{
$this->_chart->addColumn('Date', 'date');
$this->_chart->addColumn('Max amount', 'number');
$this->_chart->addColumn('Min amount', 'number');
$this->_chart->addColumn('Current entry', 'number');
// get first transaction or today for start:
$first = $recurring->transactionjournals()->orderBy('date', 'ASC')->first();
if ($first) {
$start = $first->date;
} else {
$start = new Carbon;
}
$end = new Carbon;
while ($start <= $end) {
$result = $recurring->transactionjournals()->before($end)->after($start)->first();
if ($result) {
$amount = $result->getAmount();
} else {
$amount = 0;
}
unset($result);
$this->_chart->addRow(clone $start, $recurring->amount_max, $recurring->amount_min, $amount);
$start = DateKit::addPeriod($start, $recurring->repeat_freq, 0);
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
* TODO query move to helper.
*
* @return \Illuminate\Http\JsonResponse
* @throws \FireflyIII\Exception\FireflyException
*/
public function recurringTransactionsOverview()
{
$paid = ['items' => [], 'amount' => 0];
$unpaid = ['items' => [], 'amount' => 0];
$this->_chart->addColumn('Name', 'string');
$this->_chart->addColumn('Amount', 'number');
$set = $this->_repository->getRecurringSummary($this->_start, $this->_end);
foreach ($set as $entry) {
if (intval($entry->journalId) == 0) {
$unpaid['items'][] = $entry->name;
$unpaid['amount'] += floatval($entry->averageAmount);
} else {
$paid['items'][] = $entry->description;
$paid['amount'] += floatval($entry->actualAmount);
}
}
$this->_chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
$this->_chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
* TODO see reports for better way to do this.
*
* @param $year
*
@@ -444,7 +489,6 @@ class GoogleChartController extends BaseController
}
/**
* TODO see reports for better way to do this.
*
* @param $year
*

View File

@@ -1,7 +1,10 @@
<?php
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class HelpController
*
*/
class HelpController extends BaseController
{
@@ -12,33 +15,70 @@ class HelpController extends BaseController
*/
public function show($route)
{
$helpText = '<p>There is no help for this route!</p>';
$helpTitle = 'Help';
$content = [
'text' => '<p>There is no help for this route!</p>',
'title' => 'Help',
];
if (!Route::has($route)) {
return Response::json(['title' => $helpTitle, 'text' => $helpText]);
\Log::error('No such route: ' . $route);
return Response::json($content);
}
// content in cache
if (Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text')) {
$helpText = Cache::get('help.' . $route . '.text');
$helpTitle = Cache::get('help.' . $route . '.title');
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);
return Response::json(['title' => $helpTitle, 'text' => $helpText]);
}
/**
* @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' => '<p>There is no help for this route!</p>',
'title' => $route,
];
try {
$content = file_get_contents($uri);
$content['text'] = file_get_contents($uri);
} catch (ErrorException $e) {
$content = '<p>There is no help for this route.</p>';
\Log::error(trim($e->getMessage()));
}
$helpText = \Michelf\Markdown::defaultTransform($content);
$helpTitle = $route;
if (strlen(trim($content['text'])) == 0) {
$content['text'] = '<p>There is no help for this route.</p>';
}
$content['text'] = \Michelf\Markdown::defaultTransform($content['text']);
Cache::put('help.' . $route . '.text', $helpText, 10080); // a week.
Cache::put('help.' . $route . '.title', $helpTitle, 10080);
return $content;
return Response::json(['title' => $helpTitle, 'text' => $helpText]);
}
}

View File

@@ -7,6 +7,7 @@ use Carbon\Carbon;
*/
class HomeController extends BaseController
{
/**
* @return \Illuminate\Http\RedirectResponse
*/
@@ -26,29 +27,29 @@ class HomeController extends BaseController
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $jrnls */
$jrnls = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $journalRepository */
$journalRepository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
/** @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());
// get the preference for the home accounts to show:
$frontpage = $preferences->get('frontpageAccounts', []);
if ($frontpage->data == []) {
$accounts = $acct->getAssetAccounts();
$frontPage = $preferences->get('frontPageAccounts', []);
if ($frontPage->data == []) {
$accounts = $acct->getAccountsByType(['Default account', 'Asset account']);
} else {
$accounts = $acct->getByIds($frontpage->data);
$accounts = $acct->getByIds($frontPage->data);
}
$transactions = [];
foreach ($accounts as $account) {
$set = $jrnls->getInDateRangeAccount($account, $start, $end, 10);
$set = $journalRepository->getInDateRangeAccount($account, $start, $end, 10);
if (count($set) > 0) {
$transactions[] = [$set, $account];
}
@@ -76,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();
}
}
/**
@@ -87,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();
}
}
/**
@@ -97,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();
}
}
}

View File

@@ -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;

View File

@@ -8,15 +8,12 @@ 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
* Class PiggyBankController
*
*/
class PiggybankController extends BaseController
class PiggyBankController extends BaseController
{
/** @var Repository */
@@ -35,29 +32,21 @@ class PiggybankController extends BaseController
/**
* Add money to piggy bank
*
* @param Piggybank $piggybank
* @param PiggyBank $piggyBank
*
* @return $this
*/
public function add(Piggybank $piggybank)
public function add(PiggyBank $piggyBank)
{
\Log::debug('Now in add() for piggy bank #' . $piggybank->id . ' (' . $piggybank->name . ')');
\Log::debug('Z');
\Log::debug('currentRelevantRep is null: ' . boolstr($piggybank->currentRelevantRep()));
$leftOnAccount = $this->_repository->leftOnAccount($piggybank->account);
\Log::debug('A');
$savedSoFar = $piggybank->currentRelevantRep()->currentamount;
\Log::debug('B');
$leftToSave = $piggybank->targetamount - $savedSoFar;
\Log::debug('C');
$leftOnAccount = $this->_repository->leftOnAccount($piggyBank->account);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = $piggyBank->targetamount - $savedSoFar;
$maxAmount = min($leftOnAccount, $leftToSave);
\Log::debug('D');
\Log::debug('Now going to view for piggy bank #' . $piggybank->id . ' (' . $piggybank->name . ')');
\Log::debug('Now going to view for piggy bank #' . $piggyBank->id . ' (' . $piggyBank->name . ')');
return View::make('piggybanks.add', compact('piggybank', 'maxAmount'));
return View::make('piggy_banks.add', compact('piggyBank', 'maxAmount'));
}
/**
@@ -69,75 +58,77 @@ class PiggybankController extends BaseController
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
$periods = Config::get('firefly.piggybank_periods');
$accounts = FFForm::makeSelectList($acct->getAssetAccounts());
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account']));
$subTitle = 'Create new piggy bank';
$subTitleIcon = 'fa-plus';
return View::make('piggybanks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon'));
return View::make('piggy_banks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon'));
}
/**
* @param Piggybank $piggybank
* @param PiggyBank $piggyBank
*
* @return $this
*/
public function delete(Piggybank $piggybank)
public function delete(PiggyBank $piggyBank)
{
$subTitle = 'Delete "' . e($piggybank->name) . '"';
$subTitle = 'Delete "' . e($piggyBank->name) . '"';
return View::make('piggybanks.delete', compact('piggybank', 'subTitle'));
return View::make('piggy_banks.delete', compact('piggyBank', 'subTitle'));
}
/**
* @param Piggybank $piggyBank
* @param PiggyBank $piggyBank
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Piggybank $piggyBank)
public function destroy(PiggyBank $piggyBank)
{
Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.');
$this->_repository->destroy($piggyBank);
return Redirect::route('piggybanks.index');
return Redirect::route('piggy_banks.index');
}
/**
* @param Piggybank $piggybank
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param PiggyBank $piggyBank
*
* @return $this
*/
public function edit(Piggybank $piggybank)
public function edit(PiggyBank $piggyBank)
{
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
$periods = Config::get('firefly.piggybank_periods');
$accounts = FFForm::makeSelectList($acct->getAssetAccounts());
$subTitle = 'Edit piggy bank "' . e($piggybank->name) . '"';
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account']));
$subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"';
$subTitleIcon = 'fa-pencil';
/*
* Flash some data to fill the form.
*/
if (is_null($piggybank->targetdate) || $piggybank->targetdate == '') {
if (is_null($piggyBank->targetdate) || $piggyBank->targetdate == '') {
$targetDate = null;
} else {
$targetDate = new Carbon($piggybank->targetdate);
$targetDate = new Carbon($piggyBank->targetdate);
$targetDate = $targetDate->format('Y-m-d');
}
$preFilled = ['name' => $piggybank->name,
'account_id' => $piggybank->account_id,
'targetamount' => $piggybank->targetamount,
$preFilled = ['name' => $piggyBank->name,
'account_id' => $piggyBank->account_id,
'targetamount' => $piggyBank->targetamount,
'targetdate' => $targetDate,
'reminder' => $piggybank->reminder,
'remind_me' => intval($piggybank->remind_me) == 1 || !is_null($piggybank->reminder) ? true : false
'reminder' => $piggyBank->reminder,
'remind_me' => intval($piggyBank->remind_me) == 1 || !is_null($piggyBank->reminder) ? true : false
];
Session::flash('preFilled', $preFilled);
return View::make('piggybanks.edit', compact('subTitle', 'subTitleIcon', 'piggybank', 'accounts', 'periods', 'preFilled'));
return View::make('piggy_banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'accounts', 'periods', 'preFilled'));
}
/**
@@ -145,134 +136,134 @@ class PiggybankController extends BaseController
*/
public function index()
{
/** @var Collection $piggybanks */
$piggybanks = $this->_repository->get();
/** @var Collection $piggyBanks */
$piggyBanks = $this->_repository->get();
$accounts = [];
/** @var Piggybank $piggybank */
foreach ($piggybanks as $piggybank) {
$piggybank->savedSoFar = floatval($piggybank->currentRelevantRep()->currentamount);
$piggybank->percentage = intval($piggybank->savedSoFar / $piggybank->targetamount * 100);
$piggybank->leftToSave = $piggybank->targetamount - $piggybank->savedSoFar;
/** @var PiggyBank $piggyBank */
foreach ($piggyBanks as $piggyBank) {
$piggyBank->savedSoFar = floatval($piggyBank->currentRelevantRep()->currentamount);
$piggyBank->percentage = intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100);
$piggyBank->leftToSave = $piggyBank->targetamount - $piggyBank->savedSoFar;
/*
* Fill account information:
*/
$account = $piggybank->account;
$account = $piggyBank->account;
if (!isset($accounts[$account->id])) {
$accounts[$account->id] = [
'name' => $account->name,
'balance' => Steam::balance($account),
'leftForPiggybanks' => $this->_repository->leftOnAccount($account),
'sumOfSaved' => $piggybank->savedSoFar,
'sumOfTargets' => floatval($piggybank->targetamount),
'leftToSave' => $piggybank->leftToSave
'leftForPiggyBanks' => $this->_repository->leftOnAccount($account),
'sumOfSaved' => $piggyBank->savedSoFar,
'sumOfTargets' => floatval($piggyBank->targetamount),
'leftToSave' => $piggyBank->leftToSave
];
} else {
$accounts[$account->id]['sumOfSaved'] += $piggybank->savedSoFar;
$accounts[$account->id]['sumOfTargets'] += floatval($piggybank->targetamount);
$accounts[$account->id]['leftToSave'] += $piggybank->leftToSave;
$accounts[$account->id]['sumOfSaved'] += $piggyBank->savedSoFar;
$accounts[$account->id]['sumOfTargets'] += floatval($piggyBank->targetamount);
$accounts[$account->id]['leftToSave'] += $piggyBank->leftToSave;
}
}
return View::make('piggybanks.index', compact('piggybanks', 'accounts'));
return View::make('piggy_banks.index', compact('piggyBanks', 'accounts'));
}
/**
* POST add money to piggy bank
*
* @param Piggybank $piggybank
* @param PiggyBank $piggyBank
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postAdd(Piggybank $piggybank)
public function postAdd(PiggyBank $piggyBank)
{
$amount = round(floatval(Input::get('amount')), 2);
/** @var \FireflyIII\Database\PiggyBank\PiggyBank $acct */
$repos = App::make('FireflyIII\Database\PiggyBank\PiggyBank');
$piggyRepository = App::make('FireflyIII\Database\PiggyBank\PiggyBank');
$leftOnAccount = $repos->leftOnAccount($piggybank->account);
$savedSoFar = $piggybank->currentRelevantRep()->currentamount;
$leftToSave = $piggybank->targetamount - $savedSoFar;
$leftOnAccount = $piggyRepository->leftOnAccount($piggyBank->account);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = $piggyBank->targetamount - $savedSoFar;
$maxAmount = round(min($leftOnAccount, $leftToSave), 2);
if ($amount <= $maxAmount) {
$repetition = $piggybank->currentRelevantRep();
$repetition = $piggyBank->currentRelevantRep();
$repetition->currentamount += $amount;
$repetition->save();
/*
* Create event!
*/
Event::fire('piggybank.addMoney', [$piggybank, $amount]); // new and used.
Event::fire('piggy_bank.addMoney', [$piggyBank, $amount]); // new and used.
Session::flash('success', 'Added ' . mf($amount, false) . ' to "' . e($piggybank->name) . '".');
Session::flash('success', 'Added ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".');
} else {
Session::flash('error', 'Could not add ' . mf($amount, false) . ' to "' . e($piggybank->name) . '".');
Session::flash('error', 'Could not add ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".');
}
return Redirect::route('piggybanks.index');
return Redirect::route('piggy_banks.index');
}
/**
* @param Piggybank $piggybank
* @param PiggyBank $piggyBank
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postRemove(Piggybank $piggybank)
public function postRemove(PiggyBank $piggyBank)
{
$amount = floatval(Input::get('amount'));
$savedSoFar = $piggybank->currentRelevantRep()->currentamount;
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
if ($amount <= $savedSoFar) {
$repetition = $piggybank->currentRelevantRep();
$repetition = $piggyBank->currentRelevantRep();
$repetition->currentamount -= $amount;
$repetition->save();
/*
* Create event!
*/
Event::fire('piggybank.removeMoney', [$piggybank, $amount]); // new and used.
Event::fire('piggy_bank.removeMoney', [$piggyBank, $amount]); // new and used.
Session::flash('success', 'Removed ' . mf($amount, false) . ' from "' . e($piggybank->name) . '".');
Session::flash('success', 'Removed ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".');
} else {
Session::flash('error', 'Could not remove ' . mf($amount, false) . ' from "' . e($piggybank->name) . '".');
Session::flash('error', 'Could not remove ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".');
}
return Redirect::route('piggybanks.index');
return Redirect::route('piggy_banks.index');
}
/**
* @param Piggybank $piggybank
* @param PiggyBank $piggyBank
*
* @SuppressWarnings("Unused")
*
* @return \Illuminate\View\View
*/
public function remove(Piggybank $piggybank)
public function remove(PiggyBank $piggyBank)
{
return View::make('piggybanks.remove')->with('piggybank', $piggybank);
return View::make('piggy_banks.remove', compact('piggyBank'));
}
/**
* @param Piggybank $piggybank
* @param PiggyBank $piggyBank
*
* @return $this
*/
public function show(Piggybank $piggybank)
public function show(PiggyBank $piggyBank)
{
$events = $piggybank->piggybankevents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get();
$events = $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get();
/*
* Number of reminders:
*/
$amountPerReminder = $piggybank->amountPerReminder();
$remindersCount = $piggybank->countFutureReminders();
$subTitle = e($piggybank->name);
$subTitle = e($piggyBank->name);
return View::make('piggybanks.show', compact('amountPerReminder', 'remindersCount', 'piggybank', 'events', 'subTitle'));
return View::make('piggy_banks.show', compact('piggyBank', 'events', 'subTitle'));
}
@@ -284,6 +275,10 @@ class PiggybankController extends BaseController
$data = Input::all();
$data['repeats'] = 0;
$data['user_id'] = Auth::user()->id;
$data['rep_every'] = 0;
$data['reminder_skip'] = 0;
$data['remind_me'] = intval(Input::get('remind_me'));
$data['order'] = 0;
// always validate:
@@ -295,32 +290,33 @@ 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) {
return Redirect::route('piggybanks.create')->withInput();
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('piggy_banks.create')->withInput();
}
// store:
// store
$piggyBank = $this->_repository->store($data);
Event::fire('piggybank.store', [$piggyBank]); // new and used.
Event::fire('piggy_bank.store', [$piggyBank]); // new and used.
Session::flash('success', 'Piggy bank "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('piggybanks.index');
return Redirect::route('piggy_banks.index');
}
return Redirect::route('piggybanks.create')->withInput();
return Redirect::route('piggy_banks.create')->withInput();
}
/**
* @param Piggybank $piggyBank
* @param PiggyBank $piggyBank
*
* @return $this
* @throws FireflyException
*/
public function update(Piggybank $piggyBank)
public function update(PiggyBank $piggyBank)
{
$data = Input::except('_token');
@@ -329,21 +325,22 @@ class PiggybankController extends BaseController
$data['order'] = 0;
$data['remind_me'] = isset($data['remind_me']) ? 1 : 0;
$data['user_id'] = Auth::user()->id;
$data['repeats'] = 0;
// always validate:
$messages = $this->_repository->validate($data);
// flash messages:
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
Session::flash('error', 'Could not update 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) {
return Redirect::route('piggybanks.edit', $piggyBank->id)->withInput();
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('piggy_banks.edit', $piggyBank->id)->withInput();
}
// update
@@ -352,11 +349,11 @@ class PiggybankController extends BaseController
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('piggybanks.index');
return Redirect::route('piggy_banks.index');
}
// go back to update screen.
return Redirect::route('piggybanks.edit', $piggyBank->id)->withInput(['post_submit_action' => 'return_to_edit']);
return Redirect::route('piggy_banks.edit', $piggyBank->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
}

View File

@@ -3,7 +3,6 @@
/**
* Class PreferencesController
*
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
*
*/
class PreferencesController extends BaseController
@@ -29,14 +28,14 @@ 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', []);
$frontPage = $preferences->get('frontPageAccounts', []);
$budgetMax = $preferences->get('budgetMaximum', 1000);
$budgetMaximum = $budgetMax->data;
return View::make('preferences.index', compact('budgetMaximum'))->with('accounts', $accounts)->with('frontpageAccounts', $frontPage)->with(
return View::make('preferences.index', compact('budgetMaximum'))->with('accounts', $accounts)->with('frontPageAccounts', $frontPage)->with(
'viewRange', $viewRangeValue
);
}
@@ -49,12 +48,12 @@ class PreferencesController extends BaseController
/** @var \FireflyIII\Shared\Preferences\Preferences $preferences */
$preferences = App::make('FireflyIII\Shared\Preferences\Preferences');
// frontpage accounts
$frontpageAccounts = [];
foreach (Input::get('frontpageAccounts') as $id) {
$frontpageAccounts[] = intval($id);
// front page accounts
$frontPageAccounts = [];
foreach (Input::get('frontPageAccounts') as $id) {
$frontPageAccounts[] = intval($id);
}
$preferences->set('frontpageAccounts', $frontpageAccounts);
$preferences->set('frontPageAccounts', $frontPageAccounts);
// view range:
$preferences->set('viewRange', Input::get('viewRange'));

View File

@@ -1,6 +1,7 @@
<?php
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
* Class ProfileController
*/
class ProfileController extends BaseController
@@ -37,19 +38,9 @@ class ProfileController extends BaseController
return View::make('profile.change-password');
}
if (strlen(Input::get('new1')) == 0 || strlen(Input::get('new2')) == 0) {
Session::flash('error', 'Do fill in a password!');
return View::make('profile.change-password');
}
if (Input::get('new1') == Input::get('old')) {
Session::flash('error', 'The idea is to change your password.');
return View::make('profile.change-password');
}
if (Input::get('new1') !== Input::get('new2')) {
Session::flash('error', 'New passwords do not match!');
$result = $this->_validatePassword(Input::get('old'), Input::get('new1'), Input::get('new2'));
if (!($result === true)) {
Session::flash('error', $result);
return View::make('profile.change-password');
}
@@ -64,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;
}
}

View File

@@ -1,227 +0,0 @@
<?php
use FireflyIII\Exception\FireflyException;
use Illuminate\Support\MessageBag;
/**
* Class RecurringController
*
*/
class RecurringController extends BaseController
{
/**
*
*/
public function __construct()
{
View::share('title', 'Recurring transactions');
View::share('mainTitleIcon', 'fa-rotate-right');
}
/**
* @return $this
*/
public function create()
{
$periods = \Config::get('firefly.periods_to_text');
return View::make('recurring.create')->with('periods', $periods)->with('subTitle', 'Create new');
}
/**
* @param RecurringTransaction $recurringTransaction
*
* @return $this
*/
public function delete(RecurringTransaction $recurringTransaction)
{
return View::make('recurring.delete')->with('recurringTransaction', $recurringTransaction)->with(
'subTitle', 'Delete "' . $recurringTransaction->name . '"'
);
}
/**
* @param RecurringTransaction $recurringTransaction
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(RecurringTransaction $recurringTransaction)
{
//Event::fire('recurring.destroy', [$recurringTransaction]);
/** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repository */
$repository = App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction');
$result = $repository->destroy($recurringTransaction);
if ($result === true) {
Session::flash('success', 'The recurring transaction was deleted.');
} else {
Session::flash('error', 'Could not delete the recurring transaction. Check the logs to be sure.');
}
return Redirect::route('recurring.index');
}
/**
* @param RecurringTransaction $recurringTransaction
*
* @return $this
*/
public function edit(RecurringTransaction $recurringTransaction)
{
$periods = \Config::get('firefly.periods_to_text');
return View::make('recurring.edit')->with('periods', $periods)->with('recurringTransaction', $recurringTransaction)->with(
'subTitle', 'Edit "' . $recurringTransaction->name . '"'
);
}
/**
* @return $this
*/
public function index()
{
/** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repos */
$repos = App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction');
$recurring = $repos->get();
return View::make('recurring.index', compact('recurring'));
}
/**
* @param RecurringTransaction $recurringTransaction
*
* @return mixed
*/
public function rescan(RecurringTransaction $recurringTransaction)
{
if (intval($recurringTransaction->active) == 0) {
Session::flash('warning', 'Inactive recurring transactions cannot be scanned.');
return Redirect::back();
}
/** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repos */
$repos = App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction');
$repos->scanEverything($recurringTransaction);
Session::flash('success', 'Rescanned everything.');
return Redirect::back();
}
/**
* @param RecurringTransaction $recurringTransaction
*
* @return mixed
*/
public function show(RecurringTransaction $recurringTransaction)
{
$journals = $recurringTransaction->transactionjournals()->withRelevantData()->orderBy('date', 'DESC')->get();
$hideRecurring = true;
return View::make('recurring.show', compact('journals', 'hideRecurring', 'finalDate'))->with('recurring', $recurringTransaction)->with(
'subTitle', $recurringTransaction->name
);
}
/**
* @return $this
* @throws FireflyException
*/
public function store()
{
$data = Input::except('_token');
/** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repos */
$repos = App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction');
switch ($data['post_submit_action']) {
default:
throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"');
break;
case 'create_another':
case 'store':
$messages = $repos->validate($data);
/** @var MessageBag $messages ['errors'] */
if ($messages['errors']->count() > 0) {
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('error', 'Could not save recurring transaction: ' . $messages['errors']->first());
return Redirect::route('recurring.create')->withInput()->withErrors($messages['errors']);
}
// store!
$repos->store($data);
Session::flash('success', 'New recurring transaction stored!');
if ($data['post_submit_action'] == 'create_another') {
return Redirect::route('recurring.create')->withInput();
} else {
return Redirect::route('recurring.index');
}
break;
case 'validate_only':
$messageBags = $repos->validate($data);
Session::flash('warnings', $messageBags['warnings']);
Session::flash('successes', $messageBags['successes']);
Session::flash('errors', $messageBags['errors']);
return Redirect::route('recurring.create')->withInput();
break;
}
}
/**
* @param RecurringTransaction $recurringTransaction
*
* @return $this
* @throws FireflyException
*/
public function update(RecurringTransaction $recurringTransaction)
{
/** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repos */
$repos = App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction');
$data = Input::except('_token');
$data['active'] = isset($data['active']) ? 1 : 0;
$data['automatch'] = isset($data['automatch']) ? 1 : 0;
switch (Input::get('post_submit_action')) {
default:
throw new FireflyException('Cannot handle post_submit_action "' . e(Input::get('post_submit_action')) . '"');
break;
case 'create_another':
case 'update':
$messages = $repos->validate($data);
/** @var MessageBag $messages ['errors'] */
if ($messages['errors']->count() > 0) {
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('error', 'Could not save recurring transaction: ' . $messages['errors']->first());
return Redirect::route('recurring.edit', $recurringTransaction->id)->withInput()->withErrors($messages['errors']);
}
// store!
$repos->update($recurringTransaction, $data);
Session::flash('success', 'Recurring transaction updated!');
if ($data['post_submit_action'] == 'create_another') {
return Redirect::route('recurring.edit', $recurringTransaction->id);
} else {
return Redirect::route('recurring.index');
}
case 'validate_only':
$messageBags = $repos->validate($data);
Session::flash('warnings', $messageBags['warnings']);
Session::flash('successes', $messageBags['successes']);
Session::flash('errors', $messageBags['errors']);
return Redirect::route('recurring.edit', $recurringTransaction->id)->withInput();
break;
}
}
}

View File

@@ -0,0 +1,148 @@
<?php
use FireflyIII\Helper\Related\RelatedInterface;
use Illuminate\Support\Collection;
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class RelatedController
*/
class RelatedController extends BaseController
{
protected $_repository;
/**
* @param RelatedInterface $repository
*/
public function __construct(RelatedInterface $repository)
{
$this->_repository = $repository;
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param TransactionJournal $journal
*
* @return \Illuminate\Http\JsonResponse
*/
public function alreadyRelated(TransactionJournal $journal)
{
$ids = [];
/** @var TransactionGroup $group */
foreach ($journal->transactiongroups()->get() as $group) {
/** @var TransactionJournal $loopJournal */
foreach ($group->transactionjournals()->get() as $loopJournal) {
if ($loopJournal->id != $journal->id) {
$ids[] = $loopJournal->id;
}
}
}
$unique = array_unique($ids);
if (count($unique) > 0) {
$set = $this->_repository->getJournalsByIds($unique);
$set->each(
function (TransactionJournal $journal) {
$journal->amount = Amount::format($journal->getAmount());
}
);
return Response::json($set->toArray());
} else {
return Response::json((new Collection)->toArray());
}
}
/**
* @param TransactionJournal $parentJournal
* @param TransactionJournal $childJournal
*
* @return \Illuminate\Http\JsonResponse
*/
public function relate(TransactionJournal $parentJournal, TransactionJournal $childJournal)
{
$group = new TransactionGroup;
$group->relation = 'balance';
$group->user_id = $this->_repository->getUser()->id;
$group->save();
$group->transactionjournals()->save($parentJournal);
$group->transactionjournals()->save($childJournal);
return Response::json(true);
}
/**
* @param TransactionJournal $journal
*
* @return \Illuminate\View\View
*/
public function related(TransactionJournal $journal)
{
$groups = $journal->transactiongroups()->get();
$members = new Collection;
/** @var TransactionGroup $group */
foreach ($groups as $group) {
/** @var TransactionJournal $loopJournal */
foreach ($group->transactionjournals()->get() as $loopJournal) {
if ($loopJournal->id != $journal->id) {
$members->push($loopJournal);
}
}
}
return View::make('related.relate', compact('journal', 'members'));
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param TransactionJournal $parentJournal
* @param TransactionJournal $childJournal
*
* @return \Illuminate\Http\JsonResponse
* @throws Exception
*/
public function removeRelation(TransactionJournal $parentJournal, TransactionJournal $childJournal)
{
$groups = $parentJournal->transactiongroups()->get();
/** @var TransactionGroup $group */
foreach ($groups as $group) {
foreach ($group->transactionjournals()->get() as $loopJournal) {
if ($loopJournal->id == $childJournal->id) {
// remove from group:
$group->transactionjournals()->detach($childJournal);
}
}
if ($group->transactionjournals()->count() == 1) {
$group->delete();
}
}
return Response::json(true);
}
/**
* @param TransactionJournal $journal
*
* @return \Illuminate\Http\JsonResponse
*/
public function search(TransactionJournal $journal)
{
$search = e(trim(Input::get('searchValue')));
$result = $this->_repository->search($search, $journal);
$result->each(
function (TransactionJournal $j) {
$j->amount = Amount::format($j->getAmount());
}
);
return Response::json($result->toArray());
}
}

View File

@@ -26,25 +26,22 @@ class ReminderController extends BaseController
public function act(Reminder $reminder)
{
switch (get_class($reminder->remindersable)) {
default:
throw new FireflyException('Cannot act on reminder for ' . get_class($reminder->remindersable));
break;
break;
case 'Piggybank':
$class = get_class($reminder->remindersable);
if ($class == 'PiggyBank') {
$amount = Reminders::amountForReminder($reminder);
$preFilled = [
'amount' => round($amount, 2),
'description' => 'Money for ' . $reminder->remindersable->name,
'piggybank_id' => $reminder->remindersable_id,
'piggy_bank_id' => $reminder->remindersable_id,
'account_to_id' => $reminder->remindersable->account_id
];
Session::flash('preFilled', $preFilled);
return Redirect::route('transactions.create', 'transfer');
break;
}
return View::make('error')->with('message', 'This reminder has an invalid class connected to it.');
}
/**
@@ -66,7 +63,7 @@ class ReminderController extends BaseController
*
* @return \Illuminate\Http\RedirectResponse
*/
public function notnow(Reminder $reminder)
public function notNow(Reminder $reminder)
{
$reminder->active = 0;
$reminder->notnow = 1;
@@ -85,7 +82,7 @@ class ReminderController extends BaseController
{
$amount = null;
if (get_class($reminder->remindersable) == 'Piggybank') {
if (get_class($reminder->remindersable) == 'PiggyBank') {
$amount = Reminders::amountForReminder($reminder);
}

View File

@@ -5,6 +5,8 @@ use FireflyIII\Database\PiggyBank\RepeatedExpense as Repository;
use FireflyIII\Exception\FireflyException;
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class RepeatedExpenseController
*/
class RepeatedExpenseController extends BaseController
@@ -29,17 +31,71 @@ 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->getAccountsByType(['Default account', 'Asset account']));
$periods = Config::get('firefly.piggybank_periods');
$accounts = FFForm::makeSelectList($acct->getAssetAccounts());
return View::make('repeatedexpense.create', compact('accounts', 'periods'))->with('subTitle', 'Create new repeated expense')->with(
return View::make('repeatedExpense.create', compact('accounts', 'periods'))->with('subTitle', 'Create new repeated expense')->with(
'subTitleIcon', 'fa-plus'
);
}
/**
* @param PiggyBank $repeatedExpense
*
* @return $this
*/
public function delete(PiggyBank $repeatedExpense)
{
$subTitle = 'Delete "' . e($repeatedExpense->name) . '"';
return View::make('repeatedExpense.delete', compact('repeatedExpense', 'subTitle'));
}
/**
* @param PiggyBank $repeatedExpense
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(PiggyBank $repeatedExpense)
{
Session::flash('success', 'Repeated expense "' . e($repeatedExpense->name) . '" deleted.');
$this->_repository->destroy($repeatedExpense);
return Redirect::route('repeated.index');
}
/**
* @param PiggyBank $repeatedExpense
*
* @return $this
*/
public function edit(PiggyBank $repeatedExpense)
{
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account']));
$subTitle = 'Edit repeated expense "' . e($repeatedExpense->name) . '"';
$subTitleIcon = 'fa-pencil';
/*
* Flash some data to fill the form.
*/
$preFilled = ['name' => $repeatedExpense->name,
'account_id' => $repeatedExpense->account_id,
'targetamount' => $repeatedExpense->targetamount,
'targetdate' => $repeatedExpense->targetdate->format('Y-m-d'),
'reminder' => $repeatedExpense->reminder,
'remind_me' => intval($repeatedExpense->remind_me) == 1 || !is_null($repeatedExpense->reminder) ? true : false
];
Session::flash('preFilled', $preFilled);
return View::make('repeatedExpense.edit', compact('subTitle', 'subTitleIcon', 'repeatedExpense', 'accounts', 'periods', 'preFilled'));
}
/**
* @return \Illuminate\View\View
*/
@@ -48,78 +104,124 @@ class RepeatedExpenseController extends BaseController
$subTitle = 'Overview';
/** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repository */
$repository = App::make('FireflyIII\Database\PiggyBank\RepeatedExpense');
$expenses = $repository->get();
$expenses = $this->_repository->get();
$expenses->each(
function (Piggybank $piggyBank) use ($repository) {
function (PiggyBank $piggyBank) {
$piggyBank->currentRelevantRep();
}
);
return View::make('repeatedexpense.index', compact('expenses', 'subTitle'));
return View::make('repeatedExpense.index', compact('expenses', 'subTitle'));
}
/**
* @param Piggybank $piggyBank
* @param PiggyBank $repeatedExpense
*
* @return \Illuminate\View\View
*/
public function show(Piggybank $piggyBank)
public function show(PiggyBank $repeatedExpense)
{
$subTitle = $piggyBank->name;
$subTitle = $repeatedExpense->name;
$today = Carbon::now();
$repetitions = $repeatedExpense->piggyBankRepetitions()->get();
/** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repository */
$repository = App::make('FireflyIII\Database\PiggyBank\RepeatedExpense');
$repetitions = $piggyBank->piggybankrepetitions()->get();
$repetitions->each(
function (PiggybankRepetition $repetition) use ($repository) {
$repetition->bars = $repository->calculateParts($repetition);
function (PiggyBankRepetition $repetition) {
$repetition->bars = $this->_repository->calculateParts($repetition);
}
);
return View::make('repeatedexpense.show', compact('repetitions', 'piggyBank', 'today', 'subTitle'));
return View::make('repeatedExpense.show', compact('repetitions', 'repeatedExpense', 'today', 'subTitle'));
}
/**
* @return $this
* @throws FireflyException
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*/
public function store()
{
$data = Input::except('_token');
$data = Input::all();
$data['repeats'] = 1;
$data['user_id'] = Auth::user()->id;
$targetDate = new Carbon($data['targetdate']);
$startDate = \DateKit::subtractPeriod($targetDate, $data['rep_length']);
$data['startdate'] = $startDate->format('Y-m-d');
$data['targetdate'] = $targetDate->format('Y-m-d');
$data['reminder_skip'] = 0;
$data['remind_me'] = isset($data['remind_me']) ? 1 : 0;
$data['order'] = 0;
// always validate:
$messages = $this->_repository->validate($data);
// flash messages:
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
Session::flash('error', 'Could not validate repeated expense: ' . $messages['errors']->first());
}
// return to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
Session::flash('error', 'Could not store repeated expense: ' . $messages['errors']->first());
return Redirect::route('repeated.create')->withInput();
}
// store:
$this->_repository->store($data);
Session::flash('success', 'Budget "' . e($data['name']) . '" stored.');
// return to create screen:
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('repeated.create')->withInput();
}
// store
$piggyBank = $this->_repository->store($data);
Event::fire('piggy_bank.store', [$piggyBank]); // new and used.
Session::flash('success', 'Piggy bank "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('repeated.index');
}
// create another.
if ($data['post_submit_action'] == 'create_another') {
return Redirect::route('repeated.create')->withInput();
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param PiggyBank $repeatedExpense
*
* @return $this
* @throws FireflyException
*/
public function update(PiggyBank $repeatedExpense)
{
$data = Input::except('_token');
$data['rep_every'] = 0;
$data['reminder_skip'] = 0;
$data['order'] = 0;
$data['repeats'] = 1;
$data['remind_me'] = isset($data['remind_me']) ? 1 : 0;
$data['user_id'] = Auth::user()->id;
$messages = $this->_repository->validate($data);
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
Session::flash('error', 'Could not update repeated expense: ' . $messages['errors']->first());
return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput();
}
// return to update screen:
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput();
}
// update
$this->_repository->update($repeatedExpense, $data);
Session::flash('success', 'Repeated expense "' . e($data['name']) . '" updated.');
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('repeated.index');
}
// go back to update screen.
return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
}

View File

@@ -1,34 +1,62 @@
<?php
use Carbon\Carbon;
use FireflyIII\Database\Account\Account as AccountRepository;
use FireflyIII\Database\TransactionJournal\TransactionJournal as TransactionJournalRepository;
use FireflyIII\Report\ReportInterface as Report;
/**
*
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class ReportController
*/
class ReportController extends BaseController
{
/** @var AccountRepository */
protected $_accounts;
/** @var \FireflyIII\Database\Budget\Budget */
protected $_budgets;
/** @var TransactionJournalRepository */
protected $_journals;
/** @var Report */
protected $_repository;
/**
* @param AccountRepository $accounts
* @param TransactionJournalRepository $journals
* @param Report $repository
*/
public function __construct(AccountRepository $accounts, TransactionJournalRepository $journals, Report $repository)
public function __construct(TransactionJournalRepository $journals, Report $repository)
{
$this->_accounts = $accounts;
$this->_journals = $journals;
$this->_repository = $repository;
/** @var \FireflyIII\Database\Budget\Budget _budgets */
$this->_budgets = App::make('FireflyIII\Database\Budget\Budget');
View::share('title', 'Reports');
View::share('mainTitleIcon', 'fa-line-chart');
}
/**
* @param string $year
* @param string $month
*
* @return \Illuminate\View\View
*/
public function budget($year = '2014', $month = '1')
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return View::make('error')->with('message', 'Invalid date');
}
$date = new Carbon($year . '-' . $month . '-01');
$dayEarly = clone $date;
$subTitle = 'Budget report for ' . $date->format('F Y');
$subTitleIcon = 'fa-calendar';
$dayEarly = $dayEarly->subDay();
$accounts = $this->_repository->getAccountListBudgetOverview($date);
$budgets = $this->_repository->getBudgetsForMonth($date);
return View::make('reports.budget', compact('subTitle', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly'));
}
@@ -47,58 +75,32 @@ class ReportController extends BaseController
}
/**
* @param $year
* @param $month
* @param string $year
* @param string $month
*
* @return \Illuminate\View\View
*/
public function unbalanced($year, $month)
public function month($year = '2014', $month = '1')
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
App::abort(500);
return View::make('error')->with('message', 'Invalid date.');
}
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$title = 'Reports';
$subTitle = 'Unbalanced transactions in ' . $start->format('F Y');
$mainTitleIcon = 'fa-line-chart';
$subTitleIcon = 'fa-bar-chart';
$end->endOfMonth();
$date = new Carbon($year . '-' . $month . '-01');
$subTitle = 'Report for ' . $date->format('F Y');
$subTitleIcon = 'fa-calendar';
$displaySum = true; // to show sums in report.
$income = $this->_repository->getIncomeForMonth($date);
$expenses = $this->_repository->getExpenseGroupedForMonth($date, 10);
$budgets = $this->_repository->getBudgetsForMonth($date);
$categories = $this->_repository->getCategoriesForMonth($date, 10);
$accounts = $this->_repository->getAccountsForMonth($date);
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $journalRepository */
$journalRepository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
$journals = $journalRepository->getInDateRange($start, $end);
$withdrawals = $journals->filter(
function (TransactionJournal $journal) {
$relations = $journal->transactiongroups()->where('relation', 'balance')->count();
$budgets = $journal->budgets()->count();
$type = $journal->transactionType->type;
if ($type == 'Withdrawal' && $budgets == 0 && $relations == 0) {
return $journal;
}
return null;
}
return View::make(
'reports.month',
compact('date', 'accounts', 'categories', 'budgets', 'expenses', 'subTitle', 'displaySum', 'subTitleIcon', 'income')
);
$deposits = $journals->filter(
function (TransactionJournal $journal) {
$relations = $journal->transactiongroups()->where('relation', 'balance')->count();
$budgets = $journal->budgets()->count();
$type = $journal->transactionType->type;
if ($type == 'Deposit' && $budgets == 0 && $relations == 0) {
return $journal;
}
return null;
}
);
$journals = $withdrawals->merge($deposits);
return View::make('reports.unbalanced', compact('start', 'end', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon', 'journals'));
}
/**
@@ -111,7 +113,7 @@ class ReportController extends BaseController
try {
new Carbon('01-01-' . $year);
} catch (Exception $e) {
App::abort(500);
return View::make('error')->with('message', 'Invalid date.');
}
$date = new Carbon('01-01-' . $year);
$end = clone $date;
@@ -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')
);
}

View File

@@ -17,7 +17,7 @@ class SearchController extends BaseController
$subTitle = null;
$rawQuery = null;
$result = [];
if (!is_null(Input::get('q'))) {
if (!is_null(Input::get('q')) && strlen(Input::get('q')) > 0) {
$rawQuery = trim(Input::get('q'));
$words = explode(' ', $rawQuery);
$subTitle = 'Results for "' . e($rawQuery) . '"';

View File

@@ -1,11 +1,15 @@
<?php
use FireflyIII\Database\TransactionJournal\TransactionJournal as Repository;
use FireflyIII\Exception\FireflyException;
use FireflyIII\Helper\TransactionJournal\HelperInterface as Helper;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
/**
*
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class TransactionController
*
*/
@@ -13,54 +17,25 @@ class TransactionController extends BaseController
{
/** @var Helper */
protected $_helper;
/** @var Repository */
protected $_repository;
/**
* Construct a new transaction controller with two of the most often used helpers.
*
* @param Repository $repository
* @param Helper $helper
*/
public function __construct()
public function __construct(Repository $repository, Helper $helper)
{
$this->_repository = $repository;
$this->_helper = $helper;
View::share('title', 'Transactions');
View::share('mainTitleIcon', 'fa-repeat');
}
/**
*
* TODO this needs cleaning up and thinking over.
*
* @param TransactionJournal $journal
*
* @return array|\Illuminate\Http\JsonResponse
*/
public function alreadyRelated(TransactionJournal $journal)
{
$ids = [];
/** @var TransactionGroup $group */
foreach ($journal->transactiongroups()->get() as $group) {
/** @var TransactionJournal $jrnl */
foreach ($group->transactionjournals()->get() as $jrnl) {
if ($jrnl->id != $journal->id) {
$ids[] = $jrnl->id;
}
}
}
$unique = array_unique($ids);
if (count($unique) > 0) {
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */
$repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
$set = $repository->getByIds($unique);
$set->each(
function (TransactionJournal $journal) {
$journal->amount = mf($journal->getAmount());
}
);
return Response::json($set->toArray());
} else {
return (new Collection)->toArray();
}
}
/**
* Shows the view helping the user to create a new transaction journal.
@@ -71,33 +46,18 @@ class TransactionController extends BaseController
*/
public function create($what = 'deposit')
{
/** @var \FireflyIII\Database\Account\Account $accountRepository */
$accountRepository = App::make('FireflyIII\Database\Account\Account');
/** @var \FireflyIII\Database\Budget\Budget $budgetRepository */
$budgetRepository = App::make('FireflyIII\Database\Budget\Budget');
/** @var \FireflyIII\Database\PiggyBank\PiggyBank $piggyRepository */
$piggyRepository = App::make('FireflyIII\Database\PiggyBank\PiggyBank');
/** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repRepository */
$repRepository = App::make('FireflyIII\Database\PiggyBank\RepeatedExpense');
// get asset accounts with names and id's .
$assetAccounts = FFForm::makeSelectList($accountRepository->getAssetAccounts());
// get budgets as a select list.
$budgets = FFForm::makeSelectList($budgetRepository->get());
$accounts = FFForm::makeSelectList($this->_helper->getAssetAccounts());
$budgets = FFForm::makeSelectList($this->_helper->getBudgets());
$budgets[0] = '(no budget)';
// get the piggy banks.
$list = $piggyRepository->get()->merge($repRepository->get());
$piggyBanks = $this->_helper->getPiggyBanks();
$repeatedExpenses = $this->_helper->getRepeatedExpenses();
$list = $piggyBanks->merge($repeatedExpenses);
$piggies = FFForm::makeSelectList($list);
$piggies[0] = '(no piggy bank)';
asort($piggies);
$preFilled = Session::has('preFilled') ? Session::get('preFilled') : [];
$respondTo = ['account_id', 'account_from_id'];
$subTitle = 'Add a new ' . e($what);
foreach ($respondTo as $r) {
if (!is_null(Input::get($r))) {
$preFilled[$r] = Input::get($r);
@@ -105,24 +65,25 @@ class TransactionController extends BaseController
}
Session::put('preFilled', $preFilled);
return View::make('transactions.create')->with('accounts', $assetAccounts)->with('budgets', $budgets)->with('what', $what)->with('piggies', $piggies)
->with('subTitle', 'Add a new ' . $what);
asort($piggies);
return View::make('transactions.create', compact('accounts', 'budgets', 'what', 'piggies', 'subTitle'));
}
/**
* Shows the form that allows a user to delete a transaction journal.
*
* @param TransactionJournal $transactionJournal
* @param TransactionJournal $journal
*
* @return $this
*/
public function delete(TransactionJournal $transactionJournal)
public function delete(TransactionJournal $journal)
{
$type = strtolower($transactionJournal->transactionType->type);
$type = strtolower($journal->transactionType->type);
$subTitle = 'Delete ' . e($type) . ' "' . e($journal->description) . '"';
return View::make('transactions.delete')->with('journal', $transactionJournal)->with(
'subTitle', 'Delete ' . $type . ' "' . $transactionJournal->description . '"'
);
return View::make('transactions.delete', compact('journal', 'subTitle'));
}
@@ -135,13 +96,11 @@ class TransactionController extends BaseController
public function destroy(TransactionJournal $transactionJournal)
{
$type = $transactionJournal->transactionType->type;
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */
$repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
$repository->destroy($transactionJournal);
$return = 'withdrawal';
Session::flash('success', 'Transaction "' . e($transactionJournal->description) . '" destroyed.');
$this->_repository->destroy($transactionJournal);
switch ($type) {
case 'Deposit':
@@ -155,38 +114,6 @@ class TransactionController extends BaseController
return Redirect::route('transactions.index', $return);
}
/**
* TODO this needs cleaning up and thinking over.
*
* @return \Illuminate\Http\JsonResponse
*/
public function doRelate()
{
$id = intval(Input::get('id'));
$sister = intval(Input::get('relateTo'));
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */
$repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
$journal = $repository->find($id);
$sis = $repository->find($sister);
if ($journal && $sis) {
$group = new TransactionGroup;
$group->relation = 'balance';
$group->user_id = $repository->getUser()->id;
$group->save();
$group->transactionjournals()->save($journal);
$group->transactionjournals()->save($sis);
return Response::json(true);
}
return Response::json(false);
}
/**
* Shows the view to edit a transaction.
*
@@ -196,145 +123,71 @@ class TransactionController extends BaseController
*/
public function edit(TransactionJournal $journal)
{
/*
* All the repositories we need:
*/
/** @var \FireflyIII\Database\Account\Account $accountRepository */
$accountRepository = App::make('FireflyIII\Database\Account\Account');
/** @var \FireflyIII\Database\Budget\Budget $budgetRepository */
$budgetRepository = App::make('FireflyIII\Database\Budget\Budget');
/** @var \FireflyIII\Database\PiggyBank\PiggyBank $piggyRepository */
$piggyRepository = App::make('FireflyIII\Database\PiggyBank\PiggyBank');
// type is useful for display:
$what = strtolower($journal->transactiontype->type);
// get asset accounts with names and id's.
$budgets = FFForm::makeSelectList($budgetRepository->get(), true);
$accounts = FFForm::makeSelectList($accountRepository->getAssetAccounts());
$piggies = FFForm::makeSelectList($piggyRepository->get(), true);
/*
* Data to properly display the edit form.
*/
$subTitle = 'Edit ' . e($what) . ' "' . e($journal->description) . '"';
$budgets = FFForm::makeSelectList($this->_helper->getBudgets(), true);
$accounts = FFForm::makeSelectList($this->_helper->getAssetAccounts());
$piggies = FFForm::makeSelectList($this->_helper->getPiggyBanks(), true);
$transactions = $journal->transactions()->orderBy('amount', 'DESC')->get();
$preFilled = [
'date' => $journal->date->format('Y-m-d'),
'category' => '',
'budget_id' => 0,
'piggybank_id' => 0
'piggy_bank_id' => 0
];
/*
* Fill in the category.
*/
$category = $journal->categories()->first();
if (!is_null($category)) {
$preFilled['category'] = $category->name;
}
/*
* Switch on the type of transaction edited by the user and fill in other
* relevant fields:
*/
switch ($what) {
case 'withdrawal':
if (floatval($journal->transactions[0]->amount) < 0) {
// transactions[0] is the asset account that paid for the withdrawal.
$preFilled['account_id'] = $journal->transactions[0]->account->id;
$preFilled['expense_account'] = $journal->transactions[1]->account->name;
$preFilled['amount'] = floatval($journal->transactions[1]->amount);
} else {
// transactions[1] is the asset account that paid for the withdrawal.
$preFilled['account_id'] = $journal->transactions[1]->account->id;
$preFilled['expense_account'] = $journal->transactions[0]->account->name;
$preFilled['amount'] = floatval($journal->transactions[0]->amount);
}
$budget = $journal->budgets()->first();
if (!is_null($budget)) {
$preFilled['budget_id'] = $budget->id;
}
break;
case 'deposit':
if (floatval($journal->transactions[0]->amount) < 0) {
// transactions[0] contains the account the money came from.
$preFilled['account_id'] = $journal->transactions[1]->account->id;
$preFilled['revenue_account'] = $journal->transactions[0]->account->name;
$preFilled['amount'] = floatval($journal->transactions[1]->amount);
} else {
// transactions[1] contains the account the money came from.
$preFilled['account_id'] = $journal->transactions[0]->account->id;
$preFilled['revenue_account'] = $journal->transactions[1]->account->name;
$preFilled['amount'] = floatval($journal->transactions[0]->amount);
if ($journal->piggyBankEvents()->count() > 0) {
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->first()->piggy_bank_id;
}
break;
case 'transfer':
if (floatval($journal->transactions[0]->amount) < 0) {
// zero = from account.
$preFilled['account_from_id'] = $journal->transactions[0]->account->id;
$preFilled['account_to_id'] = $journal->transactions[1]->account->id;
$preFilled['amount'] = floatval($journal->transactions[1]->amount);
} else {
// one = from account
$preFilled['account_from_id'] = $journal->transactions[1]->account->id;
$preFilled['account_to_id'] = $journal->transactions[0]->account->id;
$preFilled['amount'] = floatval($journal->transactions[0]->amount);
}
if ($journal->piggybankevents()->count() > 0) {
$preFilled['piggybank_id'] = $journal->piggybankevents()->first()->piggybank_id;
}
break;
}
$preFilled['amount'] = $journal->getAmount();
$preFilled['account_id'] = $this->_helper->getAssetAccount($what, $transactions);
$preFilled['expense_account'] = $transactions[0]->account->name;
$preFilled['revenue_account'] = $transactions[1]->account->name;
$preFilled['account_from_id'] = $transactions[1]->account->id;
$preFilled['account_to_id'] = $transactions[0]->account->id;
/*
* Show the view.
*/
return View::make('transactions.edit')->with('journal', $journal)->with('accounts', $accounts)->with(
'what', $what
)->with('budgets', $budgets)->with('data', $preFilled)->with('piggies', $piggies)->with(
'subTitle', 'Edit ' . $what . ' "' . $journal->description . '"'
);
return View::make('transactions.edit', compact('journal', 'accounts', 'what', 'budgets', 'piggies', 'subTitle'))->with('data', $preFilled);
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's 7. More than 5 but alright.
*
* @param $what
*
* @return $this
*/
public function index($what)
{
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */
$repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
switch ($what) {
case 'expenses':
case 'withdrawal':
$subTitleIcon = 'fa-long-arrow-left';
$subTitle = 'Expenses';
$journals = $repository->getWithdrawalsPaginated(50);
$journals = $this->_repository->getWithdrawalsPaginated(50);
break;
case 'revenue':
case 'deposit':
$subTitleIcon = 'fa-long-arrow-right';
$subTitle = 'Revenue, income and deposits';
$journals = $repository->getDepositsPaginated(50);
$journals = $this->_repository->getDepositsPaginated(50);
break;
case 'transfer':
case 'transfers':
$subTitleIcon = 'fa-arrows-h';
$subTitle = 'Transfers';
$journals = $repository->getTransfersPaginated(50);
$journals = $this->_repository->getTransfersPaginated(50);
break;
}
@@ -342,51 +195,6 @@ class TransactionController extends BaseController
}
/**
* @param TransactionJournal $journal
*
* @return \Illuminate\View\View
*/
public function relate(TransactionJournal $journal)
{
$groups = $journal->transactiongroups()->get();
$members = new Collection;
/** @var TransactionGroup $group */
foreach ($groups as $group) {
/** @var TransactionJournal $jrnl */
foreach ($group->transactionjournals()->get() as $jrnl) {
if ($jrnl->id != $journal->id) {
$members->push($jrnl);
}
}
}
return View::make('transactions.relate', compact('journal', 'members'));
}
/**
* TODO this needs cleaning up and thinking over.
*
* @param TransactionJournal $journal
*
* @return \Illuminate\Http\JsonResponse
*/
public function relatedSearch(TransactionJournal $journal)
{
$search = e(trim(Input::get('searchValue')));
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */
$repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
$result = $repository->searchRelated($search, $journal);
$result->each(
function (TransactionJournal $j) {
$j->amount = mf($j->getAmount());
}
);
return Response::json($result->toArray());
}
/**
* @param TransactionJournal $journal
@@ -410,20 +218,22 @@ class TransactionController extends BaseController
$members = new Collection;
/** @var TransactionGroup $group */
foreach ($journal->transactiongroups()->get() as $group) {
/** @var TransactionJournal $jrnl */
foreach ($group->transactionjournals()->get() as $jrnl) {
if ($jrnl->id != $journal->id) {
$members->push($jrnl);
/** @var TransactionJournal $loopJournal */
foreach ($group->transactionjournals()->get() as $loopJournal) {
if ($loopJournal->id != $journal->id) {
$members->push($loopJournal);
}
}
}
return View::make('transactions.show', compact('journal', 'members'))->with(
'subTitle', $journal->transactionType->type . ' "' . $journal->description . '"'
'subTitle', e($journal->transactionType->type) . ' "' . e($journal->description) . '"'
);
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param $what
*
* @return $this|\Illuminate\Http\RedirectResponse
@@ -432,89 +242,44 @@ class TransactionController extends BaseController
public function store($what)
{
$data = Input::except('_token');
$transactionType = $this->_repository->getJournalType($what);
$transactionCurrency = $this->_repository->getJournalCurrencyById(intval($data['amount_currency_id']));
$data['transaction_type_id'] = $transactionType->id;
$data['transaction_currency_id'] = $transactionCurrency->id;
$data['completed'] = 0;
$data['what'] = $what;
$data['currency'] = 'EUR';
$messages = $this->_repository->validate($data);
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */
$repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
switch ($data['post_submit_action']) {
default:
throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"');
break;
case 'create_another':
case 'store':
$messages = $repository->validate($data);
/** @var MessageBag $messages ['errors'] */
if ($messages['errors']->count() > 0) {
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('error', 'Could not save transaction: ' . $messages['errors']->first());
Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
Session::flash('error', 'Could not store transaction: ' . $messages['errors']->first());
return Redirect::route('transactions.create', $what)->withInput()->withErrors($messages['errors']);
return Redirect::route('transactions.create', $data['what'])->withInput();
}
// store!
$journal = $repository->store($data);
Session::flash('success', 'New transaction stored!');
/*
* Trigger a search for the related (if selected)
* piggy bank and store an event.
*/
Event::fire('transactionJournal.store', [$journal, Input::get('piggybank_id')]); // new and used.
/*
* Also trigger on both transactions.
*/
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('transactions.create', $data['what'])->withInput();
}
$journal = $this->_repository->store($data);
Event::fire('transactionJournal.store', [$journal, Input::get('piggy_bank_id')]); // new and used.
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
Event::fire('transaction.store', [$transaction]);
}
if ($data['post_submit_action'] == 'create_another') {
return Redirect::route('transactions.create', $what)->withInput();
} else {
return Redirect::route('transactions.index', $what);
}
break;
case 'validate_only':
$messageBags = $repository->validate($data);
Session::flash('warnings', $messageBags['warnings']);
Session::flash('successes', $messageBags['successes']);
Session::flash('errors', $messageBags['errors']);
return Redirect::route('transactions.create', $what)->withInput();
break;
}
Session::flash('success', 'Transaction "' . e($data['description']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('transactions.index', $data['what']);
}
/**
* TODO this needs cleaning up and thinking over.
*
* @param TransactionJournal $journal
*
* @return \Illuminate\Http\JsonResponse
* @throws Exception
*/
public function unrelate(TransactionJournal $journal)
{
$groups = $journal->transactiongroups()->get();
$relatedTo = intval(Input::get('relation'));
/** @var TransactionGroup $group */
foreach ($groups as $group) {
foreach ($group->transactionjournals()->get() as $jrnl) {
if ($jrnl->id == $relatedTo) {
// remove from group:
$group->transactionjournals()->detach($relatedTo);
}
}
if ($group->transactionjournals()->count() == 1) {
$group->delete();
}
return Redirect::route('transactions.create', $data['what'])->withInput();
}
return Response::json(true);
}
/**
* @param TransactionJournal $journal
@@ -524,58 +289,37 @@ class TransactionController extends BaseController
*/
public function update(TransactionJournal $journal)
{
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repos */
$repos = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
$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'] = intval($data['amount_currency_id']);
$data['completed'] = 1;
$messages = $this->_repository->validate($data);
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
Session::flash('error', 'Could not update transaction: ' . $messages['errors']->first());
switch (Input::get('post_submit_action')) {
case 'update':
case 'return_to_edit':
$messageBag = $repos->update($journal, $data);
if ($messageBag->count() == 0) {
// has been saved, return to index:
Session::flash('success', 'Transaction updated!');
return Redirect::route('transactions.edit', $journal->id)->withInput();
}
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('transactions.edit', $journal->id)->withInput();
}
$this->_repository->update($journal, $data);
Session::flash('success', 'Transaction "' . e($data['description']) . '" updated.');
Event::fire('transactionJournal.update', [$journal]); // new and used.
/*
* Also trigger on both transactions.
*/
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
foreach ($journal->transactions()->get() as $transaction) {
Event::fire('transaction.update', [$transaction]);
}
if (Input::get('post_submit_action') == 'return_to_edit') {
return Redirect::route('transactions.edit', $journal->id)->withInput();
} else {
if ($data['post_submit_action'] == 'update') {
return Redirect::route('transactions.index', $data['what']);
}
} else {
Session::flash('error', 'Could not update transaction: ' . $journal->getErrors()->first());
return Redirect::route('transactions.edit', $journal->id)->withInput()->withErrors(
$journal->getErrors()
);
}
break;
case 'validate_only':
$messageBags = $repos->validate($data);
Session::flash('warnings', $messageBags['warnings']);
Session::flash('successes', $messageBags['successes']);
Session::flash('errors', $messageBags['errors']);
return Redirect::route('transactions.edit', $journal->id)->withInput();
break;
default:
throw new FireflyException('Method ' . Input::get('post_submit_action') . ' not implemented yet.');
break;
}
// go back to update screen.
return Redirect::route('transactions.edit', $journal->id)->withInput(['post_submit_action' => 'return_to_edit']);
}

View File

@@ -33,7 +33,7 @@ class UserController extends BaseController
Auth::logout();
Session::flush();
return Redirect::route('index');
return Redirect::route('login');
}
/**
@@ -67,9 +67,6 @@ class UserController extends BaseController
*/
public function postRegister()
{
if (Config::get('auth.allow_register') !== true) {
return View::make('error')->with('message', 'Not possible');
}
/** @var \FireflyIII\Database\User\User $repository */
$repository = App::make('FireflyIII\Database\User\User');
@@ -79,18 +76,16 @@ class UserController extends BaseController
$user = $repository->register(Input::all());
//$user = $this->user->register(Input::all());
if ($user) {
if (Config::get('auth.verify_mail') === true) {
$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');
}
$email->sendPasswordMail($user);
return View::make('user.registered');
}
return View::make('user.register');
@@ -102,7 +97,7 @@ class UserController extends BaseController
*
* @return \Illuminate\View\View
*/
public function postRemindme()
public function postRemindMe()
{
/** @var \FireflyIII\Database\User\User $repository */
@@ -116,16 +111,11 @@ class UserController extends BaseController
if (!$user) {
Session::flash('error', 'No good!');
return View::make('user.remindme');
return View::make('user.remindMe');
}
if (Config::get('auth.verify_reset') === true) {
$email->sendResetVerification($user);
return View::make('user.verification-pending');
}
$email->sendPasswordMail($user);
return View::make('user.registered');
}
@@ -136,8 +126,10 @@ class UserController extends BaseController
*/
public function register()
{
if (Config::get('auth.allow_register') !== true) {
return View::make('error')->with('message', 'Not possible');
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 <code>app/config/' . App::environment() . '/mail.php</code>');
}
return View::make('user.register');
@@ -148,9 +140,9 @@ class UserController extends BaseController
*
* @return \Illuminate\View\View
*/
public function remindme()
public function remindMe()
{
return View::make('user.remindme');
return View::make('user.remindMe');
}
/**
@@ -176,7 +168,7 @@ class UserController extends BaseController
return View::make('user.registered');
}
return View::make('error')->with('message', 'Yo no hablo reset code!');
return View::make('error')->with('message', 'No reset code found!');
}
}

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateUsersTable
*/
class CreateUsersTable extends Migration

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateAccountTypesTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateAccountsTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateComponentsTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreatePiggybanksTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateTransactionCurrenciesTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateTransactionTypesTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateRecurringTransactionsTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateTransactionJournalsTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateTransactionsTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateComponentTransactionTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateComponentTransactionJournalTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreatePreferencesTable
*
*/

View File

@@ -1,8 +1,11 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateSessionTable
*
*/
@@ -27,10 +30,10 @@ class CreateSessionTable extends Migration
public function up()
{
Schema::create(
'sessions', function ($t) {
$t->string('id')->unique();
$t->text('payload');
$t->integer('last_activity');
'sessions', function (Blueprint $table) {
$table->string('id')->unique();
$table->text('payload');
$table->integer('last_activity');
}
);
}

View File

@@ -4,6 +4,9 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)\
*
*
* Class CreateLimitsTable
*
*/
@@ -37,7 +40,7 @@ class CreateLimitsTable extends Migration
$table->boolean('repeats');
$table->enum('repeat_freq', ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly']);
$table->unique(['component_id', 'startdate', 'repeat_freq']);
$table->unique(['component_id', 'startdate', 'repeat_freq'], 'unique_ci_combi');
// connect component
$table->foreign('component_id')->references('id')->on('components')->onDelete('cascade');

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateLimitRepeatTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateComponentRecurringTransactionTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreatePiggyInstance
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreatePiggybankEventsTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateRemindersTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateAccountMetaTable
*
*/

View File

@@ -4,6 +4,8 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
*
* Class CreateTransactionGroupsTable
*
*/

View File

@@ -2,8 +2,12 @@
use Illuminate\Database\Migrations\Migration;
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
@@ -271,19 +275,6 @@ class ChangesForV321 extends Migration
$this->dropComponentIdFromBudgetLimits(); // 16.
$this->expandCurrencyTable(); // 17.
// $this->doRenameInLimitRepetitions();
// $this->doBudgetLimits();
// $this->doPiggyBankEvents();
// $this->doCreateCategoryTables();
// $this->doUpdateTransactionTable();
// $this->doDropCompRecurTable();
// $this->doDropCompTransTable();
// $this->doMoveBudgets();
// $this->doMoveCategories();
// $this->doMoveLimitReferences();
}
public function createBudgetTable()
@@ -502,133 +493,5 @@ class ChangesForV321 extends Migration
\DB::update('UPDATE `transaction_currencies` SET `symbol` = "&#8364;", `name` = "Euro" WHERE `code` = "EUR";');
}
//
// public function doRenameInLimitRepetitions()
// {
// Schema::table(
// 'limit_repetitions', function (Blueprint $table) {
// $table->renameColumn('limit_id', 'budget_limit_id');
// }
// );
// }
//
// public function doBudgetLimits()
// {
// Schema::rename('limits', 'budget_limits');
// Schema::table(
// 'budget_limits', function (Blueprint $table) {
// $table->integer('budget_id')->unsigned()->after('updated_at');
// $table->foreign('budget_id', 'bid_foreign')->references('id')->on('budgets')->onDelete('cascade');
// }
// );
// }
//
// public function doPiggyBankEvents()
// {
// Schema::rename('piggybank_events', 'piggy_bank_events');
//
// }
//
// public function doCreateCategoryTables()
// {
// Schema::create(
// 'categories', function (Blueprint $table) {
// $table->increments('id');
// $table->timestamps();
// $table->softDeletes();
// $table->string('name', 50);
// $table->integer('user_id')->unsigned();
// $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
// $table->unique(['user_id', 'name']);
// }
// );
// Schema::create(
// 'category_transaction_journal', function (Blueprint $table) {
// $table->increments('id');
// $table->integer('category_id')->unsigned();
// $table->integer('transaction_journal_id')->unsigned();
// $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
// $table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade');
// $table->unique(['category_id', 'transaction_journal_id'], 'catid_tjid_unique');
// }
// );
//
// }
//
// public function doUpdateTransactionTable()
// {
// Schema::table(
// 'transactions', function (Blueprint $table) {
// $table->dropForeign('transactions_piggybank_id_foreign');
// #$table->dropIndex('transactions_piggybank_id_foreign');
// $table->dropColumn('piggybank_id');
// }
// );
// }
//
// public function doDropCompRecurTable()
// {
// Schema::drop('component_recurring_transaction');
// }
//
// public function doDropCompTransTable()
// {
// Schema::drop('component_transaction');
// }
//
// public function doMoveBudgets()
// {
// Component::where('class', 'Budget')->get()->each(
// function (Component $c) {
// $entry = [
// 'user_id' => $c->user_id,
// 'name' => $c->name
//
// ];
// $budget = Budget::firstOrCreate($entry);
// Log::debug('Migrated budget #' . $budget->id . ': ' . $budget->name);
// // create entry in budget_transaction_journal
// $connections = DB::table('component_transaction_journal')->where('component_id', $c->id)->get();
// foreach ($connections as $connection) {
// DB::table('budget_transaction_journal')->insert(
// [
// 'budget_id' => $budget->id,
// 'transaction_journal_id' => $connection->transaction_journal_id
// ]
// );
// }
// }
// );
// }
//
// public function doMoveCategories()
// {
// Component::where('class', 'Category')->get()->each(
// function (Component $c) {
// $entry = [
// 'user_id' => $c->user_id,
// 'name' => $c->name
//
// ];
// $category = Category::firstOrCreate($entry);
// Log::debug('Migrated category #' . $category->id . ': ' . $category->name);
// // create entry in category_transaction_journal
// $connections = DB::table('component_transaction_journal')->where('component_id', $c->id)->get();
// foreach ($connections as $connection) {
// DB::table('category_transaction_journal')->insert(
// [
// 'category_id' => $category->id,
// 'transaction_journal_id' => $connection->transaction_journal_id
// ]
// );
// }
// }
// );
// }
//
// public function doMoveLimitReferences()
// {
// throw new \FireflyIII\Exception\FireflyException('TODO');
// }
}

View File

@@ -0,0 +1,172 @@
<?php
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
{
/**
*
*/
public function down()
{
// rename tables:
Schema::rename('piggy_bank_repetitions', 'piggybank_repetitions');
Schema::rename('piggy_banks', 'piggybanks');
// rename fields
Schema::table(
'piggy_bank_events', function (Blueprint $table) {
$table->renameColumn('piggy_bank_id', 'piggybank_id');
}
);
Schema::table(
'piggybank_repetitions', function (Blueprint $table) {
$table->renameColumn('piggy_bank_id', 'piggybank_id');
}
);
// remove soft delete to piggy banks
Schema::table(
'piggybanks', function (Blueprint $table) {
$table->dropSoftDeletes();
}
);
// drop keys from bills (foreign bills_uid_for and unique uid_name_unique)
Schema::table(
'bills', function (Blueprint $table) {
$table->dropForeign('bills_uid_for');
$table->dropUnique('uid_name_unique');
}
);
// drop foreign key from transaction_journals (bill_id_foreign)
Schema::table(
'transaction_journals', function (Blueprint $table) {
$table->dropForeign('bill_id_foreign');
}
);
// drop foreign key from budget_limits:
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->dropForeign('bid_foreign');
$table->dropUnique('unique_bl_combi');
}
);
// rename bills to recurring_transactions
Schema::rename('bills', 'recurring_transactions');
// recreate foreign key recurring_transactions_user_id_foreign in recurring_transactions
// recreate unique recurring_transactions_user_id_name_unique in recurring_transactions
Schema::table(
'recurring_transactions', function (Blueprint $table) {
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unique(['user_id', 'name']);
}
);
// rename bill_id to recurring_transaction_id
// recreate foreign transaction_journals_recurring_transaction_id_foreign in transaction_journals
Schema::table(
'transaction_journals', function (Blueprint $table) {
$table->renameColumn('bill_id', 'recurring_transaction_id');
$table->foreign('recurring_transaction_id')->references('id')->on('recurring_transactions')->onDelete('set null');
}
);
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// rename tables:
Schema::rename('piggybank_repetitions', 'piggy_bank_repetitions');
Schema::rename('piggybanks', 'piggy_banks');
// recreate it the correct way:
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->unique(['budget_id', 'startdate', 'repeat_freq'], 'unique_bl_combi');
}
);
// rename fields
Schema::table(
'piggy_bank_events', function (Blueprint $table) {
$table->renameColumn('piggybank_id', 'piggy_bank_id');
}
);
Schema::table(
'piggy_bank_repetitions', function (Blueprint $table) {
$table->renameColumn('piggybank_id', 'piggy_bank_id');
}
);
// add soft delete to piggy banks
Schema::table(
'piggy_banks', function (Blueprint $table) {
$table->softDeletes();
}
);
// rename everything related to recurring transactions, aka bills:
Schema::table(
'transaction_journals', function (Blueprint $table) {
// drop relation
$table->dropForeign('transaction_journals_recurring_transaction_id_foreign');
// rename column
$table->renameColumn('recurring_transaction_id', 'bill_id');
}
);
Schema::table(
'recurring_transactions', function (Blueprint $table) {
$table->dropForeign('recurring_transactions_user_id_foreign');
$table->dropUnique('recurring_transactions_user_id_name_unique');
}
);
// rename table:
Schema::rename('recurring_transactions', 'bills');
// recreate foreign relation:
Schema::table(
'transaction_journals', function (Blueprint $table) {
$table->foreign('bill_id', 'bill_id_foreign')->references('id')->on('bills')->onDelete('set null');
}
);
// recreate more foreign relations.
Schema::table(
'bills', function (Blueprint $table) {
// connect user id to users
$table->foreign('user_id', 'bills_uid_for')->references('id')->on('users')->onDelete('cascade');
// for a user, the name must be unique
$table->unique(['user_id', 'name'], 'uid_name_unique');
}
);
}
}

View File

@@ -0,0 +1,71 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\QueryException;
use Illuminate\Database\Schema\Blueprint;
/**
* @SuppressWarnings(PHPMD.ShortMethodName)
* @SuppressWarnings("MethodLength") // I don't mind this in case of migrations.
*
* Class ChangesForV325
*/
class ChangesForV325 extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//
// delete an old index:
try {
Schema::table(
'budget_limits', function (Blueprint $table) {
//$table->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.
}
}
}

View File

@@ -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]);
}

View File

@@ -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');
}
}
}

View File

@@ -1,20 +0,0 @@
<?php
/**
* Class DefaultUserSeeder
*/
class DefaultUserSeeder extends Seeder
{
public function run()
{
DB::table('users')->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]);
}
}
}

View File

@@ -1,312 +0,0 @@
<?php
use Carbon\Carbon;
/**
* Class TestContentSeeder
*/
class TestContentSeeder extends Seeder
{
public function run()
{
if (App::environment() == 'testing' || App::environment() == 'homestead') {
$assetType = AccountType::whereType('Asset account')->first();
$expenseType = AccountType::whereType('Expense account')->first();
$revenueType = AccountType::whereType('Revenue account')->first();
$ibType = AccountType::whereType('Initial balance account')->first();
$obType = TransactionType::whereType('Opening balance')->first();
$withdrawal = TransactionType::whereType('Withdrawal')->first();
$transfer = TransactionType::whereType('Transfer')->first();
$deposit = TransactionType::whereType('Deposit')->first();
$user = User::whereEmail('thegrumpydictator@gmail.com')->first();
if ($user) {
// create two asset accounts.
$checking = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Checking account', 'active' => 1]);
$savings = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Savings account', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Delete me', 'active' => 1]);
// create two budgets:
$groceriesBudget = Budget::create(['user_id' => $user->id, 'name' => 'Groceries']);
$billsBudget = Budget::create(['user_id' => $user->id, 'name' => 'Bills']);
$deleteBudget = Budget::create(['user_id' => $user->id, 'name' => 'Delete me']);
// some limits:
$startDate = Carbon::now()->startOfMonth();
$endDate = Carbon::now()->endOfMonth();
$secondStart = Carbon::now()->subMonth()->startOfMonth();
$secondEnd = Carbon::now()->subMonth()->endOfMonth();
$limitOne = BudgetLimit::create(
['startdate' => $startDate->format('Y-m-d'), 'amount' => 201, 'repeats' => 0, 'repeat_freq' => 'monthly',
'budget_id' => $groceriesBudget->id]
);
$limitTwo = BudgetLimit::create(
['startdate' => $secondStart->format('Y-m-d'), 'amount' => 202, 'repeats' => 0, 'repeat_freq' => 'monthly',
'budget_id' => $billsBudget->id]
);
$limitThree = BudgetLimit::create(
['startdate' => '2014-01-01', 'amount' => 203, 'repeats' => 0, 'repeat_freq' => 'monthly',
'budget_id' => $deleteBudget->id]
);
// and because we have no filters, some repetitions:
$repOne = LimitRepetition::create(
['budget_limit_id' => $limitOne->id, 'startdate' => $startDate->format('Y-m-d'), 'enddate' => $endDate->format('Y-m-d'), 'amount' => 201]
);
$repTwo = LimitRepetition::create(
['budget_limit_id' => $limitTwo->id, 'startdate' => $secondStart->format('Y-m-d'), 'enddate' => $secondEnd->format('Y-m-d'), 'amount' => 202]
);
$repThree = LimitRepetition::create(
['budget_limit_id' => $limitThree->id, 'startdate' => '2014-01-01', 'enddate' => '2014-01-31', 'amount' => 203]
);
// create two categories:
$dailyGroceries = Category::create(['user_id' => $user->id, 'name' => 'DailyGroceries']);
$lunch = Category::create(['user_id' => $user->id, 'name' => 'Lunch']);
$house = Category::create(['user_id' => $user->id, 'name' => 'House']);
$deleteMe = Category::create(['user_id' => $user->id, 'name' => 'Delete me']);
Component::create(['user_id' => $user->id, 'name' => 'Some Component 1', 'class' => 'Budget']);
Component::create(['user_id' => $user->id, 'name' => 'Some Component 2', 'class' => 'Budget']);
Component::create(['user_id' => $user->id, 'name' => 'Some Component 3', 'class' => 'Budget']);
Component::create(['user_id' => $user->id, 'name' => 'Some Component 4', 'class' => 'Category']);
Component::create(['user_id' => $user->id, 'name' => 'Some Component 5', 'class' => 'Category']);
Component::create(['user_id' => $user->id, 'name' => 'Some Component 6', 'class' => 'Category']);
Component::create(['user_id' => $user->id, 'name' => 'Some Component 7', 'class' => 'Category']);
// piggy bank
$piggy = Piggybank::create(
[
'account_id' => $savings->id,
'name' => 'New camera',
'targetamount' => 2000,
'startdate' => Carbon::now()->format('Y-m-d'),
'targetdate' => null,
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => null,
'reminder_skip' => 0,
'remind_me' => 0,
'order' => 0,
]
);
PiggyBankEvent::create(['piggybank_id' => 1, 'date' => $startDate->format('Y-m-d'), 'amount' => 100]);
PiggybankRepetition::create(
[
'piggybank_id' => $piggy->id,
'startdate' => Carbon::now()->format('Y-m-d'),
'targetdate' => null,
'currentamount' => 0
]
);
// piggy bank
$piggyTargeted = Piggybank::create(
[
'account_id' => $savings->id,
'name' => 'New clothes',
'targetamount' => 2000,
'startdate' => Carbon::now()->format('Y-m-d'),
'targetdate' => Carbon::now()->addMonths(4)->format('Y-m-d'),
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => null,
'reminder_skip' => 0,
'remind_me' => 0,
'order' => 0,
]
);
PiggyBankEvent::create(['piggybank_id' => $piggyTargeted->id, 'date' => $startDate->format('Y-m-d'), 'amount' => 100]);
PiggybankRepetition::create(
[
'piggybank_id' => $piggyTargeted->id,
'startdate' => Carbon::now()->format('Y-m-d'),
'targetdate' => Carbon::now()->addMonths(4)->format('Y-m-d'),
'currentamount' => 0
]
);
// recurring transaction
$recurring = \RecurringTransaction::create(
[
'user_id' => $user->id,
'name' => 'Huur',
'match' => 'huur,portaal',
'amount_min' => 500,
'amount_max' => 700,
'date' => '2014-01-12',
'active' => 1,
'automatch' => 1,
'repeat_freq' => 'monthly',
'skip' => 0,
]
);
// recurring transaction
$secondRecurring = \RecurringTransaction::create(
[
'user_id' => $user->id,
'name' => 'Gas licht',
'match' => 'no,match',
'amount_min' => 500,
'amount_max' => 700,
'date' => '2014-01-12',
'active' => 1,
'automatch' => 1,
'repeat_freq' => 'monthly',
'skip' => 0,
]
);
// create some expense accounts.
$albert = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Albert Heijn', 'active' => 1]);
$plus = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'PLUS', 'active' => 1]);
$vitens = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Vitens', 'active' => 1]);
$greenchoice = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Greenchoice', 'active' => 1]);
$portaal = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Portaal', 'active' => 1]);
$store = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Buy More', 'active' => 1]);
// create three revenue accounts.
$employer = Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'Employer', 'active' => 1]);
$taxes = Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'IRS', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'Job', 'active' => 1]);
// put money in the two accounts (initial balance)
$ibChecking = Account::create(
['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Checking account initial balance', 'active' => 0]
);
$ibSavings = Account::create(
['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Savings account initial balance', 'active' => 0]
);
$this->createTransaction($ibChecking, $checking, 4000, $obType, 'Initial Balance for Checking account', '2014-01-01');
$this->createTransaction($ibSavings, $savings, 10000, $obType, 'Initial Balance for Savings account', '2014-01-01');
// create some expenses and incomes and what-not (for every month):
$start = new Carbon('2014-01-01');
$end = Carbon::now()->endOfMonth()->addDay();
while ($start <= $end) {
$this->createTransaction(
$checking, $portaal, 500, $withdrawal, 'Huur Portaal for ' . $start->format('F Y'), $start->format('Y-m-') . '01', $billsBudget, $house,
$recurring
);
$this->createTransaction(
$checking, $vitens, 12, $withdrawal, 'Water for ' . $start->format('F Y'), $start->format('Y-m-') . '02', $billsBudget, $house
);
$this->createTransaction(
$checking, $greenchoice, 110, $withdrawal, 'Power for ' . $start->format('F Y'), $start->format('Y-m-') . '02', $billsBudget, $house
);
// spend on groceries
$groceriesStart = clone $start;
for ($i = 0; $i < 13; $i++) {
$amt = rand(100, 300) / 10;
$lunchAmount = rand(30, 60) / 10;
$this->createTransaction(
$checking, $plus, $lunchAmount, $withdrawal, 'Lunch', $groceriesStart->format('Y-m-d'), $groceriesBudget, $lunch
);
$groceriesStart->addDay();
if (intval($groceriesStart->format('d')) % 2 == 0) {
$this->createTransaction(
$checking, $albert, $amt, $withdrawal, 'Groceries', $groceriesStart->format('Y-m-d'), $groceriesBudget, $dailyGroceries
);
}
$groceriesStart->addDay();
}
// get income:
$this->createTransaction($employer, $checking, rand(1400, 1600), $deposit, 'Salary', $start->format('Y-m-') . '23');
// pay taxes:
$this->createTransaction($checking, $taxes, rand(50, 70), $withdrawal, 'Taxes in ' . $start->format('F Y'), $start->format('Y-m-') . '27');
// some other stuff.
$start->addMonth();
}
// create some big expenses, move some money around.
$this->createTransaction($savings, $checking, 1259, $transfer, 'Money for new PC', $end->format('Y-m') . '-11');
$this->createTransaction($checking, $store, 1259, $withdrawal, 'New PC', $end->format('Y-m') . '-12');
// create two budgets
// create two categories
// create
}
}
}
/**
* @param Account $from
* @param Account $to
* @param $amount
* @param TransactionType $type
* @param $description
* @param $date
*
* @param Budget $budget
* @param Category $category
* @param RecurringTransaction $recurring
*
* @return TransactionJournal
*/
public function createTransaction(
Account $from, Account $to, $amount, TransactionType $type, $description, $date, Budget $budget = null, Category $category = null,
$recurring = null
) {
$user = User::whereEmail('thegrumpydictator@gmail.com')->first();
$euro = TransactionCurrency::whereCode('EUR')->first();
$recurringID = is_null($recurring) ? null : $recurring->id;
/** @var TransactionJournal $journal */
$journal = TransactionJournal::create(
[
'user_id' => $user->id,
'transaction_type_id' => $type->id,
'transaction_currency_id' => $euro->id,
'recurring_transaction_id' => $recurringID,
'description' => $description,
'completed' => 1,
'date' => $date
]
);
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
]
);
if (!is_null($budget)) {
$journal->budgets()->save($budget);
}
if (!is_null($category)) {
$journal->categories()->save($category);
}
return $journal;
}
}

View File

@@ -0,0 +1,602 @@
<?php
use Carbon\Carbon;
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
* @SuppressWarnings("TooManyMethods") // I'm fine with this
* @SuppressWarnings("CouplingBetweenObjects") // I'm fine with this
* @SuppressWarnings("MethodLength") // I'm fine with this
*
* Class TestDataSeeder
*/
class TestDataSeeder extends Seeder
{
/** @var string */
public $eom;
/** @var string */
public $neom;
/** @var string */
public $nsom;
/** @var string */
public $som;
/** @var string */
public $today;
/** @var string */
public $yaeom;
/** @var string */
public $yasom;
/** @var Carbon */
protected $_endOfMonth;
/** @var Carbon */
protected $_nextEndOfMonth;
/** @var Carbon */
protected $_nextStartOfMonth;
/** @var Carbon */
protected $_startOfMonth;
/** @var Carbon */
protected $_today;
/** @var Carbon */
protected $_yearAgoEndOfMonth;
/** @var Carbon */
protected $_yearAgoStartOfMonth;
/**
*
*/
public function __construct()
{
$this->_startOfMonth = Carbon::now()->startOfMonth();
$this->som = $this->_startOfMonth->format('Y-m-d');
$this->_endOfMonth = Carbon::now()->endOfMonth();
$this->eom = $this->_endOfMonth->format('Y-m-d');
$this->_nextStartOfMonth = Carbon::now()->addMonth()->startOfMonth();
$this->nsom = $this->_nextStartOfMonth->format('Y-m-d');
$this->_nextEndOfMonth = Carbon::now()->addMonth()->endOfMonth();
$this->neom = $this->_nextEndOfMonth->format('Y-m-d');
$this->_yearAgoStartOfMonth = Carbon::now()->subYear()->startOfMonth();
$this->yasom = $this->_yearAgoStartOfMonth->format('Y-m-d');
$this->_yearAgoEndOfMonth = Carbon::now()->subYear()->startOfMonth();
$this->yaeom = $this->_yearAgoEndOfMonth->format('Y-m-d');
$this->_today = Carbon::now();
$this->today = $this->_today->format('Y-m-d');
}
/**
* Dates are always this month, the start of this month or earlier.
*/
public function run()
{
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]);
$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.');
// 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));
$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));
$house = Category::whereName('House')->orderBy('id', 'DESC')->first();
Log::debug('Found house category: ' . json_encode($checking));
$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));
$euro = TransactionCurrency::whereCode('EUR')->first();
Log::debug('Found euro: ' . json_encode($euro));
$rentBill = Bill::where('name', 'Rent')->first();
Log::debug('Found bill "rent": ' . json_encode($rentBill));
$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
]
);
}
/**
* @param User $user
*/
public function createAssetAccounts(User $user)
{
$assetType = AccountType::whereType('Asset account')->first();
$ibType = AccountType::whereType('Initial balance account')->first();
$obType = TransactionType::whereType('Opening balance')->first();
$euro = TransactionCurrency::whereCode('EUR')->first();
$acc_a = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Checking account', 'active' => 1]);
$acc_b = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Savings account', 'active' => 1]);
$acc_c = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Delete me', 'active' => 1]);
$acc_d = Account::create(['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Checking account initial balance', 'active' => 0]);
$acc_e = Account::create(['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Savings account initial balance', 'active' => 0]);
$acc_f = Account::create(['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Delete me initial balance', 'active' => 0]);
$this->createTransaction($acc_d, $acc_a, 4000, $obType, 'Initial Balance for Checking account', $this->yasom, $euro);
$this->createTransaction($acc_e, $acc_b, 10000, $obType, 'Initial Balance for Savings account', $this->yasom, $euro);
$this->createTransaction($acc_f, $acc_c, 100, $obType, 'Initial Balance for Delete me', $this->yasom, $euro);
}
/**
* @SuppressWarnings(PHPMD.ShortVariable)
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*
* @param Account $from
* @param Account $to
* @param $amount
* @param TransactionType $type
* @param $description
* @param $date
* @param TransactionCurrency $currency
*
* @param Budget $budget
* @param Category $category
* @param Bill $bill
*
* @return TransactionJournal
*/
public function createTransaction(
Account $from, Account $to, $amount, TransactionType $type, $description, $date, TransactionCurrency $currency, Budget $budget = null,
Category $category = null, Bill $bill = null
) {
$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
]
);
//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]);
if (!is_null($budget)) {
$journal->budgets()->save($budget);
}
if (!is_null($category)) {
$journal->categories()->save($category);
}
return $journal;
}
/**
* @param User $user
*/
public function createBudgets(User $user)
{
$groceries = Budget::create(['user_id' => $user->id, 'name' => 'Groceries']);
$bills = Budget::create(['user_id' => $user->id, 'name' => 'Bills']);
$deleteMe = Budget::create(['user_id' => $user->id, 'name' => 'Delete me']);
Budget::create(['user_id' => $user->id, 'name' => 'Budget without repetition']);
$groceriesLimit = BudgetLimit::create(
['startdate' => $this->som, 'amount' => 201, 'repeats' => 0, 'repeat_freq' => 'monthly', 'budget_id' => $groceries->id]
);
$billsLimit = BudgetLimit::create(
['startdate' => $this->som, 'amount' => 202, 'repeats' => 0, 'repeat_freq' => 'monthly', 'budget_id' => $bills->id]
);
$deleteMeLimit = BudgetLimit::create(
['startdate' => $this->som, 'amount' => 203, 'repeats' => 0, 'repeat_freq' => 'monthly', 'budget_id' => $deleteMe->id]
);
// and because we have no filters, some repetitions:
LimitRepetition::create(['budget_limit_id' => $groceriesLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 201]);
LimitRepetition::create(['budget_limit_id' => $billsLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 202]);
LimitRepetition::create(['budget_limit_id' => $deleteMeLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 203]);
}
/**
* @param User $user
*/
public function createCategories(User $user)
{
Category::create(['user_id' => $user->id, 'name' => 'DailyGroceries']);
Category::create(['user_id' => $user->id, 'name' => 'Lunch']);
Category::create(['user_id' => $user->id, 'name' => 'House']);
Category::create(['user_id' => $user->id, 'name' => 'Delete me']);
}
/**
* @param User $user
*/
public function createPiggyBanks(User $user)
{
// account
$savings = Account::whereName('Savings account')->orderBy('id', 'DESC')->first();
// some dates
$endDate = clone $this->_startOfMonth;
$nextYear = clone $this->_startOfMonth;
$endDate->addMonths(4);
$nextYear->addYear()->subDay();
$next = $nextYear->format('Y-m-d');
$end = $endDate->format('Y-m-d');
// piggy bank
$newCamera = PiggyBank::create(
[
'account_id' => $savings->id,
'name' => 'New camera',
'targetamount' => 2000,
'startdate' => $this->som,
'targetdate' => null,
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => null,
'reminder_skip' => 0,
'remind_me' => 0,
'order' => 0,
]
);
// and some events!
PiggyBankEvent::create(['piggy_bank_id' => $newCamera->id, 'date' => $this->som, 'amount' => 100]);
PiggyBankRepetition::create(['piggy_bank_id' => $newCamera->id, 'startdate' => $this->som, 'targetdate' => null, 'currentamount' => 100]);
$newClothes = PiggyBank::create(
[
'account_id' => $savings->id,
'name' => 'New clothes',
'targetamount' => 2000,
'startdate' => $this->som,
'targetdate' => $end,
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => null,
'reminder_skip' => 0,
'remind_me' => 0,
'order' => 0,
]
);
PiggyBankEvent::create(['piggy_bank_id' => $newClothes->id, 'date' => $this->som, 'amount' => 100]);
PiggyBankRepetition::create(['piggy_bank_id' => $newClothes->id, 'startdate' => $this->som, 'targetdate' => $end, 'currentamount' => 100]);
// weekly reminder piggy bank
$weekly = PiggyBank::create(
[
'account_id' => $savings->id,
'name' => 'Weekly reminder for clothes',
'targetamount' => 2000,
'startdate' => $this->som,
'targetdate' => $next,
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => 'week',
'reminder_skip' => 0,
'remind_me' => 1,
'order' => 0,
]
);
PiggyBankRepetition::create(['piggy_bank_id' => $weekly->id, 'startdate' => $this->som, 'targetdate' => $next, 'currentamount' => 0]);
}
/**
* @param User $user
*/
public function createReminders(User $user)
{
// for weekly piggy bank (clothes)
$nextWeek = clone $this->_startOfMonth;
$piggyBank = PiggyBank::whereName('New clothes')->orderBy('id', 'DESC')->first();
$nextWeek->addWeek();
$week = $nextWeek->format('Y-m-d');
Reminder::create(
['user_id' => $user->id, 'startdate' => $this->som, 'enddate' => $week, 'active' => 1, 'notnow' => 0,
'remindersable_id' => $piggyBank->id, 'remindersable_type' => 'PiggyBank']
);
// a fake reminder::
Reminder::create(
['user_id' => $user->id, 'startdate' => $this->som, 'enddate' => $week, 'active' => 0, 'notnow' => 0, 'remindersable_id' => 40,
'remindersable_type' => 'Transaction']
);
}
/**
* @param User $user
*/
public function createRecurringTransactions(User $user)
{
// account
$savings = Account::whereName('Savings account')->orderBy('id', 'DESC')->first();
$recurring = PiggyBank::create(
[
'account_id' => $savings->id,
'name' => 'Nieuwe spullen',
'targetamount' => 1000,
'startdate' => $this->som,
'targetdate' => $this->eom,
'repeats' => 1,
'rep_length' => 'month',
'rep_every' => 0,
'rep_times' => 0,
'reminder' => 'month',
'reminder_skip' => 0,
'remind_me' => 1,
'order' => 0,
]
);
PiggyBankRepetition::create(['piggy_bank_id' => $recurring->id, 'startdate' => $this->som, 'targetdate' => $this->eom, 'currentamount' => 0]);
PiggyBankRepetition::create(
['piggy_bank_id' => $recurring->id, 'startdate' => $this->nsom, 'targetdate' => $this->neom, 'currentamount' => 0]
);
Reminder::create(
['user_id' => $user->id, 'startdate' => $this->som, 'enddate' => $this->neom, 'active' => 1, 'notnow' => 0,
'remindersable_id' => $recurring->id, 'remindersable_type' => 'PiggyBank']
);
}
/**
* @param $user
*/
public function createBills($user)
{
// 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,]
);
// bill
Bill::create(
[
'user_id' => $user->id,
'name' => 'Gas licht',
'match' => 'no,match',
'amount_min' => 500, 'amount_max' => 700,
'date' => $this->som,
'active' => 1, 'automatch' => 1,
'repeat_freq' => 'monthly', 'skip' => 0,
]
);
// bill
Bill::create(
[
'user_id' => $user->id,
'name' => 'Something something',
'match' => 'mumble,mumble',
'amount_min' => 500,
'amount_max' => 700,
'date' => $this->som,
'active' => 0,
'automatch' => 1,
'repeat_freq' => 'monthly',
'skip' => 0,
]
);
}
/**
* @param $user
*/
public function createExpenseAccounts($user)
{
//// create expenses for rent, utilities, water, TV, phone on the 1st of the month.
$expenseType = AccountType::whereType('Expense account')->first();
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Land lord', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Utilities company', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Water company', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'TV company', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Phone agency', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Super savers', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Groceries House', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Lunch House', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Buy More', 'active' => 1]);
}
/**
* @param $user
*/
public function createRevenueAccounts($user)
{
$revenueType = AccountType::whereType('Revenue account')->first();
Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'Employer', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'IRS', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'Second job employer', 'active' => 1]);
}
/**
* @param Carbon $date
*/
public function createGroceries(Carbon $date)
{
// variables we need:
$checking = Account::whereName('Checking account')->orderBy('id', 'DESC')->first();
$shopOne = Account::whereName('Groceries House')->orderBy('id', 'DESC')->first();
$shopTwo = Account::whereName('Super savers')->orderBy('id', 'DESC')->first();
$lunchHouse = Account::whereName('Lunch House')->orderBy('id', 'DESC')->first();
$lunch = Category::whereName('Lunch')->orderBy('id', 'DESC')->first();
$daily = Category::whereName('DailyGroceries')->orderBy('id', 'DESC')->first();
$euro = TransactionCurrency::whereCode('EUR')->first();
$withdrawal = TransactionType::whereType('Withdrawal')->first();
$groceries = Budget::whereName('Groceries')->orderBy('id', 'DESC')->first();
$shops = [$shopOne, $shopTwo];
// create groceries and lunch (daily, between 5 and 10 euro).
$mStart = clone $date;
$mEnd = clone $date;
$mEnd->endOfMonth();
while ($mStart <= $mEnd) {
$mFormat = $mStart->format('Y-m-d');
$shop = $shops[rand(0, 1)];
$this->createTransaction($checking, $shop, (rand(500, 1000) / 100), $withdrawal, 'Groceries', $mFormat, $euro, $groceries, $daily);
$this->createTransaction($checking, $lunchHouse, (rand(200, 600) / 100), $withdrawal, 'Lunch', $mFormat, $euro, $groceries, $lunch);
$mStart->addDay();
}
}
/**
* @param $date
*/
public function createBigExpense($date)
{
$date->addDays(12);
$dollar = TransactionCurrency::whereCode('USD')->first();
$checking = Account::whereName('Checking account')->orderBy('id', 'DESC')->first();
$savings = Account::whereName('Savings account')->orderBy('id', 'DESC')->first();
$buyMore = Account::whereName('Buy More')->orderBy('id', 'DESC')->first();
$withdrawal = TransactionType::whereType('Withdrawal')->first();
$transfer = TransactionType::whereType('Transfer')->first();
$user = User::whereEmail('thegrumpydictator@gmail.com')->first();
// create some big expenses, move some money around.
$amount = rand(500, 2000);
$one = $this->createTransaction(
$savings, $checking, $amount, $transfer, 'Money for big expense in ' . $date->format('F Y'), $date->format('Y-m-d'), $dollar
);
$two = $this->createTransaction(
$checking, $buyMore, $amount, $withdrawal, 'Big expense in ' . $date->format('F Y'), $date->format('Y-m-d'), $dollar
);
$group = TransactionGroup::create(
[
'user_id' => $user->id,
'relation' => 'balance'
]
);
$group->transactionjournals()->save($one);
$group->transactionjournals()->save($two);
$group->save();
}
}

View File

@@ -12,6 +12,7 @@ class TransactionCurrencySeeder extends Seeder
TransactionCurrency::create(['code' => 'EUR','name' => 'Euro','symbol' => '&#8364;']);
TransactionCurrency::create(['code' => 'USD','name' => 'US Dollar','symbol' => '$']);
TransactionCurrency::create(['code' => 'HUF','name' => 'Hungarian forint','symbol' => 'Ft']);
}
}

View File

@@ -94,3 +94,11 @@ Route::filter(
}
}
);
Route::filter(
'allow-register', function () {
if (Config::get('auth.allow_register') !== true) {
return View::make('error')->with('message', 'Not possible');
}
}
);

View File

@@ -48,12 +48,12 @@ class Chart implements ChartInterface
*
* @return Collection
*/
public function getRecurringSummary(Carbon $start, Carbon $end)
public function getBillsSummary(Carbon $start, Carbon $end)
{
return \RecurringTransaction::
return \Bill::
leftJoin(
'transaction_journals', function (JoinClause $join) use ($start, $end) {
$join->on('recurring_transactions.id', '=', 'transaction_journals.recurring_transaction_id')
$join->on('bills.id', '=', 'transaction_journals.bill_id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'));
}
@@ -64,11 +64,11 @@ class Chart implements ChartInterface
}
)
->where('active', 1)
->groupBy('recurring_transactions.id')
->groupBy('bills.id')
->get(
['recurring_transactions.id', 'recurring_transactions.name', 'transaction_journals.description',
['bills.id', 'bills.name', 'transaction_journals.description',
'transaction_journals.id as journalId',
\DB::Raw('SUM(`recurring_transactions`.`amount_min` + `recurring_transactions`.`amount_max`) / 2 as `averageAmount`'),
\DB::Raw('SUM(`bills`.`amount_min` + `bills`.`amount_max`) / 2 as `averageAmount`'),
'transactions.amount AS actualAmount']
);
}

View File

@@ -26,6 +26,6 @@ interface ChartInterface
*
* @return Collection
*/
public function getRecurringSummary(Carbon $start, Carbon $end);
public function getBillsSummary(Carbon $start, Carbon $end);
}

View File

@@ -6,11 +6,11 @@ namespace FireflyIII\Collection;
use Carbon\Carbon;
/**
* Class PiggybankPart
* Class PiggyBankPart
*
* @package FireflyIII\Collection
*/
class PiggybankPart
class PiggyBankPart
{
/** @var float */
public $amountPerBar;
@@ -21,7 +21,7 @@ class PiggybankPart
/** @var \Reminder */
public $reminder;
/** @var \PiggybankRepetition */
/** @var \PiggyBankRepetition */
public $repetition;
/** @var Carbon */
@@ -36,7 +36,7 @@ class PiggybankPart
public function getReminder()
{
if (is_null($this->reminder)) {
$this->reminder = $this->repetition->piggybank->reminders()->where('startdate', $this->getStartdate()->format('Y-m-d'))->where(
$this->reminder = $this->repetition->piggyBank->reminders()->where('startdate', $this->getStartdate()->format('Y-m-d'))->where(
'enddate', $this->getTargetdate()->format('Y-m-d')
)->first();
}
@@ -85,7 +85,7 @@ class PiggybankPart
}
/**
* @return \PiggybankRepetition
* @return \PiggyBankRepetition
*/
public function getRepetition()
{
@@ -93,7 +93,7 @@ class PiggybankPart
}
/**
* @param \PiggybankRepetition $repetition
* @param \PiggyBankRepetition $repetition
*/
public function setRepetition($repetition)
{
@@ -115,7 +115,7 @@ class PiggybankPart
{
if ($this->getCurrentamount() < $this->getCumulativeAmount()) {
$pct = 0;
// calculate halway point?
// calculate halfway point?
if ($this->getCumulativeAmount() - $this->getCurrentamount() < $this->getAmountPerBar()) {
$left = $this->getCurrentamount() % $this->getAmountPerBar();
$pct = round($left / $this->getAmountPerBar() * 100);

View File

@@ -3,11 +3,13 @@
namespace FireflyIII\Database\Account;
use Carbon\Carbon;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
use FireflyIII\Database\SwitchUser;
use FireflyIII\Exception\NotImplementedException;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
@@ -17,7 +19,7 @@ use Illuminate\Support\MessageBag;
* @package FireflyIII\Database
* @implements FireflyIII\Database\Account\AccountInterface
*/
class Account implements CUD, CommonDatabaseCalls, AccountInterface
class Account implements CUDInterface, CommonDatabaseCallsInterface, AccountInterface
{
use SwitchUser;
@@ -39,47 +41,6 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
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
*
@@ -91,7 +52,7 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
* 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) {
@@ -99,63 +60,13 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
* 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
*
@@ -178,67 +89,93 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
{
$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;
$opening = ['what' => 'opening', 'currency' => 'EUR', 'amount' => $balance, 'from' => $from, 'to' => $to, 'date' => $date,
/** @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();
$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,];
$validation = $tj->validate($opening);
$validation = $journals->validate($opening);
if ($validation['errors']->count() == 0) {
$tj->store($opening);
$journals->store($opening);
return true;
} else {
var_dump($validation['errors']);
exit;
\Log::error('Initial balance created is not valid (Database/Account)');
\Log::error($validation['errors']->all());
\App::abort(500);
}
return false;
}
/**
* @param \Account $account
*
* @return int
*/
public function getLastActivity(\Account $account)
{
$lastActivityKey = 'account.' . $account->id . '.lastActivityDate';
if (\Cache::has($lastActivityKey)) {
return \Cache::get($lastActivityKey);
}
$transaction = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->orderBy('transaction_journals.date', 'DESC')->first();
if ($transaction) {
$date = $transaction->transactionJournal->date;
} else {
$date = 0;
}
\Cache::forever($lastActivityKey, $date);
return $date;
}
/**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength) // cannot make it shorter because of query.
* @param Eloquent $model
*
* @return bool
*/
public function destroy(Eloquent $model)
{
// delete journals:
$journals = \TransactionJournal::whereIn(
'id', function ($query) use ($model) {
'id', function (QueryBuilder $query) use ($model) {
$query->select('transaction_journal_id')
->from('transactions')->whereIn(
'account_id', function ($query) use ($model) {
->from('transactions')
->whereIn(
'account_id', function (QueryBuilder $query) use ($model) {
$query
->select('id')
->select('accounts.id')
->from('accounts')
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where(
function ($q) use ($model) {
$q->where('id', $model->id);
function (QueryBuilder $q) use ($model) {
$q->where('accounts.id', $model->id);
$q->orWhere(
function ($q) use ($model) {
function (QueryBuilder $q) use ($model) {
$q->where('accounts.name', 'LIKE', '%' . $model->name . '%');
// TODO magic number!
$q->where('accounts.account_type_id', 3);
$q->where('account_types.type', 'Initial balance account');
$q->where('accounts.active', 0);
}
);
@@ -248,9 +185,6 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
)->get();
}
)->get();
/*
* Get all transactions.
*/
$transactions = [];
/** @var \TransactionJournal $journal */
foreach ($journals as $journal) {
@@ -260,26 +194,26 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
}
$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 ($q) use ($model) {
function (EloquentBuilder $q) use ($model, $accountType) {
$q->where('id', $model->id);
$q->orWhere(
function ($q) use ($model) {
function (EloquentBuilder $q) use ($model, $accountType) {
$q->where('accounts.name', 'LIKE', '%' . $model->name . '%');
// TODO magic number!
$q->where('accounts.account_type_id', 3);
$q->where('accounts.account_type_id', $accountType->id);
$q->where('accounts.active', 0);
}
);
@@ -298,9 +232,6 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
public function store(array $data)
{
/*
* Find account type.
*/
/** @var \FireflyIII\Database\AccountType\AccountType $acctType */
$acctType = \App::make('FireflyIII\Database\AccountType\AccountType');
@@ -310,19 +241,18 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
$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()) {
var_dump($account->getErrors()->all());
exit;
\Log::error('Account created is not valid (Database/Account)');
\Log::error($account->getErrors()->all());
\App::abort(500);
}
$account->save();
if (isset($data['openingbalance']) && floatval($data['openingbalance']) != 0) {
if (isset($data['openingBalance']) && floatval($data['openingBalance']) != 0) {
$this->storeInitialBalance($account, $data);
}
// TODO this needs cleaning up and thinking over.
switch ($account->accountType->type) {
case 'Asset account':
case 'Default account':
@@ -350,7 +280,6 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
$model->name = $data['name'];
$model->active = isset($data['active']) ? intval($data['active']) : 0;
// TODO this needs cleaning up and thinking over.
switch ($model->accountType->type) {
case 'Asset account':
case 'Default account':
@@ -360,15 +289,15 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
$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);
// TODO this needs cleaning up and thinking over.
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) {
@@ -434,14 +363,14 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
* 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.');
}
}
}
@@ -450,11 +379,11 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
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];
@@ -473,6 +402,9 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
* @codeCoverageIgnore
*
* @param $what
*
* @throws NotImplementedException
@@ -480,7 +412,6 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
*/
public function findByWhat($what)
{
// TODO: Implement findByWhat() method.
throw new NotImplementedException;
}
@@ -489,10 +420,10 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
*
* @return Collection
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function get()
{
// TODO: Implement get() method.
throw new NotImplementedException;
}
@@ -514,14 +445,14 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
*/
public function firstExpenseAccountOrCreate($name)
{
/** @var \FireflyIII\Database\AccountType\AccountType $accountTypeRepos */
$accountTypeRepos = \App::make('FireflyIII\Database\AccountType\AccountType');
/** @var \FireflyIII\Database\AccountType\AccountType $typeRepository */
$typeRepository = \App::make('FireflyIII\Database\AccountType\AccountType');
$accountType = $accountTypeRepos->findByWhat('expense');
$accountType = $typeRepository->findByWhat('expense');
// if name is "", find cash account:
if (strlen($name) == 0) {
$cashAccountType = $accountTypeRepos->findByWhat('cash');
$cashAccountType = $typeRepository->findByWhat('cash');
// find or create cash account:
return \Account::firstOrCreate(
@@ -543,10 +474,20 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
*/
public function firstRevenueAccountOrCreate($name)
{
/** @var \FireflyIII\Database\AccountType\AccountType $accountTypeRepos */
$accountTypeRepos = \App::make('FireflyIII\Database\AccountType\AccountType');
/** @var \FireflyIII\Database\AccountType\AccountType $typeRepository */
$typeRepository = \App::make('FireflyIII\Database\AccountType\AccountType');
$accountType = $accountTypeRepos->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];
@@ -554,57 +495,6 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
}
/**
* @param \Account $account
* @param int $limit
*
* @return \Illuminate\Pagination\Paginator
*/
public function getAllTransactionJournals(\Account $account, $limit = 50)
{
$offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0;
$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
@@ -639,24 +529,4 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
}
/**
* @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;
}
}

View File

@@ -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

View File

@@ -2,8 +2,8 @@
namespace FireflyIII\Database\AccountType;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
use FireflyIII\Exception\FireflyException;
use FireflyIII\Exception\NotImplementedException;
use Illuminate\Database\Eloquent\Model as Eloquent;
@@ -14,47 +14,52 @@ use Illuminate\Support\Collection;
*
* @package FireflyIII\Database
*/
class AccountType implements CUD, CommonDatabaseCalls
class AccountType implements CUDInterface, CommonDatabaseCallsInterface
{
/**
* @param Eloquent $model
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @return bool
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function destroy(Eloquent $model)
{
// TODO: Implement destroy() method.
throw new NotImplementedException;
}
/**
* @param array $data
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @return \Eloquent
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function store(array $data)
{
// TODO: Implement store() method.
throw new NotImplementedException;
}
/**
* @param Eloquent $model
* @param array $data
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @return bool
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function update(Eloquent $model, array $data)
{
// TODO: Implement update() method.
throw new NotImplementedException;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Validates an array. Returns an array containing MessageBags
* errors/warnings/successes.
*
@@ -62,24 +67,26 @@ class AccountType implements CUD, CommonDatabaseCalls
*
* @return array
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function validate(array $model)
{
// TODO: Implement validate() method.
throw new NotImplementedException;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Returns an object with id $id.
*
* @param int $objectId
*
* @return \Eloquent
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function find($objectId)
{
// TODO: Implement find() method.
throw new NotImplementedException;
}
@@ -93,50 +100,44 @@ class AccountType implements CUD, CommonDatabaseCalls
*/
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()
{
// TODO: Implement get() method.
throw new NotImplementedException;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param array $ids
*
* @return Collection
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function getByIds(array $ids)
{
// TODO: Implement getByIds() method.
throw new NotImplementedException;
}
}

View File

@@ -1,11 +1,11 @@
<?php
namespace FireflyIII\Database\RecurringTransaction;
namespace FireflyIII\Database\Bill;
use Carbon\Carbon;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
use FireflyIII\Database\SwitchUser;
use FireflyIII\Exception\NotImplementedException;
use Illuminate\Database\Eloquent\Model as Eloquent;
@@ -13,11 +13,11 @@ use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
/**
* Class Recurring
* Class Bill
*
* @package FireflyIII\Database
*/
class RecurringTransaction implements CUD, CommonDatabaseCalls, RecurringTransactionInterface
class Bill implements CUDInterface, CommonDatabaseCallsInterface, BillInterface
{
use SwitchUser;
@@ -48,30 +48,30 @@ class RecurringTransaction implements CUD, CommonDatabaseCalls, RecurringTransac
*/
public function store(array $data)
{
$recurring = new \RecurringTransaction;
$recurring->user()->associate($this->getUser());
$recurring->name = $data['name'];
$recurring->match = $data['match'];
$recurring->amount_max = floatval($data['amount_max']);
$recurring->amount_min = floatval($data['amount_min']);
$bill = new \Bill;
$bill->user()->associate($this->getUser());
$bill->name = $data['name'];
$bill->match = $data['match'];
$bill->amount_max = floatval($data['amount_max']);
$bill->amount_min = floatval($data['amount_min']);
$date = new Carbon($data['date']);
$recurring->active = intval($data['active']);
$recurring->automatch = intval($data['automatch']);
$recurring->repeat_freq = $data['repeat_freq'];
$bill->active = intval($data['active']);
$bill->automatch = intval($data['automatch']);
$bill->repeat_freq = $data['repeat_freq'];
/*
* Jump to the start of the period.
*/
$date = \DateKit::startOfPeriod($date, $data['repeat_freq']);
$recurring->date = $date;
$recurring->skip = intval($data['skip']);
$bill->date = $date;
$bill->skip = intval($data['skip']);
$recurring->save();
$bill->save();
return $recurring;
return $bill;
}
/**
@@ -114,11 +114,11 @@ class RecurringTransaction implements CUD, CommonDatabaseCalls, RecurringTransac
$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.');
}
$object = new \RecurringTransaction($model);
$object = new \Bill($model);
$object->isValid();
$errors->merge($object->getErrors());
@@ -133,30 +133,34 @@ class RecurringTransaction implements CUD, CommonDatabaseCalls, RecurringTransac
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Returns an object with id $id.
*
* @param int $objectId
*
* @return \Eloquent
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function find($objectId)
{
// TODO: Implement find() method.
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)
{
// TODO: Implement findByWhat() method.
throw new NotImplementedException;
}
@@ -167,57 +171,97 @@ class RecurringTransaction implements CUD, CommonDatabaseCalls, RecurringTransac
*/
public function get()
{
return $this->getUser()->recurringtransactions()->get();
return $this->getUser()->bills()->get();
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
* @param array $ids
*
* @return Collection
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function getByIds(array $ids)
{
// TODO: Implement getByIds() method.
throw new NotImplementedException;
}
/**
* Returns all objects.
* @param \Bill $bill
*
* @return Collection
* @return Carbon|null
*/
public function getActive()
public function lastFoundMatch(\Bill $bill)
{
return $this->getUser()->recurringtransactions()->where('active', 1)->get();
$last = $bill->transactionjournals()->orderBy('date', 'DESC')->first();
if ($last) {
return $last->date;
}
return null;
}
/**
* @param \RecurringTransaction $recurring
* @param Carbon $start
* @param Carbon $end
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @return \TransactionJournal|null
* @param \Bill $bill
*
* @return Carbon|null
*/
public function getJournalForRecurringInRange(\RecurringTransaction $recurring, Carbon $start, Carbon $end)
public function nextExpectedMatch(\Bill $bill)
{
return $this->getUser()->transactionjournals()->where('recurring_transaction_id', $recurring->id)->after($start)->before($end)->first();
$finalDate = null;
if ($bill->active == 0) {
return $finalDate;
}
/*
* $today is the start of the next period, to make sure FF3 won't miss anything
* when the current period has a transaction journal.
*/
$today = \DateKit::addPeriod(new Carbon, $bill->repeat_freq, 0);
$skip = $bill->skip + 1;
$start = \DateKit::startOfPeriod(new Carbon, $bill->repeat_freq);
/*
* go back exactly one month/week/etc because FF3 does not care about 'next'
* bills if they're too far into the past.
*/
$counter = 0;
while ($start <= $today) {
if (($counter % $skip) == 0) {
// do something.
$end = \DateKit::endOfPeriod(clone $start, $bill->repeat_freq);
$journalCount = $bill->transactionjournals()->before($end)->after($start)->count();
if ($journalCount == 0) {
$finalDate = clone $start;
break;
}
}
// add period for next round!
$start = \DateKit::addPeriod($start, $bill->repeat_freq, 0);
$counter++;
}
return $finalDate;
}
/**
* @param \RecurringTransaction $recurring
* @param \Bill $bill
* @param \TransactionJournal $journal
*
* @return bool
*/
public function scan(\RecurringTransaction $recurring, \TransactionJournal $journal)
public function scan(\Bill $bill, \TransactionJournal $journal)
{
/*
* Match words.
*/
$wordMatch = false;
$matches = explode(',', $recurring->match);
$matches = explode(',', $bill->match);
$description = strtolower($journal->description);
/*
@@ -261,8 +305,8 @@ class RecurringTransaction implements CUD, CommonDatabaseCalls, RecurringTransac
if (count($transactions) > 1) {
$amount = max(floatval($transactions[0]->amount), floatval($transactions[1]->amount));
$min = floatval($recurring->amount_min);
$max = floatval($recurring->amount_max);
$min = floatval($bill->amount_min);
$max = floatval($bill->amount_max);
if ($amount >= $min && $amount <= $max) {
$amountMatch = true;
\Log::debug('Amount match is true!');
@@ -273,17 +317,17 @@ class RecurringTransaction implements CUD, CommonDatabaseCalls, RecurringTransac
* If both, update!
*/
if ($wordMatch && $amountMatch) {
$journal->recurringTransaction()->associate($recurring);
$journal->bill()->associate($bill);
$journal->save();
}
}
/**
* @param \RecurringTransaction $recurring
* @param \Bill $bill
*
* @return bool
*/
public function scanEverything(\RecurringTransaction $recurring)
public function scanEverything(\Bill $bill)
{
// get all journals that (may) be relevant.
// this is usually almost all of them.
@@ -291,7 +335,7 @@ class RecurringTransaction implements CUD, CommonDatabaseCalls, RecurringTransac
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $journalRepository */
$journalRepository = \App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
$set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $recurring->amount_min)->where('amount', '<=', $recurring->amount_max)
$set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)
->get(['transaction_journal_id']);
$ids = [];
@@ -303,7 +347,7 @@ class RecurringTransaction implements CUD, CommonDatabaseCalls, RecurringTransac
$journals = $journalRepository->getByIds($ids);
/** @var \TransactionJournal $journal */
foreach ($journals as $journal) {
$this->scan($recurring, $journal);
$this->scan($bill, $journal);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace FireflyIII\Database\Bill;
use Carbon\Carbon;
/**
* Interface BillInterface
*
* @package FireflyIII\Database
*/
interface BillInterface
{
/**
* @param \Bill $bill
*
* @return Carbon|null
*/
public function lastFoundMatch(\Bill $bill);
/**
* @param \Bill $bill
*
* @return Carbon|null
*/
public function nextExpectedMatch(\Bill $bill);
/**
* @param \Bill $bill
* @param \TransactionJournal $journal
*
* @return bool
*/
public function scan(\Bill $bill, \TransactionJournal $journal);
/**
* @param \Bill $bill
*
* @return bool
*/
public function scanEverything(\Bill $bill);
}

View File

@@ -2,12 +2,13 @@
namespace FireflyIII\Database\Budget;
use Carbon\Carbon;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
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;
@@ -16,7 +17,7 @@ use Illuminate\Support\MessageBag;
*
* @package FireflyIII\Database
*/
class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
class Budget implements CUDInterface, CommonDatabaseCallsInterface, BudgetInterface
{
use SwitchUser;
@@ -96,6 +97,71 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
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.
*
@@ -109,16 +175,18 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
}
/**
* @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)
{
// TODO: Implement findByWhat() method.
throw new NotImplementedException;
}
@@ -135,14 +203,16 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param array $ids
*
* @return Collection
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function getByIds(array $ids)
{
// TODO: Implement getByIds() method.
throw new NotImplementedException;
}
@@ -191,95 +261,6 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
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 doesn't 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 transactionsWithoutBudgetInDateRange(Carbon $start, Carbon $end)
{
// Add expenses that have no budget:
return $this->getUser()
->transactionjournals()
->whereNotIn(
'transaction_journals.id', function ($query) use ($start, $end) {
$query
->select('transaction_journals.id')
->from('transaction_journals')
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'));
}
)
->before($end)
->after($start)
->lessThan(0)
->transactionTypes(['Withdrawal'])
->get();
}
/**
* @param \Budget $budget
* @param Carbon $date
@@ -296,20 +277,6 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
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.
@@ -323,7 +290,7 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
*/
public function updateLimitAmount(\Budget $budget, Carbon $date, $amount)
{
/** @var \Limit $limit */
/** @var \BudgetLimit $limit */
$limit = $this->limitOnStartingOnDate($budget, $date);
if (!$limit) {
// create one!
@@ -333,8 +300,7 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
$limit->amount = $amount;
$limit->repeat_freq = 'monthly';
$limit->repeats = 0;
$result = $limit->save();
\Log::info('Created new limit? ' . boolstr($result));
$limit->save();
\Log::info('ID: ' . $limit->id);
/*
* A newly stored limit also created a limit repetition.
@@ -362,10 +328,12 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
* @param \Budget $budget
* @param Carbon $date
*
* @return \Limit
* @return \BudgetLimit
*/
public function limitOnStartingOnDate(\Budget $budget, Carbon $date)
{
return $budget->budgetLimits()->where('startdate', $date->format('Y-m-d'))->first();
return $budget->budgetLimits()->where('startdate', $date->format('Y-m-d 00:00:00'))->first();
}
}

View File

@@ -26,6 +26,15 @@ interface BudgetInterface
*
* @return Collection
*/
public function transactionsWithoutBudgetInDateRange(Carbon $start, Carbon $end);
public function expenseNoBudget(Carbon $start, Carbon $end);
/**
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function journalsNoBudget(Carbon $start, Carbon $end);
}

View File

@@ -10,7 +10,7 @@ use Illuminate\Database\Eloquent\Model as Eloquent;
*
* @package FireflyIII\Database
*/
interface CUD
interface CUDInterface
{
/**

View File

@@ -2,8 +2,8 @@
namespace FireflyIII\Database\Category;
use Carbon\Carbon;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
use FireflyIII\Database\SwitchUser;
use FireflyIII\Exception\FireflyException;
use FireflyIII\Exception\NotImplementedException;
@@ -16,7 +16,7 @@ use Illuminate\Support\MessageBag;
*
* @package FireflyIII\Database
*/
class Category implements CUD, CommonDatabaseCalls
class Category implements CUDInterface, CommonDatabaseCallsInterface
{
use SwitchUser;
@@ -99,34 +99,40 @@ class Category implements CUD, CommonDatabaseCalls
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Returns an object with id $id.
*
* @param int $objectId
*
* @return \Eloquent
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function find($objectId)
{
// TODO: Implement find() method.
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)
{
// TODO: Implement findByWhat() method.
throw new NotImplementedException;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Returns all objects.
*
* @return Collection
@@ -137,14 +143,16 @@ class Category implements CUD, CommonDatabaseCalls
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param array $ids
*
* @return Collection
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function getByIds(array $ids)
{
// TODO: Implement getByIds() method.
throw new NotImplementedException;
}
@@ -179,16 +187,23 @@ class Category implements CUD, CommonDatabaseCalls
}
/**
* @param \Category $category
* @param Carbon $date
* @param Carbon $start
* @param Carbon $end
*
* @return null
* @throws NotImplementedException
* @internal param \Category $budget
* @return Collection
*/
public function repetitionOnStartingOnDate(\Category $category, Carbon $date)
public function journalsNoCategory(Carbon $start, Carbon $end)
{
throw new NotImplementedException;
$set = $this->getUser()
->transactionjournals()
->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->whereNull('category_transaction_journal.id')
->before($end)
->after($start)
->orderBy('transaction_journals.date')
->get(['transaction_journals.*']);
return $set;
}
/**

View File

@@ -10,7 +10,7 @@ use Illuminate\Support\Collection;
*
* @package FireflyIII\Database
*/
interface CommonDatabaseCalls
interface CommonDatabaseCallsInterface
{
/**
* Returns an object with id $id.

View File

@@ -2,246 +2,37 @@
namespace FireflyIII\Database\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\SwitchUser;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
use FireflyIII\Exception\FireflyException;
use FireflyIII\Exception\NotImplementedException;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
/**
* Class Piggybank
* Class PiggyBank
*
* @package FireflyIII\Database
*/
class PiggyBank implements CUD, CommonDatabaseCalls, PiggyBankInterface
class PiggyBank extends PiggyBankShared implements CUDInterface, CommonDatabaseCallsInterface, PiggyBankInterface
{
use SwitchUser;
/**
*
*/
public function __construct()
{
$this->setUser(\Auth::user());
}
/**
* @param Eloquent $model
*
* @return bool
*/
public function destroy(Eloquent $model)
{
$model->delete();
}
/**
* @param array $data
*
* @return \Eloquent
* @throws FireflyException
*/
public function store(array $data)
{
if (!isset($data['remind_me']) || (isset($data['remind_me']) && $data['remind_me'] == 0)) {
$data['reminder'] = null;
}
$piggyBank = new \Piggybank($data);
$piggyBank->save();
return $piggyBank;
}
/**
* @param Eloquent $model
* @param array $data
*
* @return bool
*/
public function update(Eloquent $model, array $data)
{
/** @var \Piggybank $model */
$model->name = $data['name'];
$model->account_id = intval($data['account_id']);
$model->targetamount = floatval($data['targetamount']);
$model->targetdate = isset($data['targetdate']) && $data['targetdate'] != '' ? $data['targetdate'] : null;
$model->rep_every = intval($data['rep_every']);
$model->reminder_skip = intval($data['reminder_skip']);
$model->order = intval($data['order']);
$model->remind_me = intval($data['remind_me']);
$model->reminder = isset($data['reminder']) ? $data['reminder'] : 'month';
if ($model->remind_me == 0) {
$model->reminder = null;
}
$model->save();
return true;
}
/**
* Validates an array. Returns an array containing MessageBags
* errors/warnings/successes.
*
* Ignore PHPMD rules because Laravel 5.0 will make this method superfluous anyway.
*
* @param array $model
*
* @return array
*/
public function validate(array $model)
{
$warnings = new MessageBag;
$successes = new MessageBag;
$errors = new MessageBag;
/*
* Name validation:
*/
if (!isset($model['name'])) {
$errors->add('name', 'Name is mandatory');
}
if (isset($model['name']) && strlen($model['name']) == 0) {
$errors->add('name', 'Name is too short');
}
if (isset($model['name']) && strlen($model['name']) > 100) {
$errors->add('name', 'Name is too long');
}
if (intval($model['account_id']) == 0) {
$errors->add('account_id', 'Account is mandatory');
}
if ($model['targetdate'] == '' && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
$errors->add('targetdate', 'Target date is mandatory when setting reminders.');
}
if ($model['targetdate'] != '') {
try {
new Carbon($model['targetdate']);
} catch (\Exception $e) {
$errors->add('targetdate', 'Invalid date.');
}
}
if (floatval($model['targetamount']) < 0.01) {
$errors->add('targetamount', 'Amount should be above 0.01.');
}
if (!in_array(ucfirst($model['reminder']), \Config::get('firefly.piggybank_periods'))) {
$errors->add('reminder', 'Invalid reminder period (' . $model['reminder'] . ')');
}
// check period.
if (!$errors->has('reminder') && !$errors->has('targetdate') && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
$today = new Carbon;
$target = new Carbon($model['targetdate']);
switch ($model['reminder']) {
case 'week':
$today->addWeek();
break;
case 'month':
$today->addMonth();
break;
case 'year':
$today->addYear();
break;
}
if ($today > $target) {
$errors->add('reminder', 'Target date is too close to today to set reminders.');
}
}
$validator = \Validator::make($model, \Piggybank::$rules);
if ($validator->invalid()) {
$errors->merge($errors);
}
// add ok messages.
$list = ['name', 'account_id', 'targetamount', 'targetdate', 'remind_me', 'reminder'];
foreach ($list as $entry) {
if (!$errors->has($entry) && !$warnings->has($entry)) {
$successes->add($entry, 'OK');
}
}
return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes];
}
/**
* Returns an object with id $id.
*
* @param int $objectId
*
* @return \Eloquent
*/
public function find($objectId)
{
return \Piggybank::
leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where('piggybanks.id', '=', $objectId)->where(
'accounts.user_id', $this->getUser()->id
)
->first(['piggybanks.*']);
}
/**
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
*
* @param $what
*
* @return \AccountType|null
* @throws NotImplementedException
*/
public function findByWhat($what)
{
// TODO: Implement findByWhat() method.
throw new NotImplementedException;
}
/**
* Returns all objects.
*
* @return Collection
*/
public function get()
{
return $this->getUser()->piggybanks()->where('repeats', 0)->get();
}
/**
* @param array $ids
*
* @return Collection
* @throws NotImplementedException
*/
public function getByIds(array $ids)
{
// TODO: Implement getByIds() method.
throw new NotImplementedException;
}
/**
* @param \Piggybank $piggybank
* @param \PiggyBank $piggyBank
* @param Carbon $date
*
* @return mixed
* @throws FireflyException
* @throws NotImplementedException
*/
public function findRepetitionByDate(\Piggybank $piggybank, Carbon $date)
public function findRepetitionByDate(\PiggyBank $piggyBank, Carbon $date)
{
/** @var Collection $reps */
$reps = $piggybank->piggybankrepetitions()->get();
$reps = $piggyBank->piggyBankRepetitions()->get();
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) {
function (\PiggyBankRepetition $rep) use ($date) {
if ($date->between($rep->startdate, $rep->targetdate)) {
return $rep;
}
@@ -256,21 +47,12 @@ class PiggyBank implements CUD, CommonDatabaseCalls, PiggyBankInterface
}
/**
* @param \Account $account
* Returns all objects.
*
* @return float
* @return Collection
*/
public function leftOnAccount(\Account $account)
public function get()
{
\Log::debug('Now in leftOnAccount() for account #'.$account->id.' ('.$account->name.')');
$balance = \Steam::balance($account);
\Log::debug('Steam says: ' . $balance);
/** @var \Piggybank $p */
foreach ($account->piggybanks()->get() as $p) {
$balance -= $p->currentRelevantRep()->currentamount;
}
return $balance;
return $this->getUser()->piggyBanks()->where('repeats', 0)->orderBy('name')->get();
}
}

View File

@@ -0,0 +1,185 @@
<?php
namespace FireflyIII\Database\PiggyBank;
use FireflyIII\Database\SwitchUser;
use FireflyIII\Exception\NotImplementedException;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
/**
* Class PiggyBankShared
*
* @package FireflyIII\Database\PiggyBank
*/
class PiggyBankShared
{
use SwitchUser;
/**
*
*/
public function __construct()
{
$this->setUser(\Auth::user());
}
/**
* @param Eloquent $model
*
* @return bool
*/
public function destroy(Eloquent $model)
{
$reminders = \Reminder::where('remindersable_id', $model->id)->get();
/** @var \Reminder $reminder */
foreach ($reminders as $reminder) {
$reminder->delete();
}
$model->delete();
}
/**
* Returns an object with id $id.
*
* @param int $objectId
*
* @return \Eloquent
*/
public function find($objectId)
{
return \PiggyBank::
leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')->where('piggy_banks.id', '=', $objectId)->where(
'accounts.user_id', $this->getUser()->id
)
->first(['piggy_banks.*']);
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
*
* @param $what
*
* @return \AccountType|null
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function findByWhat($what)
{
throw new NotImplementedException;
}
/**
* @param array $ids
*
* @return Collection
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function getByIds(array $ids)
{
throw new NotImplementedException;
}
/**
* @param \Account $account
*
* @return float
*/
public function leftOnAccount(\Account $account)
{
\Log::debug('Now in leftOnAccount() for account #' . $account->id . ' (' . $account->name . ')');
$balance = \Steam::balance($account);
\Log::debug('Steam says: ' . $balance);
/** @var \PiggyBank $p */
foreach ($account->piggyBanks()->get() as $p) {
$balance -= $p->currentRelevantRep()->currentamount;
}
return $balance;
}
/**
* @param array $data
*
* @return \Eloquent
* @throws FireflyException
*/
public function store(array $data)
{
if (!isset($data['remind_me']) || (isset($data['remind_me']) && $data['remind_me'] == 0)) {
$data['reminder'] = null;
}
$piggyBank = new \PiggyBank($data);
$piggyBank->save();
return $piggyBank;
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param Eloquent $model
* @param array $data
*
* @return bool
*/
public function update(Eloquent $model, array $data)
{
/** @var \PiggyBank $model */
$model->name = $data['name'];
$model->account_id = intval($data['account_id']);
$model->targetamount = floatval($data['targetamount']);
$model->targetdate = isset($data['targetdate']) && $data['targetdate'] != '' ? $data['targetdate'] : null;
$model->rep_every = intval($data['rep_every']);
$model->reminder_skip = intval($data['reminder_skip']);
$model->order = intval($data['order']);
$model->remind_me = intval($data['remind_me']);
$model->reminder = isset($data['reminder']) ? $data['reminder'] : 'month';
if ($model->remind_me == 0) {
$model->reminder = null;
}
$model->save();
return true;
}
/**
* Validates an array. Returns an array containing MessageBags
* errors/warnings/successes.
*
* Ignore PHPMD rules because Laravel 5.0 will make this method superfluous anyway.
*
* @param array $model
*
* @return array
*/
public function validate(array $model)
{
$warnings = new MessageBag;
$successes = new MessageBag;
$model = new \PiggyBank($model);
$model->isValid();
$errors = $model->getErrors();
// add ok messages.
$list = ['name', 'account_id', 'targetamount', 'targetdate', 'remind_me', 'reminder'];
foreach ($list as $entry) {
if (!$errors->has($entry) && !$warnings->has($entry)) {
$successes->add($entry, 'OK');
}
}
return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes];
}
}

View File

@@ -3,46 +3,34 @@
namespace FireflyIII\Database\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Collection\PiggybankPart;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\SwitchUser;
use FireflyIII\Exception\NotImplementedException;
use Illuminate\Database\Eloquent\Model as Eloquent;
use FireflyIII\Collection\PiggyBankPart;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
/**
* Class RepeatedExpense
*
* @package FireflyIII\Database
*/
class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggyBankInterface
class RepeatedExpense extends PiggyBankShared implements CUDInterface, CommonDatabaseCallsInterface, PiggyBankInterface
{
use SwitchUser;
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
*/
public function __construct()
{
$this->setUser(\Auth::user());
}
/**
* Based on the piggy bank, the reminder-setting and
* other variables this method tries to divide the piggy bank into equal parts. Each is
* accommodated by a reminder (if everything goes to plan).
*
* @param \PiggybankRepetition $repetition
* @param \PiggyBankRepetition $repetition
*
* @return Collection
*/
public function calculateParts(\PiggybankRepetition $repetition)
public function calculateParts(\PiggyBankRepetition $repetition)
{
/** @var \Piggybank $piggyBank */
$piggyBank = $repetition->piggybank()->first();
/** @var \PiggyBank $piggyBank */
$piggyBank = $repetition->piggyBank()->first();
$bars = new Collection;
$currentStart = clone $repetition->startdate;
@@ -66,7 +54,7 @@ class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggyBankInterface
}
$amountPerBar = floatval($piggyBank->targetamount) / $bars->count();
$cumulative = $amountPerBar;
/** @var PiggybankPart $bar */
/** @var PiggyBankPart $bar */
foreach ($bars as $index => $bar) {
$bar->setAmountPerBar($amountPerBar);
$bar->setCumulativeAmount($cumulative);
@@ -82,11 +70,11 @@ class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggyBankInterface
/**
* @param array $data
*
* @return PiggybankPart
* @return PiggyBankPart
*/
public function createPiggyBankPart(array $data)
{
$part = new PiggybankPart;
$part = new PiggyBankPart;
$part->setRepetition($data['repetition']);
$part->setAmountPerBar($data['amountPerBar']);
$part->setCurrentamount($data['currentAmount']);
@@ -97,17 +85,6 @@ class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggyBankInterface
return $part;
}
/**
* @param Eloquent $model
*
* @return bool
* @throws NotImplementedException
*/
public function destroy(Eloquent $model)
{
// TODO: Implement destroy() method.
throw new NotImplementedException;
}
/**
* @param array $data
@@ -128,150 +105,12 @@ class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggyBankInterface
$data['reminder'] = null;
}
$repeated = new \Piggybank($data);
$repeated = new \PiggyBank($data);
$repeated->save();
return $repeated;
}
/**
* @param Eloquent $model
* @param array $data
*
* @return bool
* @throws NotImplementedException
*/
public function update(Eloquent $model, array $data)
{
// TODO: Implement update() method.
throw new NotImplementedException;
}
/**
* Validates an array. Returns an array containing MessageBags
* errors/warnings/successes.
*
*
* ignored because this method will be gone soon.
*
* @param array $model
*
* @return array
*/
public function validate(array $model)
{
$warnings = new MessageBag;
$successes = new MessageBag;
$errors = new MessageBag;
/*
* Name validation:
*/
if (!isset($model['name'])) {
$errors->add('name', 'Name is mandatory');
}
if (isset($model['name']) && strlen($model['name']) == 0) {
$errors->add('name', 'Name is too short');
}
if (isset($model['name']) && strlen($model['name']) > 100) {
$errors->add('name', 'Name is too long');
}
if (intval($model['account_id']) == 0) {
$errors->add('account_id', 'Account is mandatory');
}
if ($model['targetdate'] == '' && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
$errors->add('targetdate', 'Target date is mandatory when setting reminders.');
}
if ($model['targetdate'] != '') {
try {
new Carbon($model['targetdate']);
} catch (\Exception $e) {
$errors->add('targetdate', 'Invalid date.');
}
$diff = Carbon::now()->diff(new Carbon($model['targetdate']));
if ($diff->days > 365) {
$errors->add('targetdate', 'First target date should a a year or less from now.');
}
} else {
$errors->add('targetdate', 'Invalid target date.');
}
if (floatval($model['targetamount']) < 0.01) {
$errors->add('targetamount', 'Amount should be above 0.01.');
}
if (!in_array(ucfirst($model['reminder']), \Config::get('firefly.piggybank_periods'))) {
$errors->add('reminder', 'Invalid reminder period (' . $model['reminder'] . ')');
}
if (!in_array(ucfirst($model['rep_length']), \Config::get('firefly.piggybank_periods'))) {
$errors->add('rep_length', 'Invalid repeat period (' . $model['rep_length'] . ')');
}
// check period.
if (!$errors->has('reminder') && !$errors->has('targetdate') && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
$today = new Carbon;
$target = new Carbon($model['targetdate']);
switch ($model['reminder']) {
case 'week':
$today->addWeek();
break;
case 'month':
$today->addMonth();
break;
case 'year':
$today->addYear();
break;
}
if ($today > $target) {
$errors->add('reminder', 'Target date is too close to today to set reminders.');
}
}
$validator = \Validator::make($model, \Piggybank::$rules);
if ($validator->invalid()) {
$errors->merge($errors);
}
// add ok messages.
$list = ['name', 'account_id', 'rep_every', 'rep_times', 'rep_length', 'targetamount', 'targetdate', 'remind_me', 'reminder'];
foreach ($list as $entry) {
if (!$errors->has($entry) && !$warnings->has($entry)) {
$successes->add($entry, 'OK');
}
}
return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes];
}
/**
* Returns an object with id $id.
*
* @param int $objectId
*
* @return \Eloquent
* @throws NotImplementedException
*/
public function find($objectId)
{
// TODO: Implement find() method.
throw new NotImplementedException;
}
/**
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
*
* @param $what
*
* @return \AccountType|null
* @throws NotImplementedException
*/
public function findByWhat($what)
{
// TODO: Implement findByWhat() method.
throw new NotImplementedException;
}
/**
* Returns all objects.
*
@@ -279,30 +118,7 @@ class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggyBankInterface
*/
public function get()
{
return $this->getUser()->piggybanks()->where('repeats', 1)->get();
return $this->getUser()->piggyBanks()->where('repeats', 1)->get();
}
/**
* @param array $ids
*
* @return Collection
* @throws NotImplementedException
*/
public function getByIds(array $ids)
{
// TODO: Implement getByIds() method.
throw new NotImplementedException;
}
/**
* @param \Account $account
*
* @return float
* @throws NotImplementedException
*/
public function leftOnAccount(\Account $account)
{
// TODO: Implement leftOnAccount() method.
throw new NotImplementedException;
}
}

View File

@@ -1,41 +0,0 @@
<?php
namespace FireflyIII\Database\RecurringTransaction;
use Carbon\Carbon;
/**
* Interface RecurringInterface
*
* @package FireflyIII\Database
*/
interface RecurringTransactionInterface
{
/**
* @param \RecurringTransaction $recurring
* @param Carbon $start
* @param Carbon $end
*
* @return null|\TransactionJournal
* @internal param Carbon $current
* @internal param Carbon $currentEnd
*
*/
public function getJournalForRecurringInRange(\RecurringTransaction $recurring, Carbon $start, Carbon $end);
/**
* @param \RecurringTransaction $recurring
* @param \TransactionJournal $journal
*
* @return bool
*/
public function scan(\RecurringTransaction $recurring, \TransactionJournal $journal);
/**
* @param \RecurringTransaction $recurring
*
* @return bool
*/
public function scanEverything(\RecurringTransaction $recurring);
}

View File

@@ -2,8 +2,8 @@
namespace FireflyIII\Database\Transaction;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
use FireflyIII\Database\SwitchUser;
use FireflyIII\Exception\FireflyException;
use FireflyIII\Exception\NotImplementedException;
@@ -16,19 +16,20 @@ use Illuminate\Support\MessageBag;
*
* @package FireflyIII\Database
*/
class Transaction implements CUD, CommonDatabaseCalls
class Transaction implements CUDInterface, CommonDatabaseCallsInterface
{
use SwitchUser;
/**
* @param Eloquent $model
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @return bool
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function destroy(Eloquent $model)
{
// TODO: Implement destroy() method.
throw new NotImplementedException;
}
@@ -44,8 +45,8 @@ class Transaction implements CUD, CommonDatabaseCalls
$transaction->account()->associate($data['account']);
$transaction->transactionJournal()->associate($data['transaction_journal']);
$transaction->amount = floatval($data['amount']);
if (isset($data['piggybank'])) {
$transaction->piggybank()->associate($data['piggybank']);
if (isset($data['piggyBank'])) {
$transaction->piggyBank()->associate($data['piggyBank']);
}
if (isset($data['description'])) {
$transaction->description = $data['description'];
@@ -60,15 +61,17 @@ class Transaction implements CUD, CommonDatabaseCalls
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param Eloquent $model
* @param array $data
*
* @return bool
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function update(Eloquent $model, array $data)
{
// TODO: Implement update() method.
throw new NotImplementedException;
}
@@ -94,30 +97,34 @@ class Transaction implements CUD, CommonDatabaseCalls
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Returns an object with id $id.
*
* @param int $objectId
*
* @return \Eloquent
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function find($objectId)
{
// TODO: Implement find() method.
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)
{
// TODO: Implement findByWhat() method.
throw new NotImplementedException;
}
@@ -126,22 +133,24 @@ class Transaction implements CUD, CommonDatabaseCalls
*
* @return Collection
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function get()
{
// TODO: Implement get() method.
throw new NotImplementedException;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param array $ids
*
* @return Collection
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function getByIds(array $ids)
{
// TODO: Implement getByIds() method.
throw new NotImplementedException;
}
}

View File

@@ -2,8 +2,8 @@
namespace FireflyIII\Database\TransactionCurrency;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
use FireflyIII\Exception\NotImplementedException;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Support\Collection;
@@ -14,7 +14,7 @@ use Illuminate\Support\MessageBag;
*
* @package FireflyIII\Database
*/
class TransactionCurrency implements TransactionCurrencyInterface, CommonDatabaseCalls, CUD
class TransactionCurrency implements TransactionCurrencyInterface, CommonDatabaseCallsInterface, CUDInterface
{
/**
@@ -35,7 +35,6 @@ class TransactionCurrency implements TransactionCurrencyInterface, CommonDatabas
public function store(array $data)
{
$currency = new \TransactionCurrency($data);
\Log::debug('Is valid? ' . boolstr($currency->isValid()));
$currency->save();
return $currency;
@@ -52,7 +51,6 @@ class TransactionCurrency implements TransactionCurrencyInterface, CommonDatabas
$model->symbol = $data['symbol'];
$model->code = $data['code'];
$model->name = $data['name'];
\Log::debug('Is valid? ' . boolstr($model->isValid()));
$model->save();
return true;
@@ -91,6 +89,8 @@ class TransactionCurrency implements TransactionCurrencyInterface, CommonDatabas
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Returns an object with id $id.
*
* @param int $objectId
@@ -99,20 +99,22 @@ class TransactionCurrency implements TransactionCurrencyInterface, CommonDatabas
*/
public function find($objectId)
{
// TODO: Implement find() method.
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
*/
public function findByWhat($what)
{
// TODO: Implement findByWhat() method.
throw new NotImplementedException;
}
@@ -127,13 +129,16 @@ class TransactionCurrency implements TransactionCurrencyInterface, CommonDatabas
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param array $objectIds
* @throws NotImplementedException
* @codeCoverageIgnore
*
* @return Collection
*/
public function getByIds(array $objectIds)
{
// TODO: Implement getByIds() method.
throw new NotImplementedException;
}

View File

@@ -4,8 +4,8 @@ namespace FireflyIII\Database\TransactionJournal;
use Carbon\Carbon;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
use FireflyIII\Database\SwitchUser;
use FireflyIII\Exception\FireflyException;
use FireflyIII\Exception\NotImplementedException;
@@ -18,7 +18,7 @@ use Illuminate\Support\MessageBag;
*
* @package FireflyIII\Database
*/
class TransactionJournal implements TransactionJournalInterface, CUD, CommonDatabaseCalls
class TransactionJournal implements TransactionJournalInterface, CUDInterface, CommonDatabaseCallsInterface
{
use SwitchUser;
@@ -63,18 +63,27 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
*/
public function store(array $data)
{
$journalType = $this->getJournalType($data['what']);
$currency = $this->getJournalCurrency($data['currency']);
$journal = new \TransactionJournal(
['transaction_type_id' => $journalType->id, 'transaction_currency_id' => $currency->id, 'user_id' => $this->getUser()->id,
'description' => $data['description'], 'date' => $data['date'], 'completed' => 0]
[
'transaction_type_id' => $data['transaction_type_id'],
'transaction_currency_id' => $data['transaction_currency_id'],
'user_id' => $this->getUser()->id,
'description' => $data['description'],
'date' => $data['date'], 'completed' => 0]
);
$journal->save();
list($fromAccount, $toAccount) = $this->storeAccounts($data);
$this->storeTransaction(['account' => $fromAccount, 'transaction_journal' => $journal, 'amount' => floatval($data['amount'] * -1)]);
$this->storeTransaction(['account' => $toAccount, 'transaction_journal' => $journal, 'amount' => floatval($data['amount'])]);
$this->storeTransaction(
['account_id' => $fromAccount->id, 'account' => $fromAccount, 'transaction_journal' => $journal, 'transaction_journal_id' => $journal->id,
'amount' => floatval($data['amount'] * -1)]
);
$this->storeTransaction(
['account_id' => $toAccount->id, 'account' => $toAccount, 'transaction_journal' => $journal, 'transaction_journal_id' => $journal->id,
'amount' => floatval($data['amount'])]
);
$this->storeBudget($data, $journal);
$this->storeCategory($data, $journal);
@@ -94,7 +103,7 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
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'];
@@ -105,12 +114,10 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
list($fromAccount, $toAccount) = $this->storeAccounts($data);
/** @noinspection PhpParamsInspection */
$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) {
@@ -128,7 +135,7 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
$transaction->save();
}
return new MessageBag;
return true;
}
/**
@@ -147,127 +154,27 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
$warnings = new MessageBag;
$successes = new MessageBag;
$errors = new MessageBag;
$journal = new \TransactionJournal($model);
$journal->isValid();
$errors = $journal->getErrors();
if (!isset($model['what'])) {
$errors->add('description', 'Internal error: need to know type of transaction!');
}
if (isset($model['recurring_transaction_id']) && intval($model['recurring_transaction_id']) < 0) {
$errors->add('recurring_transaction_id', 'Recurring transaction is invalid.');
}
if (!isset($model['description'])) {
$errors->add('description', 'This field is mandatory.');
}
if (isset($model['description']) && strlen($model['description']) == 0) {
$errors->add('description', 'This field is mandatory.');
}
if (isset($model['description']) && strlen($model['description']) > 255) {
$errors->add('description', 'Description is too long.');
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));
if (!isset($model['currency'])) {
$errors->add('description', 'Internal error: currency is mandatory!');
$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');
}
if (isset($model['date']) && !($model['date'] instanceof Carbon) && strlen($model['date']) > 0) {
try {
new Carbon($model['date']);
} catch (\Exception $e) {
$errors->add('date', 'This date is invalid.');
}
}
if (!isset($model['date'])) {
$errors->add('date', 'This date is invalid.');
}
/*
* 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');
}
}
/*
* 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;
}
$validator = \Validator::make([$model], \TransactionJournal::$rules);
if ($validator->invalid()) {
$errors->merge($errors);
}
/*
* 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];
@@ -276,33 +183,8 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
}
/**
* @param $type
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @return \AccountType|null
* @throws FireflyException
*/
public function getJournalType($type)
{
/** @var \FireflyIII\Database\TransactionType\TransactionType $typeRepository */
$typeRepository = \App::make('FireflyIII\Database\TransactionType\TransactionType');
return $typeRepository->findByWhat($type);
}
/**
* @param $currency
*
* @return null|\TransactionCurrency
*/
public function getJournalCurrency($currency)
{
/** @var \FireflyIII\Database\TransactionCurrency\TransactionCurrency $currencyRepository */
$currencyRepository = \App::make('FireflyIII\Database\TransactionCurrency\TransactionCurrency');
return $currencyRepository->findByCode($currency);
}
/**
* @param array $data
*
* @return array
@@ -321,6 +203,8 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
$toAccount = $accountRepository->firstExpenseAccountOrCreate($data['expense_account']);
break;
case 'opening':
$fromAccount = $data['from'];
$toAccount = $data['to'];
break;
case 'deposit':
$fromAccount = $accountRepository->firstRevenueAccountOrCreate($data['revenue_account']);
@@ -389,7 +273,127 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
if ($category) {
$journal->categories()->sync([$category->id]);
}
return;
}
$journal->categories()->sync([]);
return;
}
/**
* @param $type
*
* @return \TransactionType|null
* @throws FireflyException
*/
public function getJournalType($type)
{
/** @var \FireflyIII\Database\TransactionType\TransactionType $typeRepository */
$typeRepository = \App::make('FireflyIII\Database\TransactionType\TransactionType');
return $typeRepository->findByWhat($type);
}
/**
* @param int $currencyId
*
* @return null|\TransactionCurrency
*/
public function getJournalCurrencyById($currencyId)
{
/** @var \FireflyIII\Database\TransactionCurrency\TransactionCurrency $currencyRepository */
$currencyRepository = \App::make('FireflyIII\Database\TransactionCurrency\TransactionCurrency');
return $currencyRepository->find($currencyId);
}
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* @param array $model
*
* @return MessageBag
*/
protected function _validateAmount(array $model)
{
$errors = new MessageBag;
if (isset($model['amount']) && floatval($model['amount']) < 0.01) {
$errors->add('amount', 'Amount must be > 0.01');
} else {
if (!isset($model['amount'])) {
$errors->add('amount', 'Amount must be set!');
}
}
return $errors;
}
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* @param array $model
*
* @return MessageBag
*/
protected function _validateBudget(array $model)
{
/*
* Budget (is not in rules)
*/
$errors = new MessageBag;
if (isset($model['budget_id']) && !ctype_digit($model['budget_id'])) {
$errors->add('budget_id', 'Invalid budget');
}
return $errors;
}
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* @param array $model
*
* @return MessageBag
* @throws FireflyException
*/
protected function _validateAccount(array $model)
{
$errors = new MessageBag;
switch (true) {
// this combination is often seen in withdrawals.
case (isset($model['account_id']) && isset($model['expense_account'])):
if (intval($model['account_id']) < 1) {
$errors->add('account_id', 'Invalid account.');
}
break;
// often seen in deposits
case (isset($model['account_id']) && isset($model['revenue_account'])):
if (intval($model['account_id']) < 1) {
$errors->add('account_id', 'Invalid account.');
}
break;
// often seen in transfers
case (isset($model['account_from_id']) && isset($model['account_to_id'])):
if (intval($model['account_from_id']) < 1 || intval($model['account_from_id']) < 1) {
$errors->add('account_from_id', 'Invalid account selected.');
$errors->add('account_to_id', 'Invalid account selected.');
} else {
if (intval($model['account_from_id']) == intval($model['account_to_id'])) {
$errors->add('account_to_id', 'Cannot be the same as "from" account.');
$errors->add('account_from_id', 'Cannot be the same as "to" account.');
}
}
break;
case (isset($model['from']) && isset($model['to'])):
break;
default:
throw new FireflyException('Cannot validate accounts for transaction journal.');
break;
}
return $errors;
}
/**
@@ -397,24 +401,30 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
*
* @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)
{
// TODO: Implement findByWhat() method.
throw new NotImplementedException;
}
@@ -422,11 +432,11 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
* 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;
}
/**
@@ -460,17 +470,6 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
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
*
@@ -478,16 +477,15 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
*/
public function getSumOfExpensesByMonth(Carbon $date)
{
$end = clone $date;
$date->startOfMonth();
$end->endOfMonth();
/** @var \FireflyIII\Report\ReportInterface $reportRepository */
$reportRepository = \App::make('FireflyIII\Report\ReportInterface');
$set = $reportRepository->getExpenseGroupedForMonth($date, 200);
$sum = 0;
foreach ($set as $entry) {
$sum += $entry['amount'];
}
$sum = \DB::table('transactions')->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->leftJoin(
'transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id'
)->where('amount', '>', 0)->where('transaction_types.type', '=', 'Withdrawal')->where('transaction_journals.date', '>=', $date->format('Y-m-d'))->where(
'transaction_journals.date', '<=', $end->format('Y-m-d')
)->sum('transactions.amount');
$sum = floatval($sum);
return $sum;
}
@@ -499,18 +497,17 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
*/
public function getSumOfIncomesByMonth(Carbon $date)
{
$end = clone $date;
$date->startOfMonth();
$end->endOfMonth();
/** @var \FireflyIII\Report\ReportInterface $reportRepository */
$reportRepository = \App::make('FireflyIII\Report\ReportInterface');
$sum = \DB::table('transactions')->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->leftJoin(
'transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id'
)->where('amount', '>', 0)->where('transaction_types.type', '=', 'Deposit')->where('transaction_journals.date', '>=', $date->format('Y-m-d'))->where(
'transaction_journals.date', '<=', $end->format('Y-m-d')
)->sum('transactions.amount');
$sum = floatval($sum);
$incomes = $reportRepository->getIncomeForMonth($date);
$totalIn = 0;
/** @var \TransactionJournal $entry */
foreach ($incomes as $entry) {
$totalIn += $entry->getAmount();
}
return $sum;
return $totalIn;
}
/**
@@ -557,6 +554,19 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
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
*
@@ -598,37 +608,4 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
return \Paginator::make($items, $count, $limit);
}
/**
* @param string $query
* @param \TransactionJournal $journal
*
* @return Collection
*/
public function searchRelated($query, \TransactionJournal $journal)
{
$start = clone $journal->date;
$end = clone $journal->date;
$start->startOfMonth();
$end->endOfMonth();
// get already related transactions:
$exclude = [$journal->id];
foreach ($journal->transactiongroups()->get() as $group) {
foreach ($group->transactionjournals() as $jrnl) {
$exclude[] = $jrnl->id;
}
}
$exclude = array_unique($exclude);
$query = $this->getUser()->transactionjournals()
->withRelevantData()
->before($end)
->after($start)
->whereNotIn('id', $exclude)
->where('description', 'LIKE', '%' . $query . '%')
->get();
return $query;
}
}

View File

@@ -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
*

View File

@@ -3,8 +3,8 @@
namespace FireflyIII\Database\TransactionType;
use FireflyIII\Database\CommonDatabaseCalls;
use FireflyIII\Database\CUD;
use FireflyIII\Database\CommonDatabaseCallsInterface;
use FireflyIII\Database\CUDInterface;
use FireflyIII\Exception\FireflyException;
use FireflyIII\Exception\NotImplementedException;
use Illuminate\Database\Eloquent\Model as Eloquent;
@@ -16,47 +16,55 @@ use Illuminate\Support\Collection;
*
* @package FireflyIII\Database
*/
class TransactionType implements CUD, CommonDatabaseCalls
class TransactionType implements CUDInterface, CommonDatabaseCallsInterface
{
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param Eloquent $model
*
* @return bool
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function destroy(Eloquent $model)
{
// TODO: Implement destroy() method.
throw new NotImplementedException;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param array $data
*
* @return \Eloquent
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function store(array $data)
{
// TODO: Implement store() method.
throw new NotImplementedException;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param Eloquent $model
* @param array $data
*
* @return bool
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function update(Eloquent $model, array $data)
{
// TODO: Implement update() method.
throw new NotImplementedException;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Validates an array. Returns an array containing MessageBags
* errors/warnings/successes.
*
@@ -64,24 +72,26 @@ class TransactionType implements CUD, CommonDatabaseCalls
*
* @return array
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function validate(array $model)
{
// TODO: Implement validate() method.
throw new NotImplementedException;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Returns an object with id $id.
*
* @param int $objectId
*
* @return \Eloquent
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function find($objectId)
{
// TODO: Implement find() method.
throw new NotImplementedException;
}
@@ -95,48 +105,44 @@ class TransactionType implements CUD, CommonDatabaseCalls
*/
public function findByWhat($what)
{
switch ($what) {
case 'opening':
return \TransactionType::whereType('Opening balance')->first();
break;
case 'transfer':
return \TransactionType::whereType('Transfer')->first();
break;
case 'withdrawal':
return \TransactionType::whereType('Withdrawal')->first();
break;
case 'deposit':
return \TransactionType::whereType('Deposit')->first();
break;
default:
$translation = [
'opening' => 'Opening balance',
'transfer' => 'Transfer',
'withdrawal' => 'Withdrawal',
'deposit' => 'Deposit',
];
if (!isset($translation[$what])) {
throw new FireflyException('Cannot find transaction type described as "' . e($what) . '".');
break;
}
return \TransactionType::whereType($translation[$what])->first();
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* Returns all objects.
*
* @return Collection
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function get()
{
// TODO: Implement get() method.
throw new NotImplementedException;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param array $ids
*
* @return Collection
* @throws NotImplementedException
* @codeCoverageIgnore
*/
public function getByIds(array $ids)
{
// TODO: Implement getByIds() method.
throw new NotImplementedException;
}
}

View File

@@ -14,7 +14,7 @@ class User
/**
* @param $mail
*
* @return null|User
* @return null|\User
*/
public function findByEmail($mail)
{
@@ -43,7 +43,8 @@ class User
$user->reset = \Str::random(32);
$user->password = \Hash::make(\Str::random(12));
if (!$user->save()) {
// validate user:
if (!$user->isValid()) {
\Log::error('Invalid user with data: ' . isset($data['email']) ? $data['email'] : '(no email!)');
\Session::flash('error', 'Input invalid, please try again: ' . $user->getErrors()->first());

View File

@@ -20,10 +20,10 @@ class Event
public function deleteAccount(\Account $account)
{
// get piggy banks
$piggies = $account->piggybanks()->get();
$piggies = $account->piggyBanks()->get();
// get reminders for each
/** @var \Piggybank $piggyBank */
/** @var \PiggyBank $piggyBank */
foreach ($piggies as $piggyBank) {
$reminders = $piggyBank->reminders()->get();
/** @var \Reminder $reminder */

View File

@@ -7,22 +7,22 @@ use Carbon\Carbon;
use Illuminate\Events\Dispatcher;
/**
* Class Piggybank
* Class PiggyBank
*
* @package FireflyIII\Event
*/
class Piggybank
class PiggyBank
{
/**
* @param \Piggybank $piggybank
* @param \PiggyBank $piggyBank
* @param float $amount
*/
public function addMoney(\Piggybank $piggybank, $amount = 0.0)
public function addMoney(\PiggyBank $piggyBank, $amount = 0.0)
{
if ($amount > 0) {
$event = new \PiggyBankEvent;
$event->piggybank()->associate($piggybank);
$event->piggyBank()->associate($piggyBank);
$event->amount = floatval($amount);
$event->date = new Carbon;
if (!$event->isValid()) {
@@ -34,6 +34,8 @@ class Piggybank
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param \TransactionJournal $journal
*
* @throws \FireflyIII\Exception\FireflyException
@@ -41,15 +43,15 @@ class Piggybank
*/
public function destroyTransfer(\TransactionJournal $journal)
{
if ($journal->piggybankevents()->count() > 0) {
if ($journal->piggyBankEvents()->count() > 0) {
/** @var \FireflyIII\Database\PiggyBank\PiggyBank $repository */
$repository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank');
/** @var \Piggybank $piggyBank */
$piggyBank = $journal->piggybankevents()->first()->piggybank()->first();
/** @var \PiggyBank $piggyBank */
$piggyBank = $journal->piggyBankEvents()->first()->piggyBank()->first();
/** @var \PiggybankRepetition $repetition */
/** @var \PiggyBankRepetition $repetition */
$repetition = $repository->findRepetitionByDate($piggyBank, $journal->date);
$relevantTransaction = null;
@@ -68,7 +70,7 @@ class Piggybank
$event = new \PiggyBankEvent;
$event->piggybank()->associate($piggyBank);
$event->piggyBank()->associate($piggyBank);
$event->amount = floatval($relevantTransaction->amount * -1);
$event->date = new Carbon;
$event->save();
@@ -76,15 +78,15 @@ class Piggybank
}
/**
* @param \Piggybank $piggybank
* @param \PiggyBank $piggyBank
* @param float $amount
*/
public function removeMoney(\Piggybank $piggybank, $amount = 0.0)
public function removeMoney(\PiggyBank $piggyBank, $amount = 0.0)
{
$amount = $amount * -1;
if ($amount < 0) {
$event = new \PiggyBankEvent;
$event->piggybank()->associate($piggybank);
$event->piggyBank()->associate($piggyBank);
$event->amount = floatval($amount);
$event->date = new Carbon;
$event->save();
@@ -92,43 +94,43 @@ class Piggybank
}
/**
* @param \Piggybank $piggybank
* @param \PiggyBank $piggyBank
*/
public function storePiggybank(\Piggybank $piggybank)
public function storePiggyBank(\PiggyBank $piggyBank)
{
if (intval($piggybank->repeats) == 0) {
$repetition = new \PiggybankRepetition;
$repetition->piggybank()->associate($piggybank);
$repetition->startdate = $piggybank->startdate;
$repetition->targetdate = $piggybank->targetdate;
$repetition = new \PiggyBankRepetition;
$repetition->piggyBank()->associate($piggyBank);
$repetition->startdate = $piggyBank->startdate;
$repetition->targetdate = $piggyBank->targetdate;
$repetition->currentamount = 0;
$repetition->save();
}
}
/*
*
*/
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param \TransactionJournal $journal
* @param int $piggybankId
* @param int $piggyBankId
*/
public function storeTransfer(\TransactionJournal $journal, $piggybankId = 0)
public function storeTransfer(\TransactionJournal $journal, $piggyBankId = 0)
{
if (intval($piggybankId) == 0) {
if (intval($piggyBankId) == 0) {
return;
}
/** @var \FireflyIII\Database\PiggyBank\PiggyBank $repository */
$repository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank');
/** @var \Piggybank $piggyBank */
$piggyBank = $repository->find($piggybankId);
/** @var \PiggyBank $piggyBank */
$piggyBank = $repository->find($piggyBankId);
if ($journal->transactions()->where('account_id', $piggyBank->account_id)->count() == 0) {
return;
}
/** @var \PiggybankRepetition $repetition */
/** @var \PiggyBankRepetition $repetition */
$repetition = $repository->findRepetitionByDate($piggyBank, $journal->date);
$amount = floatval($piggyBank->targetamount);
$leftToSave = $amount - floatval($repetition->currentamount);
@@ -146,7 +148,7 @@ class Piggybank
$repetition->currentamount += floatval($transaction->amount);
$repetition->save();
$event = new \PiggyBankEvent;
$event->piggybank()->associate($piggyBank);
$event->piggyBank()->associate($piggyBank);
$event->transactionjournal()->associate($journal);
$event->amount = floatval($transaction->amount);
$event->date = new Carbon;
@@ -160,10 +162,10 @@ class Piggybank
public function subscribe(Dispatcher $events)
{
// triggers on piggy bank events:
$events->listen('piggybank.addMoney', 'FireflyIII\Event\Piggybank@addMoney');
$events->listen('piggybank.removeMoney', 'FireflyIII\Event\Piggybank@removeMoney');
$events->listen('piggybank.store', 'FireflyIII\Event\Piggybank@storePiggybank');
$events->listen('piggybank.update', 'FireflyIII\Event\Piggybank@updatePiggybank');
$events->listen('piggy_bank.addMoney', 'FireflyIII\Event\PiggyBank@addMoney');
$events->listen('piggy_bank.removeMoney', 'FireflyIII\Event\PiggyBank@removeMoney');
$events->listen('piggy_bank.store', 'FireflyIII\Event\PiggyBank@storePiggyBank');
$events->listen('piggy_bank.update', 'FireflyIII\Event\PiggyBank@updatePiggyBank');
\App::before(
function () {
@@ -171,16 +173,15 @@ class Piggybank
}
);
//$events->listen('piggybank.boo', 'FireflyIII\Event\Piggybank@updatePiggybank');
// triggers when others are updated.
$events->listen('transactionJournal.store', 'FireflyIII\Event\Piggybank@storeTransfer');
$events->listen('transactionJournal.update', 'FireflyIII\Event\Piggybank@updateTransfer');
$events->listen('transactionJournal.destroy', 'FireflyIII\Event\Piggybank@destroyTransfer');
$events->listen('transactionJournal.store', 'FireflyIII\Event\PiggyBank@storeTransfer');
$events->listen('transactionJournal.update', 'FireflyIII\Event\PiggyBank@updateTransfer');
$events->listen('transactionJournal.destroy', 'FireflyIII\Event\PiggyBank@destroyTransfer');
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's 6. More than 5 but alright.
*
* Validates the presence of repetitions for all repeated expenses!
*/
public function validateRepeatedExpenses()
@@ -190,36 +191,28 @@ class Piggybank
}
/** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repository */
$repository = \App::make('FireflyIII\Database\PiggyBank\RepeatedExpense');
$list = $repository->get();
$today = Carbon::now();
/** @var \Piggybank $entry */
/** @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 = new \PiggyBankRepetition;
$repetition->piggyBank()->associate($entry);
$repetition->startdate = $entry->startdate;
$repetition->targetdate = $entry->targetdate;
$repetition->currentamount = 0;
$repetition->save();
}
// then continue and do something in the current relevant timeframe.
$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();
$count = $entry->piggyBankRepetitions()->starts($currentStart)->targets($currentTarget)->count();
if ($count == 0) {
$repetition = new \PiggybankRepetition;
$repetition->piggybank()->associate($entry);
$repetition = new \PiggyBankRepetition;
$repetition->piggyBank()->associate($entry);
$repetition->startdate = $currentStart;
$repetition->targetdate = $currentTarget;
$repetition->currentamount = 0;
@@ -231,9 +224,9 @@ class Piggybank
}
/**
* @param \Piggybank $piggyBank
* @param \PiggyBank $piggyBank
*/
public function updatePiggybank(\Piggybank $piggyBank)
public function updatePiggyBank(\PiggyBank $piggyBank)
{
// get the repetition:
$repetition = $piggyBank->currentRelevantRep();
@@ -251,18 +244,18 @@ class Piggybank
public function updateTransfer(\TransactionJournal $journal)
{
if ($journal->piggybankevents()->count() > 0) {
if ($journal->piggyBankEvents()->count() > 0) {
$event = $journal->piggybankevents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->first();
$eventSum = floatval($journal->piggybankevents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->sum('amount'));
$event = $journal->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->first();
$eventSum = floatval($journal->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->sum('amount'));
/** @var \FireflyIII\Database\PiggyBank\PiggyBank $repository */
$repository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank');
/** @var \Piggybank $piggyBank */
$piggyBank = $journal->piggybankevents()->first()->piggybank()->first();
/** @var \PiggyBank $piggyBank */
$piggyBank = $journal->piggyBankEvents()->first()->piggyBank()->first();
/** @var \PiggybankRepetition $repetition */
/** @var \PiggyBankRepetition $repetition */
$repetition = $repository->findRepetitionByDate($piggyBank, $journal->date);
$relevantTransaction = null;
@@ -285,13 +278,13 @@ class Piggybank
$event = new \PiggyBankEvent;
$event->piggybank()->associate($piggyBank);
$event->piggyBank()->associate($piggyBank);
$event->transactionJournal()->associate($journal);
$event->amount = $diff;
$event->date = new Carbon;
if (!$event->isValid()) {
var_dump($event->getErrors());
exit();
\Log::error($event->getErrors());
\App::abort(500);
}
$event->save();
}

View File

@@ -17,12 +17,12 @@ class TransactionJournal
*/
public function store(\TransactionJournal $journal)
{
/** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repository */
$repository = \App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction');
/** @var \FireflyIII\Database\Bill\Bill $repository */
$repository = \App::make('FireflyIII\Database\Bill\Bill');
$set = $repository->get();
/** @var \RecurringTransaction $entry */
/** @var \Bill $entry */
foreach ($set as $entry) {
$repository->scan($entry, $journal);
}
@@ -43,13 +43,13 @@ class TransactionJournal
*/
public function update(\TransactionJournal $journal)
{
/** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repository */
$repository = \App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction');
/** @var \FireflyIII\Database\Bill\Bill $repository */
$repository = \App::make('FireflyIII\Database\Bill\Bill');
$set = $repository->get();
$journal->recurring_transaction_id = null;
$journal->bill_id = null;
$journal->save();
/** @var \RecurringTransaction $entry */
/** @var \Bill $entry */
foreach ($set as $entry) {
$repository->scan($entry, $journal);
}

View File

@@ -7,6 +7,7 @@ use FireflyIII\Shared\Toolkit\Form;
use FireflyIII\Shared\Toolkit\Navigation;
use FireflyIII\Shared\Toolkit\Reminders;
use FireflyIII\Shared\Toolkit\Steam;
use FireflyIII\Shared\Toolkit\Amount;
use FireflyIII\Shared\Validation\FireflyValidator;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\ServiceProvider;
@@ -31,6 +32,7 @@ class FF3ServiceProvider extends ServiceProvider
/**
* Return the services bla bla.
*
* @CodeCoverageIgnore
* @return array
*/
public function provides()
@@ -43,8 +45,6 @@ class FF3ServiceProvider extends ServiceProvider
*/
public function register()
{
// FORMAT:
#$this->app->bind('Interface', 'Class');
$this->registerFacades();
$this->registerInterfaces();
$this->registerAliases();
@@ -84,18 +84,29 @@ class FF3ServiceProvider extends ServiceProvider
return new Steam;
}
);
$this->app->bind(
'amount', function () {
return new Amount;
}
);
}
public function registerInterfaces()
{
// preferences:
// preferences
$this->app->bind('FireflyIII\Shared\Preferences\PreferencesInterface', 'FireflyIII\Shared\Preferences\Preferences');
// registration and user mail:
// registration and user mail
$this->app->bind('FireflyIII\Shared\Mail\RegistrationInterface', 'FireflyIII\Shared\Mail\Registration');
// reports
$this->app->bind('FireflyIII\Report\ReportInterface', 'FireflyIII\Report\Report');
$this->app->bind('FireflyIII\Report\ReportQueryInterface', 'FireflyIII\Report\ReportQuery');
$this->app->bind('FireflyIII\Report\ReportHelperInterface', 'FireflyIII\Report\ReportHelper');
$this->app->bind('FireflyIII\Helper\Related\RelatedInterface', 'FireflyIII\Helper\Related\Related');
$this->app->bind('FireflyIII\Helper\TransactionJournal\HelperInterface', 'FireflyIII\Helper\TransactionJournal\Helper');
// chart
$this->app->bind('FireflyIII\Chart\ChartInterface', 'FireflyIII\Chart\Chart');
@@ -113,6 +124,7 @@ class FF3ServiceProvider extends ServiceProvider
$loader->alias('Navigation', 'FireflyIII\Shared\Facade\Navigation');
$loader->alias('FFForm', 'FireflyIII\Shared\Facade\FFForm');
$loader->alias('Steam', 'FireflyIII\Shared\Facade\Steam');
$loader->alias('Amount', 'FireflyIII\Shared\Facade\Amount');
}
);
}

View File

@@ -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 = '<div class="' . $classes . '">';
$html .= '<label for="' . $options['id'] . '" class="col-sm-4 control-label">' . $label . '</label>';
$html .= '<div class="col-sm-8">';
/*
* Switch input type:
*/
unset($options['label']);
switch ($type) {
case 'text':
$html .= \Form::input('text', $name, $value, $options);
break;
case 'amount':
$html .= '<div class="input-group"><div class="input-group-addon">'.getCurrencySymbol().'</div>';
$html .= \Form::input('number', $name, $value, $options);
$html .= '</div>';
break;
case 'number':
$html .= \Form::input('number', $name, $value, $options);
break;
case 'checkbox':
$checked = $options['checked'];
unset($options['placeholder'], $options['autocomplete'], $options['class']);
$html .= '<div class="checkbox"><label>';
$html .= \Form::checkbox($name, $value, $checked, $options);
$html .= '</label></div>';
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 .= '<span class="glyphicon glyphicon-remove form-control-feedback"></span>';
$html .= '<p class="text-danger">' . e($errors->first($name)) . '</p>';
}
}
unset($errors);
/*
* If warnings, respond to them:
*/
if (!is_null($warnings)) {
if ($warnings->has($name)) {
$html .= '<span class="glyphicon glyphicon-warning-sign form-control-feedback"></span>';
$html .= '<p class="text-warning">' . e($warnings->first($name)) . '</p>';
}
}
unset($warnings);
/*
* If successes, respond to them:
*/
if (!is_null($successes)) {
if ($successes->has($name)) {
$html .= '<span class="glyphicon glyphicon-ok form-control-feedback"></span>';
$html .= '<p class="text-success">' . e($successes->first($name)) . '</p>';
}
}
unset($successes);
$html .= '</div>';
$html .= '</div>';
$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 = '<div class="form-group"><label for="' . $name . '_store" class="col-sm-4 control-label">Store</label>';
$store .= '<div class="col-sm-8"><div class="radio"><label>';
$store .= \Form::radio('post_submit_action', 'store', $previousValue == 'store', ['id' => $name . '_store']);
$store .= 'Store ' . $name . '</label></div></div></div>';
break;
case 'update':
$store = '<div class="form-group"><label for="' . $name . 'update" class="col-sm-4 control-label">Store</label>';
$store .= '<div class="col-sm-8"><div class="radio"><label>';
$store .= \Form::radio('post_submit_action', 'update', $previousValue == 'update' || $previousValue == 'store', ['id' => $name . '_update']);
$store .= 'Update ' . $name . '</label></div></div></div>';
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 = '<div class="form-group"><label for="' . $name . 'validate_only" class="col-sm-4 control-label">Validate only';
$validate .= '</label><div class="col-sm-8"><div class="radio"><label>';
$validate .= \Form::radio('post_submit_action', 'validate_only', $previousValue == 'validate_only', ['id' => $name . '_validate_only']);
$validate .= 'Only validate, do not save</label></div></div></div>';
/*
* Store & return:
*/
switch ($type) {
case 'create':
$return = '<div class="form-group"><label for="' . $name . 'return_to_form" class="col-sm-4 control-label">';
$return .= 'Return here</label><div class="col-sm-8"><div class="radio"><label>';
$return .= \Form::radio('post_submit_action', 'create_another', $previousValue == 'create_another', ['id' => $name . '_create_another']);
$return .= 'After storing, return here to create another one.</label></div></div></div>';
break;
case 'update':
$return = '<div class="form-group"><label for="' . $name . 'return_to_edit" class="col-sm-4 control-label">';
$return .= 'Return here</label><div class="col-sm-8"><div class="radio"><label>';
$return .= \Form::radio('post_submit_action', 'return_to_edit', $previousValue == 'return_to_edit', ['id' => $name . '_return_to_edit']);
$return .= 'After updating, return here.</label></div></div></div>';
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;
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace FireflyIII\Helper\Related;
use FireflyIII\Database\SwitchUser;
use Illuminate\Support\Collection;
/**
* Class Related
*
* @package FireflyIII\Helper\Related
*/
class Related implements RelatedInterface
{
use SwitchUser;
/**
*
*/
public function __construct()
{
$this->setUser(\Auth::user());
}
/**
* @param array $objectIds
*
* @return Collection
*/
public function getJournalsByIds(array $objectIds)
{
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */
$repository = \App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
return $repository->getByIds($objectIds);
}
/**
* @param string $query
* @param \TransactionJournal $journal
*
* @return Collection
*/
public function search($query, \TransactionJournal $journal)
{
$start = clone $journal->date;
$end = clone $journal->date;
$start->startOfMonth();
$end->endOfMonth();
// get already related transactions:
$exclude = [$journal->id];
foreach ($journal->transactiongroups()->get() as $group) {
foreach ($group->transactionjournals() as $current) {
$exclude[] = $current->id;
}
}
$exclude = array_unique($exclude);
/** @var Collection $collection */
$collection = $this->getUser()->transactionjournals()
->withRelevantData()
->before($end)
->where('encrypted', 0)
->after($start)
->whereNotIn('id', $exclude)
->where('description', 'LIKE', '%' . $query . '%')
->get();
// 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;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace FireflyIII\Helper\Related;
use Illuminate\Support\Collection;
/**
* Interface RelatedInterface
*
* @package FireflyIII\Helper\Related
*/
interface RelatedInterface
{
/**
* @param string $query
* @param \TransactionJournal $journal
*
* @return Collection
*/
public function search($query, \TransactionJournal $journal);
/**
* @param array $objectIds
*
* @return Collection
*/
public function getJournalsByIds(array $objectIds);
}

View File

@@ -0,0 +1,85 @@
<?php
namespace FireflyIII\Helper\TransactionJournal;
use Illuminate\Support\Collection;
/**
* Class Helper
*
* @package FireflyIII\Helper\TransactionJournal
*/
class Helper implements HelperInterface
{
/**
*
* Get the account_id, which is the asset account that paid for the transaction.
*
* @param string $what
* @param Collection $transactions
*
* @return mixed
*/
public function getAssetAccount($what, Collection $transactions)
{
if ($what == 'withdrawal') {
// transaction #1 is the one that paid for it.
return intval($transactions[1]->account->id);
}
// otherwise (its a deposit), it's been paid into account #0.
return intval($transactions[0]->account->id);
}
/**
* @return Collection
*/
public function getAssetAccounts()
{
/** @var \FireflyIII\Database\Account\Account $accountRepository */
$accountRepository = \App::make('FireflyIII\Database\Account\Account');
return $accountRepository->getAccountsByType(['Default account', 'Asset account']);
}
/**
* @return Collection
*/
public function getBudgets()
{
/** @var \FireflyIII\Database\Budget\Budget $budgetRepository */
$budgetRepository = \App::make('FireflyIII\Database\Budget\Budget');
return $budgetRepository->get();
}
/**
* @return Collection
*/
public function getPiggyBanks()
{
/** @var \FireflyIII\Database\PiggyBank\PiggyBank $piggyRepository */
$piggyRepository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank');
return $piggyRepository->get();
}
/**
* @return Collection
*/
public function getRepeatedExpenses()
{
/** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repRepository */
$repRepository = \App::make('FireflyIII\Database\PiggyBank\RepeatedExpense');
return $repRepository->get();
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace FireflyIII\Helper\TransactionJournal;
use Illuminate\Support\Collection;
/**
* Interface HelperInterface
*
* @package FireflyIII\Helper\TransactionJournal
*/
interface HelperInterface
{
/**
*
* Get the account_id, which is the asset account that paid for the transaction.
*
* @param string $what
* @param Collection $transactions
*
* @return int
*/
public function getAssetAccount($what, Collection $transactions);
/**
* @return Collection
*/
public function getAssetAccounts();
/**
* @return Collection
*/
public function getBudgets();
/**
* @return Collection
*/
public function getPiggyBanks();
/**
* @return Collection
*/
public function getRepeatedExpenses();
}

View File

@@ -5,13 +5,14 @@ namespace FireflyIII\Report;
use Carbon\Carbon;
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\Support\Collection;
// todo add methods to itnerface
/**
* Class Report
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class Report
*
* @package FireflyIII\Report
*/
@@ -22,17 +23,30 @@ class Report implements ReportInterface
/** @var AccountRepository */
protected $_accounts;
/** @var \FireflyIII\Report\ReportHelperInterface */
protected $_helper;
/** @var JournalRepository */
protected $_journals;
/** @var \FireflyIII\Report\ReportQueryInterface */
protected $_queries;
/**
* @param AccountRepository $accounts
* @param JournalRepository $journals
*/
public function __construct(AccountRepository $accounts)
public function __construct(AccountRepository $accounts, JournalRepository $journals)
{
$this->_accounts = $accounts;
$this->_journals = $journals;
$this->_queries = \App::make('FireflyIII\Report\ReportQueryInterface');
$this->_helper = \App::make('FireflyIII\Report\ReportHelperInterface');
}
/**
* This methods fails to take in account transfers FROM shared accounts.
*
* @param Carbon $start
* @param Carbon $end
* @param int $limit
@@ -41,36 +55,269 @@ class Report implements ReportInterface
*/
public function expensesGroupedByAccount(Carbon $start, Carbon $end, $limit = 15)
{
return \TransactionJournal::
leftJoin(
'transactions as t_from', function ($join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
$result = $this->_queries->journalsByExpenseAccount($start, $end);
$array = $this->_helper->makeArray($result);
$limited = $this->_helper->limitArray($array, $limit);
return $limited;
}
/**
* Gets all the users shared and non-shared accounts combined with various meta-data
* to display the amount of money spent that month compared to what's been spend within
* budgets.
*
* @param Carbon $date
*
* @return Collection
*/
public function getAccountListBudgetOverview(Carbon $date)
{
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
$start->subDay();
$accounts = $this->_queries->getAllAccounts($start, $end);
$accounts->each(
function (\Account $account) use ($start, $end) {
$budgets = $this->_queries->getBudgetSummary($account, $start, $end);
$balancedAmount = $this->_queries->balancedTransactionsSum($account, $start, $end);
$array = [];
foreach ($budgets as $budget) {
$id = intval($budget->id);
$data = $budget->toArray();
$array[$id] = $data;
}
$account->budgetInformation = $array;
$account->balancedAmount = $balancedAmount;
}
);
return $accounts;
}
/**
* @param Carbon $date
*
* @return array
*/
public function getAccountsForMonth(Carbon $date)
{
$start = clone $date;
$start->startOfMonth()->subDay();
$end = clone $date;
$end->endOfMonth();
\Log::debug('Monthly report account dates: start:[' . $start->format('Y-m-d') . '] and end:[' . $end->format('Y-m-d') . ']');
$list = $this->_queries->accountList();
$accounts = [];
/** @var \Account $account */
foreach ($list as $account) {
$id = intval($account->id);
/** @noinspection PhpParamsInspection */
$accounts[$id] = [
'name' => $account->name,
'startBalance' => \Steam::balance($account, $start),
'endBalance' => \Steam::balance($account, $end)
];
$accounts[$id]['difference'] = $accounts[$id]['endBalance'] - $accounts[$id]['startBalance'];
}
return $accounts;
}
/**
* @param Carbon $date
*
* @return Collection
*/
public function getBudgetsForMonth(Carbon $date)
{
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
// all budgets
$set = $this->_queries->getAllBudgets($date);
$budgets = $this->_helper->makeArray($set);
$amountSet = $this->_queries->journalsByBudget($start, $end);
$amounts = $this->_helper->makeArray($amountSet);
$combined = $this->_helper->mergeArrays($budgets, $amounts);
$combined[0]['spent'] = isset($combined[0]['spent']) ? $combined[0]['spent'] : 0.0;
$combined[0]['amount'] = isset($combined[0]['amount']) ? $combined[0]['amount'] : 0.0;
$combined[0]['name'] = 'No budget';
// find transactions to shared expense accounts, which are without a budget by default:
$transfers = $this->_queries->sharedExpenses($start, $end);
foreach ($transfers as $transfer) {
$combined[0]['spent'] += floatval($transfer->amount) * -1;
}
return $combined;
}
/**
* @param Carbon $date
* @param int $limit
*
* @return array
*/
public function getCategoriesForMonth(Carbon $date, $limit = 15)
{
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
// all categories.
$result = $this->_queries->journalsByCategory($start, $end);
$categories = $this->_helper->makeArray($result);
// all transfers
$result = $this->_queries->sharedExpensesByCategory($start, $end);
$transfers = $this->_helper->makeArray($result);
$merged = $this->_helper->mergeArrays($categories, $transfers);
// sort.
$sorted = $this->_helper->sortNegativeArray($merged);
// limit to $limit:
$cut = $this->_helper->limitArray($sorted, $limit);
return $cut;
}
/**
* @param Carbon $date
* @param int $limit
*
* @return Collection
*/
public function getExpenseGroupedForMonth(Carbon $date, $limit = 15)
{
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
$set = $this->_queries->journalsByExpenseAccount($start, $end);
$expenses = $this->_helper->makeArray($set);
// $alt = $this->_queries->sharedExpenses($start, $end);
// $transfers = $this->_helper->makeArray($alt);
//
// $expenses[-1] = [
// 'amount' => 0,
// 'name' => 'Transfers to shared',
// 'spent' => 0
// ];
//
// foreach ($transfers as $transfer) {
// $expenses[-1]['amount'] += $transfer['amount'];
// }
$expenses = $this->_helper->sortArray($expenses);
$limited = $this->_helper->limitArray($expenses, $limit);
return $limited;
}
/**
* This method gets all incomes (journals) in a list.
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param Carbon $date
* @param bool $shared
*
* @return Collection
*/
public function getIncomeForMonth(Carbon $date, $shared = false)
{
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
$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.*']);
//
// // 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;
}
/**
* @param Carbon $date
*
* @return Collection
*/
public function getPiggyBanksForMonth(Carbon $date)
{
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
\PiggyBank::
leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')
->where('accounts.user_id', \Auth::user()->id)
->where('repeats', 0)
->where(
function (Builder $query) use ($start, $end) {
$query->whereNull('piggy_banks.deleted_at');
$query->orWhere(
function (Builder $query) use ($start, $end) {
$query->whereNotNull('piggy_banks.deleted_at');
$query->where('piggy_banks.deleted_at', '>=', $start->format('Y-m-d 00:00:00'));
$query->where('piggy_banks.deleted_at', '<=', $end->format('Y-m-d 00:00:00'));
}
);
}
)
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin(
'account_meta as acm_from', function ($join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function ($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 ($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('transaction_types.type', 'Withdrawal')
->where('acm_from.data', '!=', '"sharedExpense"')
->before($end)->after($start)
->where('transaction_journals.user_id', \Auth::user()->id)
->groupBy('account_id')->orderBy('sum', 'DESC')->limit(15)
->get(['t_to.account_id as account_id', 'ac_to.name as name', \DB::Raw('SUM(t_to.amount) as `sum`')]);
->get(['piggy_banks.*']);
}
@@ -114,6 +361,7 @@ class Report implements ReportInterface
}
/**
*
* @param Carbon $start
* @param Carbon $end
* @param int $limit
@@ -122,36 +370,7 @@ class Report implements ReportInterface
*/
public function revenueGroupedByAccount(Carbon $start, Carbon $end, $limit = 15)
{
return \TransactionJournal::
leftJoin(
'transactions as t_from', function ($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 ($join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function ($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 ($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('transaction_types.type', 'Deposit')
->where('acm_to.data', '!=', '"sharedExpense"')
->before($end)->after($start)
->where('transaction_journals.user_id', \Auth::user()->id)
->groupBy('account_id')->orderBy('sum')->limit(15)
->get(['t_from.account_id as account_id', 'ac_from.name as name', \DB::Raw('SUM(t_from.amount) as `sum`')]);
return $this->_queries->journalsByRevenueAccount($start, $end, $limit);
}
@@ -176,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;
@@ -186,7 +405,7 @@ class Report implements ReportInterface
}
);
$report = [];
$start->startOfYear();
$start->startOfYear()->subDay();
$end->endOfYear();
foreach ($accounts as $account) {

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