mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-31 10:47:00 +00:00 
			
		
		
		
	Compare commits
	
		
			160 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 42458ce11d | ||
|  | aceb683d07 | ||
|  | b7517b49ed | ||
|  | 849b711b79 | ||
|  | 25585b28c7 | ||
|  | 073da8fb2a | ||
|  | a787ff3f3c | ||
|  | 733b6d7eb7 | ||
|  | 36d8dee853 | ||
|  | 65a2e07d24 | ||
|  | 7c97c558ab | ||
|  | a6bb61050c | ||
|  | b184aa2315 | ||
|  | e4595333e7 | ||
|  | 41dd139bde | ||
|  | c577dd302a | ||
|  | 0ab87de78b | ||
|  | 8a22509b41 | ||
|  | b024c18441 | ||
|  | d9ac681a68 | ||
|  | 637a5579ec | ||
|  | 4794156e80 | ||
|  | 5f4db7874c | ||
|  | b4ea1839a5 | ||
|  | 6a6d889983 | ||
|  | 287c2e7af8 | ||
|  | 0fe6acc8cf | ||
|  | 7d2dab7ca0 | ||
|  | f68c1aff26 | ||
|  | 81662473a6 | ||
|  | d40645be68 | ||
|  | a53550537f | ||
|  | 223ad16616 | ||
|  | 3f060979d7 | ||
|  | 2eac9081ea | ||
|  | b3eef4f40b | ||
|  | dd70fbad3f | ||
|  | 8cb7a1aef8 | ||
|  | a687140056 | ||
|  | 3cba673a9c | ||
|  | 01de230785 | ||
|  | e405d06f23 | ||
|  | d9b70f7ad8 | ||
|  | 0ef5825d98 | ||
|  | 1e76a5fc3f | ||
|  | 1fbdb3d0ae | ||
|  | d5bcf5497f | ||
|  | 28aaea1aa3 | ||
|  | 980d9ce885 | ||
|  | ec601efa6e | ||
|  | b3209d3b4d | ||
|  | 4ce978b9f3 | ||
|  | a84064663a | ||
|  | 6798cea268 | ||
|  | 8e86196352 | ||
|  | 1b3d345fbd | ||
|  | 7d2627515f | ||
|  | aa9eb8ca64 | ||
|  | 9015d6ca16 | ||
|  | 217483639d | ||
|  | 78e80530d3 | ||
|  | 3bbecfe830 | ||
|  | 9ab3679d49 | ||
|  | fc44a52ba5 | ||
|  | bb2b71bdc0 | ||
|  | b23d2a9d95 | ||
|  | eeb773fd7b | ||
|  | 53a582f374 | ||
|  | 73110f6a51 | ||
|  | 5667663fef | ||
|  | fb664ba17d | ||
|  | 0c10190a8e | ||
|  | 183a323ef6 | ||
|  | 90bada5497 | ||
|  | 7c043e1923 | ||
|  | 2720ae3c46 | ||
|  | 401508577e | ||
|  | b0a31cebc2 | ||
|  | 95adb428fa | ||
|  | f92a0310dd | ||
|  | 84f0cb3765 | ||
|  | d49e6787d6 | ||
|  | 0884853a6f | ||
|  | 1967c63006 | ||
|  | 9461e7b70a | ||
|  | f1e5df566c | ||
|  | fb02a0d5ad | ||
|  | e438a02fa3 | ||
|  | b112452aa1 | ||
|  | 1a2fc81af3 | ||
|  | 38bbda982c | ||
|  | 41ad6e64d1 | ||
|  | efcad0b935 | ||
|  | e892b69a96 | ||
|  | 5dfc04e777 | ||
|  | c119a42d70 | ||
|  | 802541b796 | ||
|  | 0770c79777 | ||
|  | 5f4669341e | ||
|  | f15fc80233 | ||
|  | a7d75ea94a | ||
|  | ba4bddf756 | ||
|  | 6a26408552 | ||
|  | c39c59fff5 | ||
|  | c1ba8dc6a7 | ||
|  | f2825da878 | ||
|  | c61f1307d8 | ||
|  | 9e88d7a60d | ||
|  | 406ae25162 | ||
|  | dbfb342021 | ||
|  | 4632142e06 | ||
|  | 9ae036f297 | ||
|  | 497b8c48c8 | ||
|  | 5d11949313 | ||
|  | a91c9f04c5 | ||
|  | 4f3493f9ff | ||
|  | 49b8742082 | ||
|  | 69cee59e23 | ||
|  | 19402b9022 | ||
|  | 62ba40b687 | ||
|  | f9af9a4fbe | ||
|  | c2ab43d0ab | ||
|  | af28e6e7b9 | ||
|  | 114ad7f292 | ||
|  | 44eb67f94e | ||
|  | 0203fee174 | ||
|  | a1ba340ead | ||
|  | 0ae9ff4575 | ||
|  | 5b501cb942 | ||
|  | 0255b7a4a0 | ||
|  | 15ef0bab1d | ||
|  | decad6830b | ||
|  | b6e0b985c2 | ||
|  | c140f71878 | ||
|  | 87044e6b8e | ||
|  | affa9014d2 | ||
|  | 4bbc3c3bd8 | ||
|  | d296dbbc23 | ||
|  | 9bcd27b847 | ||
|  | 2a54b36db0 | ||
|  | 77fb02daa4 | ||
|  | 1963ac191f | ||
|  | 33da8aa987 | ||
|  | 0192484044 | ||
|  | 3c0863d8ea | ||
|  | 710d6dfb74 | ||
|  | 2359542d72 | ||
|  | e2227271b5 | ||
|  | 7a639a1d6e | ||
|  | 9edb9b91b2 | ||
|  | b2adeb20d9 | ||
|  | fa665de847 | ||
|  | ab9e5f716d | ||
|  | 5788db9f07 | ||
|  | 3068a8d58d | ||
|  | 14aacf42b9 | ||
|  | d1b97da309 | ||
|  | 867074e7b2 | ||
|  | 18748510b1 | ||
|  | bcf71cdf85 | 
| @@ -1 +0,0 @@ | ||||
| If you place an image here called foobar.png then you can access that image by going to http://<hostname>/assets/foobar.png | ||||
| @@ -1,16 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require highslide/highslide-full.min | ||||
| //= require highslide/highslide.config | ||||
| //= require_tree highcharts | ||||
| //= require firefly/accounts | ||||
| @@ -1,15 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require jquery | ||||
| //= require bootstrap/bootstrap.min | ||||
| //= require firefly/reminders | ||||
| @@ -1,14 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require_tree highcharts | ||||
| //= require firefly/budgets/default | ||||
| @@ -1,14 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require_tree highcharts | ||||
| //= require firefly/budgets/limit | ||||
| @@ -1,14 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require_tree highcharts | ||||
| //= require firefly/budgets/nolimit | ||||
| @@ -1,14 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require_tree highcharts | ||||
| //= require firefly/budgets/session | ||||
| @@ -1,14 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require_tree highcharts | ||||
| //= require firefly/budgets | ||||
| @@ -1,14 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require_tree highcharts | ||||
| //= require firefly/categories | ||||
| @@ -1,95 +0,0 @@ | ||||
| $(function () { | ||||
| if($('#chart').length == 1) { | ||||
|     /** | ||||
|      * get data from controller for home charts: | ||||
|      */ | ||||
|     $.getJSON('chart/home/account/' + accountID).success(function (data) { | ||||
|         var options = { | ||||
|             chart: { | ||||
|                 renderTo: 'chart', | ||||
|                 type: 'spline' | ||||
|             }, | ||||
|  | ||||
|             series: data.series, | ||||
|             title: { | ||||
|                 text: data.chart_title | ||||
|             }, | ||||
|             yAxis: { | ||||
|                 formatter: function () { | ||||
|                     return '$' + Highcharts.numberFormat(this.y, 0); | ||||
|                 } | ||||
|             }, | ||||
|             subtitle: { | ||||
|                 text: data.subtitle, | ||||
|                 useHTML: true | ||||
|             }, | ||||
|  | ||||
|             xAxis: { | ||||
|                 floor: 0, | ||||
|                 type: 'datetime', | ||||
|                 dateTimeLabelFormats: { | ||||
|                     day: '%e %b', | ||||
|                     year: '%b' | ||||
|                 }, | ||||
|                 title: { | ||||
|                     text: 'Date' | ||||
|                 } | ||||
|             }, | ||||
|             tooltip: { | ||||
|                 shared: true, | ||||
|                 crosshairs: false, | ||||
|                 formatter: function () { | ||||
|                     var str = '<span style="font-size:80%;">' + Highcharts.dateFormat("%A, %e %B", this.x) + '</span><br />'; | ||||
|                     for (x in this.points) { | ||||
|                         var point = this.points[x]; | ||||
|                         var colour = point.point.pointAttr[''].fill; | ||||
|                         str += '<span style="color:' + colour + '">' + point.series.name + '</span>: € ' + Highcharts.numberFormat(point.y, 2) + '<br />'; | ||||
|                     } | ||||
|                     //console.log(); | ||||
|                     return str; | ||||
|                     return '<span style="font-size:80%;">' + this.series.name + ' on ' + Highcharts.dateFormat("%e %B", this.x) + ':</span><br /> € ' + Highcharts.numberFormat(this.y, 2); | ||||
|                 } | ||||
|             }, | ||||
|             plotOptions: { | ||||
|                 line: { | ||||
|                     shadow: true | ||||
|                 }, | ||||
|                 series: { | ||||
|                     cursor: 'pointer', | ||||
|                     negativeColor: '#FF0000', | ||||
|                     threshold: 0, | ||||
|                     lineWidth: 1, | ||||
|                     marker: { | ||||
|                         radius: 2 | ||||
|                     }, | ||||
|                     point: { | ||||
|                         events: { | ||||
|                             click: function (e) { | ||||
|                                 hs.htmlExpand(null, { | ||||
|                                         src: 'chart/home/info/' + this.series.name + '/' + Highcharts.dateFormat("%d/%m/%Y", this.x), | ||||
|                                         pageOrigin: { | ||||
|                                             x: e.pageX, | ||||
|                                             y: e.pageY | ||||
|                                         }, | ||||
|                                         objectType: 'ajax', | ||||
|                                         headingText: '<a href="#">' + this.series.name + '</a>', | ||||
|                                         width: 250 | ||||
|                                     } | ||||
|                                 ) | ||||
|                                 ; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             }, | ||||
|             credits: { | ||||
|                 enabled: false | ||||
|             } | ||||
|         }; | ||||
|         $('#chart').highcharts(options); | ||||
|     }); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| }); | ||||
| @@ -1,4 +0,0 @@ | ||||
| $(function () { | ||||
|  | ||||
|  | ||||
| }); | ||||
| @@ -1,7 +0,0 @@ | ||||
| $.getJSON('json/beneficiaries').success(function (data) { | ||||
|     $('input[name="beneficiary"]').typeahead({ source: data }); | ||||
| }); | ||||
|  | ||||
| $.getJSON('json/categories').success(function (data) { | ||||
|     $('input[name="category"]').typeahead({ source: data }); | ||||
| }); | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -1,12 +0,0 @@ | ||||
| /** | ||||
| *	Site-specific configuration settings for Highslide JS | ||||
| */ | ||||
| hs.graphicsDir = 'assets/highslide/'; | ||||
| hs.outlineType = 'rounded-white'; | ||||
| hs.wrapperClassName = 'draggable-header'; | ||||
| hs.captionEval = 'this.a.title'; | ||||
| hs.showCredits = false; | ||||
| hs.marginTop = 20; | ||||
| hs.marginRight = 20; | ||||
| hs.marginBottom = 20; | ||||
| hs.marginLeft = 20; | ||||
| @@ -1,16 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require highslide/highslide-full.min | ||||
| //= require highslide/highslide.config | ||||
| //= require_tree highcharts | ||||
| //= require firefly/index | ||||
| @@ -1,13 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require firefly/piggybanks-create | ||||
| @@ -1,13 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require firefly/piggybanks | ||||
| @@ -1,14 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require tagsinput/bootstrap-tagsinput.min | ||||
| //= require firefly/recurring | ||||
| @@ -1,14 +0,0 @@ | ||||
| // This is a manifest file that'll be compiled into application.js, which will include all the files | ||||
| // listed below. | ||||
| // | ||||
| // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
| // can be referenced here using a relative path. | ||||
| // | ||||
| // It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
| // gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
| // but before any files alphabetically greater than 'application.js'  | ||||
| // | ||||
| // The available directives right now are require, require_directory, and require_tree | ||||
| // | ||||
| //= require typeahead/bootstrap3-typeahead.min | ||||
| //= require firefly/transactions | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,13 +0,0 @@ | ||||
| /** | ||||
|  * This is a manifest file that'll be compiled into application.css, which will include all the files | ||||
|  * listed below. | ||||
|  * | ||||
|  * Any Css/Less files within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
|  * can be referenced here using a relative path. | ||||
|  * | ||||
|  * It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
|  * gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
|  * but before any files alphabetically greater than 'application.css'  | ||||
|  * | ||||
|  *= require highslide/highslide | ||||
|  */ | ||||
| @@ -1,13 +0,0 @@ | ||||
| /** | ||||
|  * This is a manifest file that'll be compiled into application.css, which will include all the files | ||||
|  * listed below. | ||||
|  * | ||||
|  * Any Css/Less files within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
|  * can be referenced here using a relative path. | ||||
|  * | ||||
|  * It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
|  * gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
|  * but before any files alphabetically greater than 'application.css'  | ||||
|  * | ||||
|  *= require bootstrap/bootstrap.min | ||||
|  */ | ||||
| @@ -1,13 +0,0 @@ | ||||
| /** | ||||
|  * This is a manifest file that'll be compiled into application.css, which will include all the files | ||||
|  * listed below. | ||||
|  * | ||||
|  * Any Css/Less files within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
|  * can be referenced here using a relative path. | ||||
|  * | ||||
|  * It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
|  * gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
|  * but before any files alphabetically greater than 'application.css'  | ||||
|  * | ||||
|  *= require highslide/highslide | ||||
|  */ | ||||
| @@ -1,13 +0,0 @@ | ||||
| /** | ||||
|  * This is a manifest file that'll be compiled into application.css, which will include all the files | ||||
|  * listed below. | ||||
|  * | ||||
|  * Any Css/Less files within this directory, lib/assets/javascripts, vendor/assets/javascripts, | ||||
|  * can be referenced here using a relative path. | ||||
|  * | ||||
|  * It's not advisable to add code directly here, but if you do, it'll appear in whatever order it  | ||||
|  * gets included (e.g. say you have require_tree . then the code will appear after all the directories  | ||||
|  * but before any files alphabetically greater than 'application.css'  | ||||
|  * | ||||
|  *= require tagsinput/bootstrap-tagsinput | ||||
|  */ | ||||
							
								
								
									
										7
									
								
								app/breadcrumbs.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/breadcrumbs.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| <?php | ||||
| /* | ||||
|  * Back home. | ||||
|  */ | ||||
| Breadcrumbs::register('home', function($breadcrumbs) { | ||||
|     $breadcrumbs->push('Home', route('index')); | ||||
| }); | ||||
| @@ -6,6 +6,7 @@ return [ | ||||
|     'timezone'        => 'UTC', | ||||
|     'locale'          => 'en', | ||||
|     'fallback_locale' => 'en', | ||||
|     'log_level'       => 'notice', | ||||
|     'key'             => 'D93oqmVsIARg23FC3cbsHuBGk0uXQc3r', | ||||
|     'cipher'          => MCRYPT_RIJNDAEL_128, | ||||
|     'providers'       => [ | ||||
| @@ -36,12 +37,13 @@ return [ | ||||
|         'Illuminate\Validation\ValidationServiceProvider', | ||||
|         'Illuminate\View\ViewServiceProvider', | ||||
|         'Illuminate\Workbench\WorkbenchServiceProvider', | ||||
| #        'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider', | ||||
| #        'Barryvdh\Debugbar\ServiceProvider', | ||||
|         'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider', | ||||
|         'Barryvdh\Debugbar\ServiceProvider', | ||||
|         'Firefly\Storage\StorageServiceProvider', | ||||
|         'Firefly\Helper\HelperServiceProvider', | ||||
|         'Firefly\Validation\ValidationServiceProvider', | ||||
|         'Codesleeve\AssetPipeline\AssetPipelineServiceProvider', | ||||
|         'DaveJamesMiller\Breadcrumbs\ServiceProvider', | ||||
|         'TwigBridge\ServiceProvider' | ||||
|     ], | ||||
|     'manifest'        => storage_path() . '/meta', | ||||
|     'aliases'         => [ | ||||
| @@ -84,6 +86,8 @@ return [ | ||||
|         'URL'               => 'Illuminate\Support\Facades\URL', | ||||
|         'Validator'         => 'Illuminate\Support\Facades\Validator', | ||||
|         'View'              => 'Illuminate\Support\Facades\View', | ||||
|         'Breadcrumbs'       => 'DaveJamesMiller\Breadcrumbs\Facade', | ||||
|         'Twig'              => 'TwigBridge\Facade\Twig', | ||||
|  | ||||
|     ], | ||||
|  | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| use Carbon\Carbon; | ||||
|  | ||||
| return [ | ||||
|     'index_periods'          => ['1D', '1W', '1M', '3M', '6M', 'custom'], | ||||
|     'index_periods'          => ['1D', '1W', '1M', '3M', '6M','1Y', 'custom'], | ||||
|     'budget_periods'         => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'], | ||||
|     'piggybank_periods'      => ['day', 'week', 'month', 'year'], | ||||
|     'periods_to_text'        => [ | ||||
| @@ -21,6 +21,14 @@ return [ | ||||
|         '6M'     => 'half year', | ||||
|         'custom' => '(custom)' | ||||
|     ], | ||||
|     'range_to_name'          => [ | ||||
|         '1D'     => 'one day', | ||||
|         '1W'     => 'one week', | ||||
|         '1M'     => 'one month', | ||||
|         '3M'     => 'three months', | ||||
|         '6M'     => 'six months', | ||||
|         '1Y'     => 'one year', | ||||
|     ], | ||||
|     'range_to_repeat_freq'   => [ | ||||
|         '1D'     => 'weekly', | ||||
|         '1W'     => 'weekly', | ||||
|   | ||||
| @@ -1,331 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
| |-------------------------------------------------------------------------- | ||||
| | EnvironmentFilter | ||||
| |-------------------------------------------------------------------------- | ||||
| | | ||||
| | This is used to run filters on specific environments. For example, if you | ||||
| | only want to run a filter on production and staging environments | ||||
| | | ||||
| | new EnvironmentFilter(new FilterExample, App::environment(), ['production', 'staging')), | ||||
| | | ||||
| */ | ||||
| use Codesleeve\AssetPipeline\Filters\EnvironmentFilter; | ||||
|  | ||||
| return [ | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| routing array | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| This is passed to the Route::group and allows us to group and filter the | ||||
| 	| routes for our package | ||||
| 	| | ||||
| 	*/ | ||||
| 	'routing' => [ | ||||
| 		'prefix' => '/assets' | ||||
|     ], | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| paths | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| These are the directories we search for files in. | ||||
| 	| | ||||
| 	| NOTE that the '.' in require_tree . is relative to where the manifest file | ||||
| 	| (i.e. app/assets/javascripts/application.js) is located | ||||
| 	| | ||||
| 	*/ | ||||
| 	'paths' => [ | ||||
| 		'app/assets/javascripts', | ||||
| 		'app/assets/stylesheets', | ||||
| 		'app/assets/images', | ||||
| 		'lib/assets/javascripts', | ||||
| 		'lib/assets/stylesheets', | ||||
| 		'lib/assets/images', | ||||
| 		'provider/assets/javascripts', | ||||
| 		'provider/assets/stylesheets', | ||||
| 		'provider/assets/images' | ||||
|     ], | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| mimes | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| In order to know which mime type to send back to the server | ||||
| 	| we need to know if it is a javascript or stylesheet type. If | ||||
| 	| the extension is not found below then we just return a regular | ||||
| 	| download. | ||||
| 	| | ||||
| 	*/ | ||||
| 	'mimes' => [ | ||||
| 	    'javascripts' => ['.js', '.js.coffee', '.coffee', '.html', '.min.js'], | ||||
| 	    'stylesheets' => ['.css', '.css.less', '.css.sass', '.css.scss', '.less', '.sass', '.scss', '.min.css'], | ||||
|     ], | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| filters | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| In order for a file to be included with sprockets, it needs to be listed | ||||
| 	| here and we can also do any preprocessing on files with the extension if | ||||
| 	| we choose to. | ||||
| 	| | ||||
| 	*/ | ||||
| 	'filters' => [ | ||||
| 		'.min.js' => [ | ||||
|  | ||||
| 		], | ||||
| 		'.min.css' => [ | ||||
| 			new Codesleeve\AssetPipeline\Filters\URLRewrite(App::make('url')->to('/')), | ||||
| 		], | ||||
| 		'.js' => [ | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\JSMinPlusFilter, App::environment()), | ||||
| 		], | ||||
| 		'.js.coffee' => [ | ||||
| 			new Codesleeve\AssetPipeline\Filters\CoffeeScript, | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\JSMinPlusFilter, App::environment()), | ||||
| 		], | ||||
| 		'.coffee' => [ | ||||
| 			new Codesleeve\AssetPipeline\Filters\CoffeeScript, | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\JSMinPlusFilter, App::environment()), | ||||
| 		], | ||||
| 		'.css' => [ | ||||
| 			new Codesleeve\AssetPipeline\Filters\URLRewrite(App::make('url')->to('/')), | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\CssMinFilter, App::environment()), | ||||
|         ], | ||||
| 		'.css.less' => [ | ||||
| 			new Codesleeve\AssetPipeline\Filters\LessphpFilter, | ||||
| 			new Codesleeve\AssetPipeline\Filters\URLRewrite(App::make('url')->to('/')), | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\CssMinFilter, App::environment()), | ||||
|         ], | ||||
| 		'.css.sass' => [ | ||||
| 			new Codesleeve\AssetPipeline\Filters\SassFilter, | ||||
| 			new Codesleeve\AssetPipeline\Filters\URLRewrite(App::make('url')->to('/')), | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\CssMinFilter, App::environment()), | ||||
|         ], | ||||
| 		'.css.scss' => [ | ||||
| 			new Assetic\Filter\ScssphpFilter, | ||||
| 			new Codesleeve\AssetPipeline\Filters\URLRewrite(App::make('url')->to('/')), | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\CssMinFilter, App::environment()), | ||||
|         ], | ||||
| 		'.less' => [ | ||||
| 			new Codesleeve\AssetPipeline\Filters\LessphpFilter, | ||||
| 			new Codesleeve\AssetPipeline\Filters\URLRewrite(App::make('url')->to('/')), | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\CssMinFilter, App::environment()), | ||||
|         ], | ||||
| 		'.sass' => [ | ||||
| 			new Codesleeve\AssetPipeline\Filters\SassFilter, | ||||
| 			new Codesleeve\AssetPipeline\Filters\URLRewrite(App::make('url')->to('/')), | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\CssMinFilter, App::environment()), | ||||
|         ], | ||||
| 		'.scss' => [ | ||||
| 			new Assetic\Filter\ScssphpFilter, | ||||
| 			new Codesleeve\AssetPipeline\Filters\URLRewrite(App::make('url')->to('/')), | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\CssMinFilter, App::environment()), | ||||
|         ], | ||||
| 		'.html' => [ | ||||
| 			new Codesleeve\AssetPipeline\Filters\JST, | ||||
| 			new EnvironmentFilter(new Codesleeve\AssetPipeline\Filters\JSMinPlusFilter, App::environment()), | ||||
|         ] | ||||
|     ], | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| cache | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| By default we cache assets on production environment permanently. We also cache | ||||
| 	| all files using the `cache_server` driver below but the cache is busted anytime | ||||
| 	| those files are modified. On production we will cache and the only way to bust | ||||
| 	| the cache is to delete files from app/storage/cache/asset-pipeline or run a | ||||
| 	| command php artisan assets:clean -f somefilename.js -f application.css ... | ||||
| 	| | ||||
| 	*/ | ||||
| 	'cache' => 	['production'], | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| cache_server | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| You can create your own CacheInterface if the filesystem cache is not up to | ||||
| 	| your standards. This is for caching asset files on the server-side. | ||||
| 	| | ||||
| 	| Please note that caching is used on **ALL** environments always. This is done | ||||
| 	| to increase performance of the pipeline. Cached files will be busted when the | ||||
| 	| file changes. | ||||
| 	| | ||||
| 	| However, manifest files are regenerated (not cached) when the environment is | ||||
| 	| not found within the 'cache' array. This lets you develop on local and still | ||||
| 	| utilize caching, so you don't have to regenerate all precompiled files while | ||||
| 	| developing on your assets. | ||||
| 	| | ||||
| 	| See more in CacheInterface.php at | ||||
| 	| | ||||
| 	|    https://github.com/kriswallsmith/assetic/blob/master/src/Assetic/Cache | ||||
| 	| | ||||
| 	| | ||||
| 	*/ | ||||
| 	'cache_server' => new Assetic\Cache\FilesystemCache(App::make('path.storage') . '/cache/asset-pipeline'), | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| cache_client | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| If you want to handle 304's and what not, to keep users from refetching | ||||
| 	| your assets and saving your bandwidth you can use a cache_client driver | ||||
| 	| that handles this. This doesn't handle assets on the server-side, use | ||||
| 	| cache_server for that. This only works when the current environment is | ||||
| 	| listed within `cache` | ||||
| 	| | ||||
| 	| Note that this needs to implement the interface | ||||
| 	| | ||||
| 	|	Codesleeve\Sprockets\Interfaces\ClientCacheInterface | ||||
| 	| | ||||
| 	| or this won't work correctly. It is a wrapper class around your cache_server | ||||
| 	| driver and also uses the AssetCache class to help access files. | ||||
| 	| | ||||
| 	*/ | ||||
| 	'cache_client' => new Codesleeve\AssetPipeline\Filters\ClientCacheFilter, | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| concat | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| This allows us to turn on the asset concatenation for specific | ||||
| 	| environments listed below. You can turn off local environment if | ||||
| 	| you are trying to troubleshoot, but you will likely have better | ||||
| 	| performance if you leave concat on (except if you are doing a lot | ||||
| 	| of minification stuff on each page refresh) | ||||
| 	| | ||||
| 	*/ | ||||
| 	'concat' => ['production', 'local'], | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| directives | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| This allows us to turn completely control which directives are used | ||||
| 	| for the sprockets parser that asset pipeline uses to parse manifest files. | ||||
| 	| | ||||
| 	| It is probably safe just to leave this alone unless you are familar with | ||||
| 	| what is actually going on here. | ||||
| 	| | ||||
| 	*/ | ||||
| 	'directives' => [ | ||||
| 		'require ' => new Codesleeve\Sprockets\Directives\RequireFile, | ||||
| 		'require_directory ' => new Codesleeve\Sprockets\Directives\RequireDirectory, | ||||
| 		'require_tree ' => new Codesleeve\Sprockets\Directives\RequireTree, | ||||
| 		'require_tree_df ' => new Codesleeve\Sprockets\Directives\RequireTreeDf, | ||||
| 		'require_self' => new Codesleeve\Sprockets\Directives\RequireSelf, | ||||
| 		'include ' => new Codesleeve\Sprockets\Directives\IncludeFile, | ||||
| 		'include_directory ' => new Codesleeve\Sprockets\Directives\IncludeDirectory, | ||||
| 		'include_tree ' => new Codesleeve\Sprockets\Directives\IncludeTree, | ||||
| 		'stub ' => new Codesleeve\Sprockets\Directives\Stub, | ||||
| 		'depend_on ' => new Codesleeve\Sprockets\Directives\DependOn, | ||||
|     ], | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| javascript_include_tag | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| This allows us to completely control how the javascript_include_tag function | ||||
| 	| works for asset pipeline. | ||||
| 	| | ||||
| 	| It is probably safe just to leave this alone unless you are familar with | ||||
| 	| what is actually going on here. | ||||
| 	| | ||||
| 	*/ | ||||
| 	'javascript_include_tag' => new Codesleeve\AssetPipeline\Composers\JavascriptComposer, | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| stylesheet_link_tag | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| This allows us to completely control how the stylesheet_link_tag function | ||||
| 	| works for asset pipeline. | ||||
| 	| | ||||
| 	| It is probably safe just to leave this alone unless you are familar with | ||||
| 	| what is actually going on here. | ||||
| 	| | ||||
| 	*/ | ||||
| 	'stylesheet_link_tag' => new Codesleeve\AssetPipeline\Composers\StylesheetComposer, | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| image_tag | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| This allows us to completely control how the image_tag function | ||||
| 	| works for asset pipeline. | ||||
| 	| | ||||
| 	| It is probably safe just to leave this alone unless you are familar with | ||||
| 	| what is actually going on here. | ||||
| 	| | ||||
| 	*/ | ||||
| 	'image_tag' => new Codesleeve\AssetPipeline\Composers\ImageComposer, | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| controller_action | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| Asset pipeline will route all requests through the controller action | ||||
| 	| listed here. This allows us to completely control how the controller | ||||
| 	| should behave for incoming requests for assets. | ||||
| 	| | ||||
| 	| It is probably safe just to leave this alone unless you are familar with | ||||
| 	| what is actually going on here. | ||||
| 	| | ||||
| 	*/ | ||||
| 	'controller_action' => '\Codesleeve\AssetPipeline\AssetPipelineController@file', | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| sprockets_filter | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| When concatenation is turned on, when an asset is fetched from the sprockets | ||||
| 	| generator it is filtered through this filter class named below. This allows us | ||||
| 	| to modify the sprockets filter if we need to behave differently. | ||||
| 	| | ||||
| 	| It is probably safe just to leave this alone unless you are familar with | ||||
| 	| what is actually going on here. | ||||
| 	| | ||||
| 	*/ | ||||
| 	'sprockets_filter' => '\Codesleeve\Sprockets\SprocketsFilter', | ||||
|  | ||||
| 	/* | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| sprockets_filter | ||||
| 	|-------------------------------------------------------------------------- | ||||
| 	| | ||||
| 	| When concatenation is turned on, assets are filtered via SprocketsFilter | ||||
| 	| and we can do global filters on the resulting dump file. This would be | ||||
| 	| useful if you wanted to apply a filter to all javascript or stylesheet files | ||||
| 	| like minification. Out of the box we don't have any filters here. Add at | ||||
| 	| your own risk. I don't put minification filters here because the minify | ||||
| 	| doesn't always work perfectly and can bjork your entire concatenated | ||||
| 	| javascript or stylesheet file if it messes up. | ||||
| 	| | ||||
| 	| It is probably safe just to leave this alone unless you are familar with | ||||
| 	| what is actually going on here. | ||||
| 	| | ||||
| 	*/ | ||||
| 	'sprockets_filters' => [ | ||||
| 		'javascripts' => [], | ||||
| 		'stylesheets' => [], | ||||
|     ], | ||||
|  | ||||
| ]; | ||||
| @@ -0,0 +1,5 @@ | ||||
| <?php | ||||
|  | ||||
| return array( | ||||
|     'view' => 'laravel-breadcrumbs::bootstrap3', | ||||
| ); | ||||
							
								
								
									
										134
									
								
								app/config/packages/rcrowe/twigbridge/extensions.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								app/config/packages/rcrowe/twigbridge/extensions.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * This file is part of the TwigBridge package. | ||||
|  * | ||||
|  * @copyright Robert Crowe <hello@vivalacrowe.com> | ||||
|  * | ||||
|  * For the full copyright and license information, please view the LICENSE | ||||
|  * file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Configuration options for the built-in extensions. | ||||
|  */ | ||||
| return [ | ||||
|  | ||||
|     /* | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | Extensions | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | | ||||
|     | Enabled extensions. | ||||
|     | | ||||
|     | `Twig_Extension_Debug` is enabled automatically if twig.debug is TRUE. | ||||
|     | | ||||
|     */ | ||||
|     'enabled' => [ | ||||
|         'TwigBridge\Extension\Loader\Facades', | ||||
|         'TwigBridge\Extension\Loader\Filters', | ||||
|         'TwigBridge\Extension\Loader\Functions', | ||||
|  | ||||
|         'TwigBridge\Extension\Laravel\Auth', | ||||
|         'TwigBridge\Extension\Laravel\Config', | ||||
|         'TwigBridge\Extension\Laravel\Form', | ||||
|         'TwigBridge\Extension\Laravel\Html', | ||||
|         'TwigBridge\Extension\Laravel\Input', | ||||
|         'TwigBridge\Extension\Laravel\Session', | ||||
|         'TwigBridge\Extension\Laravel\String', | ||||
|         'TwigBridge\Extension\Laravel\Translator', | ||||
|         'TwigBridge\Extension\Laravel\Url', | ||||
|  | ||||
|         // 'TwigBridge\Extension\Laravel\Legacy\Facades', | ||||
|     ], | ||||
|  | ||||
|     /* | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | Facades | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | | ||||
|     | Available facades. Access like `{{ Config.get('foo.bar') }}`. | ||||
|     | | ||||
|     | Each facade can take an optional array of options. To mark the whole facade | ||||
|     | as safe you can set the option `'is_safe' => true`. Setting the facade as | ||||
|     | safe means that any HTML returned will not be escaped. | ||||
|     | | ||||
|     | It is advisable to not set the whole facade as safe and instead mark the | ||||
|     | each appropriate method as safe for security reasons. You can do that with | ||||
|     | the following syntax: | ||||
|     | | ||||
|     | <code> | ||||
|     |     'Form' => [ | ||||
|     |         'is_safe' => [ | ||||
|     |             'open' | ||||
|     |         ] | ||||
|     |     ] | ||||
|     | </code> | ||||
|     | | ||||
|     | The values of the `is_safe` array must match the called method on the facade | ||||
|     | in order to be marked as safe. | ||||
|     | | ||||
|     */ | ||||
|     'facades' => [], | ||||
|  | ||||
|     /* | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | Functions | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | | ||||
|     | Available functions. Access like `{{ secure_url(...) }}`. | ||||
|     | | ||||
|     | Each function can take an optional array of options. These options are | ||||
|     | passed directly to `Twig_SimpleFunction`. | ||||
|     | | ||||
|     | So for example, to mark a function as safe you can do the following: | ||||
|     | | ||||
|     | <code> | ||||
|     |     'link_to' => [ | ||||
|     |         'is_safe' => ['html'] | ||||
|     |     ] | ||||
|     | </code> | ||||
|     | | ||||
|     | The options array also takes a `callback` that allows you to name the | ||||
|     | function differently in your Twig templates than what it's actually called. | ||||
|     | | ||||
|     | <code> | ||||
|     |     'link' => [ | ||||
|     |         'callback' => 'link_to' | ||||
|     |     ] | ||||
|     | </code> | ||||
|     | | ||||
|     */ | ||||
|     'functions' => [], | ||||
|  | ||||
|     /* | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | Filters | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | | ||||
|     | Available filters. Access like `{{ variable|filter }}`. | ||||
|     | | ||||
|     | Each filter can take an optional array of options. These options are | ||||
|     | passed directly to `Twig_SimpleFilter`. | ||||
|     | | ||||
|     | So for example, to mark a filter as safe you can do the following: | ||||
|     | | ||||
|     | <code> | ||||
|     |     'studly_case' => [ | ||||
|     |         'is_safe' => ['html'] | ||||
|     |     ] | ||||
|     | </code> | ||||
|     | | ||||
|     | The options array also takes a `callback` that allows you to name the | ||||
|     | filter differently in your Twig templates than what is actually called. | ||||
|     | | ||||
|     | <code> | ||||
|     |     'snake' => [ | ||||
|     |         'callback' => 'snake_case' | ||||
|     |     ] | ||||
|     | </code> | ||||
|     | | ||||
|     */ | ||||
|     'filters' => [], | ||||
|  | ||||
| ]; | ||||
							
								
								
									
										88
									
								
								app/config/packages/rcrowe/twigbridge/twig.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								app/config/packages/rcrowe/twigbridge/twig.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * This file is part of the TwigBridge package. | ||||
|  * | ||||
|  * @copyright Robert Crowe <hello@vivalacrowe.com> | ||||
|  * | ||||
|  * For the full copyright and license information, please view the LICENSE | ||||
|  * file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| use Illuminate\Support\Facades\Config; | ||||
|  | ||||
| /** | ||||
|  * Configuration options for Twig. | ||||
|  */ | ||||
| return [ | ||||
|  | ||||
|     /* | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | Extension | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | | ||||
|     | File extension for Twig view files. | ||||
|     | | ||||
|     */ | ||||
|     'extension' => 'twig', | ||||
|  | ||||
|     /* | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | Accepts all Twig environment configuration options | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | | ||||
|     | http://twig.sensiolabs.org/doc/api.html#environment-options | ||||
|     | | ||||
|     */ | ||||
|     'environment' => [ | ||||
|  | ||||
|         // When set to true, the generated templates have a __toString() method | ||||
|         // that you can use to display the generated nodes. | ||||
|         // default: false | ||||
|         'debug' => Config::get('app.debug', false), | ||||
|  | ||||
|         // The charset used by the templates. | ||||
|         // default: utf-8 | ||||
|         'charset' => 'utf-8', | ||||
|  | ||||
|         // The base template class to use for generated templates. | ||||
|         // default: TwigBridge\Twig\Template | ||||
|         'base_template_class' => 'TwigBridge\Twig\Template', | ||||
|  | ||||
|         // An absolute path where to store the compiled templates, or false to disable caching. If null | ||||
|         // then the cache file path is used. | ||||
|         // default: cache file storage path | ||||
|         'cache' => null, | ||||
|  | ||||
|         // When developing with Twig, it's useful to recompile the template | ||||
|         // whenever the source code changes. If you don't provide a value | ||||
|         // for the auto_reload option, it will be determined automatically based on the debug value. | ||||
|         'auto_reload' => true, | ||||
|  | ||||
|         // If set to false, Twig will silently ignore invalid variables | ||||
|         // (variables and or attributes/methods that do not exist) and | ||||
|         // replace them with a null value. When set to true, Twig throws an exception instead. | ||||
|         // default: false | ||||
|         'strict_variables' => false, | ||||
|  | ||||
|         // If set to true, auto-escaping will be enabled by default for all templates. | ||||
|         // default: true | ||||
|         'autoescape' => true, | ||||
|  | ||||
|         // A flag that indicates which optimizations to apply | ||||
|         // (default to -1 -- all optimizations are enabled; set it to 0 to disable) | ||||
|         'optimizations' => -1, | ||||
|     ], | ||||
|  | ||||
|     /* | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | Global variables | ||||
|     |-------------------------------------------------------------------------- | ||||
|     | | ||||
|     | These will always be passed in and can be accessed as Twig variables. | ||||
|     | NOTE: these will be overwritten if you pass data into the view with the same key. | ||||
|     | | ||||
|     */ | ||||
|     'globals' => [], | ||||
|  | ||||
| ]; | ||||
| @@ -22,14 +22,73 @@ class AccountController extends \BaseController | ||||
|     { | ||||
|         $this->_accounts   = $accounts; | ||||
|         $this->_repository = $repository; | ||||
|         View::share('mainTitleIcon', 'fa-credit-card'); | ||||
|         View::share('title', 'Accounts'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return \Illuminate\View\View | ||||
|      */ | ||||
|     public function create() | ||||
|     public function create($what) | ||||
|     { | ||||
|         return View::make('accounts.create')->with('title', 'Create account'); | ||||
|         switch ($what) { | ||||
|             case 'asset': | ||||
|                 View::share('subTitleIcon', 'fa-money'); | ||||
|                 break; | ||||
|             case 'expense': | ||||
|                 View::share('subTitleIcon', 'fa-shopping-cart'); | ||||
|                 break; | ||||
|             case 'revenue': | ||||
|                 View::share('subTitleIcon', 'fa-download'); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         return View::make('accounts.create')->with('subTitle', 'Create a new ' . $what . ' account')->with( | ||||
|             'what', $what | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function asset() | ||||
|     { | ||||
|         View::share('subTitleIcon', 'fa-money'); | ||||
|  | ||||
|         $accounts = $this->_repository->getOfTypes(['Asset account', 'Default account']); | ||||
|  | ||||
|         return View::make('accounts.asset')->with('subTitle', 'Asset accounts')->with( | ||||
|             'accounts', $accounts | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function expense() | ||||
|     { | ||||
|         View::share('subTitleIcon', 'fa-shopping-cart'); | ||||
|  | ||||
|         $accounts = $this->_repository->getOfTypes(['Expense account', 'Beneficiary account']); | ||||
|  | ||||
|         return View::make('accounts.expense')->with('subTitle', 'Expense accounts')->with( | ||||
|             'accounts', $accounts | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function revenue() | ||||
|     { | ||||
|         View::share('subTitleIcon', 'fa-download'); | ||||
|  | ||||
|         $accounts = $this->_repository->getOfTypes(['Revenue account']); | ||||
|  | ||||
|         return View::make('accounts.revenue')->with('subTitle', 'Revenue accounts')->with( | ||||
|             'accounts', $accounts | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -40,7 +99,9 @@ class AccountController extends \BaseController | ||||
|     public function delete(Account $account) | ||||
|     { | ||||
|         return View::make('accounts.delete')->with('account', $account) | ||||
|             ->with('title', 'Delete account "' . $account->name . '"'); | ||||
|             ->with( | ||||
|                 'subTitle', 'Delete ' . strtolower($account->accountType->type) . ' "' . $account->name . '"' | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -50,11 +111,23 @@ class AccountController extends \BaseController | ||||
|      */ | ||||
|     public function destroy(Account $account) | ||||
|     { | ||||
|  | ||||
|         $type = $account->accountType->type; | ||||
|         $this->_repository->destroy($account); | ||||
|         Session::flash('success', 'The account was deleted.'); | ||||
|         switch ($type) { | ||||
|             case 'Asset account': | ||||
|             case 'Default account': | ||||
|                 return Redirect::route('accounts.asset'); | ||||
|                 break; | ||||
|             case 'Expense account': | ||||
|             case 'Beneficiary account': | ||||
|                 return Redirect::route('accounts.expense'); | ||||
|                 break; | ||||
|             case 'Revenue account': | ||||
|                 return Redirect::route('accounts.revenue'); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         return Redirect::route('accounts.index'); | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -65,9 +138,25 @@ class AccountController extends \BaseController | ||||
|      */ | ||||
|     public function edit(Account $account) | ||||
|     { | ||||
|  | ||||
|         switch ($account->accountType->type) { | ||||
|             case 'Asset account': | ||||
|             case 'Default account': | ||||
|                 View::share('subTitleIcon', 'fa-money'); | ||||
|                 break; | ||||
|             case 'Expense account': | ||||
|             case 'Beneficiary account': | ||||
|                 View::share('subTitleIcon', 'fa-shopping-cart'); | ||||
|                 break; | ||||
|             case 'Revenue account': | ||||
|                 View::share('subTitleIcon', 'fa-download'); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         $openingBalance = $this->_accounts->openingBalanceTransaction($account); | ||||
|         return View::make('accounts.edit')->with('account', $account)->with('openingBalance', $openingBalance) | ||||
|             ->with('title', 'Edit account "' . $account->name . '"'); | ||||
|  | ||||
|             ->with('subTitle', 'Edit ' . strtolower($account->accountType->type) . ' "' . $account->name . '"'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -75,23 +164,7 @@ class AccountController extends \BaseController | ||||
|      */ | ||||
|     public function index() | ||||
|     { | ||||
|         $accounts = $this->_repository->get(); | ||||
|         $set      = [ | ||||
|             'personal'      => [], | ||||
|             'beneficiaries' => [] | ||||
|         ]; | ||||
|         foreach ($accounts as $account) { | ||||
|             switch ($account->accounttype->type) { | ||||
|                 case 'Default account': | ||||
|                     $set['personal'][] = $account; | ||||
|                     break; | ||||
|                 case 'Beneficiary account': | ||||
|                     $set['beneficiaries'][] = $account; | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return View::make('accounts.index')->with('accounts', $set)->with('title', 'All your accounts'); | ||||
|         return View::make('error')->with('message', 'This view has been disabled'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -101,11 +174,26 @@ class AccountController extends \BaseController | ||||
|      */ | ||||
|     public function show(Account $account) | ||||
|     { | ||||
|         switch ($account->accountType->type) { | ||||
|             case 'Asset account': | ||||
|             case 'Default account': | ||||
|                 View::share('subTitleIcon', 'fa-money'); | ||||
|                 break; | ||||
|             case 'Expense account': | ||||
|             case 'Beneficiary account': | ||||
|                 View::share('subTitleIcon', 'fa-shopping-cart'); | ||||
|                 break; | ||||
|             case 'Revenue account': | ||||
|                 View::share('subTitleIcon', 'fa-download'); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         $data = $this->_accounts->show($account, 40); | ||||
|  | ||||
|         return View::make('accounts.show')->with('account', $account)->with('show', $data)->with( | ||||
|             'title', | ||||
|             'Details for account "' . $account->name . '"' | ||||
|             'subTitle', | ||||
|             'Details for ' . strtolower($account->accountType->type) . ' "' . $account->name . '"' | ||||
|         ); | ||||
|     } | ||||
|  | ||||
| @@ -115,21 +203,39 @@ class AccountController extends \BaseController | ||||
|     public function store() | ||||
|     { | ||||
|  | ||||
|         $account = $this->_repository->store(Input::all()); | ||||
|         $data         = Input::all(); | ||||
|         $data['what'] = isset($data['what']) && $data['what'] != '' ? $data['what'] : 'asset'; | ||||
|  | ||||
|  | ||||
|         switch ($data['what']) { | ||||
|             default: | ||||
|             case 'asset': | ||||
|                 $data['account_type'] = 'Asset account'; | ||||
|                 break; | ||||
|             case 'expense': | ||||
|                 $data['account_type'] = 'Expense account'; | ||||
|                 break; | ||||
|             case 'revenue': | ||||
|                 $data['account_type'] = 'Revenue account'; | ||||
|                 break; | ||||
|  | ||||
|         } | ||||
|         $account = $this->_repository->store($data); | ||||
|  | ||||
|         if ($account->validate()) { | ||||
|             // saved! return to wherever. | ||||
|             Session::flash('success', 'Account "' . $account->name . '" created!'); | ||||
|             if (intval(Input::get('create')) === 1) { | ||||
|                 return Redirect::route('accounts.create')->withInput(); | ||||
|                 return Redirect::route('accounts.create', $data['what'])->withInput(); | ||||
|             } else { | ||||
|                 return Redirect::route('accounts.index'); | ||||
|  | ||||
|                 return Redirect::route('accounts.' . e($data['what'])); | ||||
|             } | ||||
|         } else { | ||||
|             // did not save, return with error: | ||||
|             Session::flash('error', 'Could not save the new account: ' . $account->errors()->first()); | ||||
|  | ||||
|             return Redirect::route('accounts.create')->withErrors($account->errors())->withInput(); | ||||
|             return Redirect::route('accounts.create', $data['what'])->withErrors($account->errors())->withInput(); | ||||
|  | ||||
|         } | ||||
|     } | ||||
| @@ -141,11 +247,24 @@ class AccountController extends \BaseController | ||||
|      */ | ||||
|     public function update(Account $account) | ||||
|     { | ||||
|         /** @var \Account $account */ | ||||
|         $account = $this->_repository->update($account, Input::all()); | ||||
|         if ($account->validate()) { | ||||
|             Session::flash('success', 'Account "' . $account->name . '" updated.'); | ||||
|             switch ($account->accountType->type) { | ||||
|                 case 'Asset account': | ||||
|                 case 'Default account': | ||||
|                     return Redirect::route('accounts.asset'); | ||||
|                     break; | ||||
|                 case 'Expense account': | ||||
|                 case 'Beneficiary account': | ||||
|                     return Redirect::route('accounts.expense'); | ||||
|                     break; | ||||
|                 case 'Revenue account': | ||||
|                     return Redirect::route('accounts.revenue'); | ||||
|                     break; | ||||
|             } | ||||
|  | ||||
|             return Redirect::route('accounts.index'); | ||||
|         } else { | ||||
|             Session::flash('error', 'Could not update account: ' . $account->errors()->first()); | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| <?php | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Firefly\Exception\FireflyException; | ||||
| use Firefly\Helper\Controllers\BudgetInterface as BI; | ||||
| use Firefly\Storage\Budget\BudgetRepositoryInterface as BRI; | ||||
|  | ||||
| @@ -25,6 +26,40 @@ class BudgetController extends BaseController | ||||
|     { | ||||
|         $this->_budgets    = $budgets; | ||||
|         $this->_repository = $repository; | ||||
|         View::share('title', 'Budgets'); | ||||
|         View::share('mainTitleIcon', 'fa-tasks'); | ||||
|     } | ||||
|  | ||||
|     public function nobudget($view = 'session') { | ||||
|         switch($view) { | ||||
|             default: | ||||
|                 throw new FireflyException('Cannot show transactions without a budget for view "'.$view.'".'); | ||||
|                 break; | ||||
|             case 'session': | ||||
|                 $start = Session::get('start'); | ||||
|                 $end   = Session::get('end'); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         // Add expenses that have no budget: | ||||
|         $set = \Auth::user()->transactionjournals()->whereNotIn( | ||||
|             'transaction_journals.id', function ($query) use ($start, $end) { | ||||
|                 $query->select('transaction_journals.id')->from('transaction_journals') | ||||
|                       ->leftJoin( | ||||
|                           'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=', | ||||
|                           'transaction_journals.id' | ||||
|                       ) | ||||
|                       ->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id') | ||||
|                       ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) | ||||
|                       ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) | ||||
|                       ->where('components.class', 'Budget'); | ||||
|             } | ||||
|         )->before($end)->after($start)->get(); | ||||
|  | ||||
|         return View::make('budgets.nobudget') | ||||
|                    ->with('view', $view) | ||||
|                    ->with('transactions',$set) | ||||
|                    ->with('subTitle', 'Transactions without a budget'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -34,7 +69,7 @@ class BudgetController extends BaseController | ||||
|     { | ||||
|         $periods = \Config::get('firefly.periods_to_text'); | ||||
|  | ||||
|         return View::make('budgets.create')->with('periods', $periods)->with('title', 'Create a new budget'); | ||||
|         return View::make('budgets.create')->with('periods', $periods)->with('subTitle', 'Create a new budget'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -45,7 +80,7 @@ class BudgetController extends BaseController | ||||
|     public function delete(Budget $budget) | ||||
|     { | ||||
|         return View::make('budgets.delete')->with('budget', $budget) | ||||
|             ->with('title', 'Delete budget "' . $budget->name . '"'); | ||||
|             ->with('subTitle', 'Delete budget "' . $budget->name . '"'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -76,7 +111,7 @@ class BudgetController extends BaseController | ||||
|     public function edit(Budget $budget) | ||||
|     { | ||||
|         return View::make('budgets.edit')->with('budget', $budget) | ||||
|             ->with('title', 'Edit budget "' . $budget->name . '"'); | ||||
|             ->with('subTitle', 'Edit budget "' . $budget->name . '"'); | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -85,10 +120,12 @@ class BudgetController extends BaseController | ||||
|      */ | ||||
|     public function indexByBudget() | ||||
|     { | ||||
|         View::share('subTitleIcon', 'fa-folder-open'); | ||||
|  | ||||
|         $budgets = $this->_repository->get(); | ||||
|  | ||||
|         return View::make('budgets.indexByBudget')->with('budgets', $budgets)->with('today', new Carbon) | ||||
|             ->with('title', 'All your budgets grouped by budget'); | ||||
|             ->with('subTitle', 'Grouped by budget'); | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -97,12 +134,14 @@ class BudgetController extends BaseController | ||||
|      */ | ||||
|     public function indexByDate() | ||||
|     { | ||||
|         View::share('subTitleIcon', 'fa-calendar'); | ||||
|  | ||||
|         // get a list of dates by getting all repetitions: | ||||
|         $set     = $this->_repository->get(); | ||||
|         $budgets = $this->_budgets->organizeByDate($set); | ||||
|  | ||||
|         return View::make('budgets.indexByDate')->with('budgets', $budgets) | ||||
|             ->with('title', 'All your budgets grouped by date'); | ||||
|             ->with('subTitle', 'Grouped by date'); | ||||
|  | ||||
|  | ||||
|     } | ||||
| @@ -152,7 +191,7 @@ class BudgetController extends BaseController | ||||
|             ->with('view', $view) | ||||
|             ->with('highlight', Input::get('highlight')) | ||||
|             ->with('useSessionDates', $useSessionDates) | ||||
|             ->with('title', $title); | ||||
|             ->with('subTitle', 'Overview for ' . $title); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -21,6 +21,8 @@ class CategoryController extends BaseController | ||||
|     { | ||||
|         $this->_repository = $repository; | ||||
|         $this->_category   = $category; | ||||
|         View::share('title','Categories'); | ||||
|         View::share('mainTitleIcon', 'fa-bar-chart'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -28,7 +30,7 @@ class CategoryController extends BaseController | ||||
|      */ | ||||
|     public function create() | ||||
|     { | ||||
|         return View::make('categories.create')->with('title', 'Create a new category'); | ||||
|         return View::make('categories.create')->with('subTitle', 'Create a new category'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -39,7 +41,7 @@ class CategoryController extends BaseController | ||||
|     public function delete(Category $category) | ||||
|     { | ||||
|         return View::make('categories.delete')->with('category', $category) | ||||
|             ->with('title', 'Delete category "' . $category->name . '"'); | ||||
|             ->with('subTitle', 'Delete category "' . $category->name . '"'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -62,7 +64,7 @@ class CategoryController extends BaseController | ||||
|     public function edit(Category $category) | ||||
|     { | ||||
|         return View::make('categories.edit')->with('category', $category) | ||||
|             ->with('title', 'Edit category "' . $category->name . '"'); | ||||
|             ->with('subTitle', 'Edit category "' . $category->name . '"'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -73,7 +75,7 @@ class CategoryController extends BaseController | ||||
|         $categories = $this->_repository->get(); | ||||
|  | ||||
|         return View::make('categories.index')->with('categories', $categories) | ||||
|             ->with('title', 'All your categories'); | ||||
|             ->with('subTitle', 'All your categories'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -91,7 +93,7 @@ class CategoryController extends BaseController | ||||
|  | ||||
|         return View::make('categories.show')->with('category', $category)->with('journals', $journals)->with( | ||||
|             'highlight', Input::get('highlight') | ||||
|         )->with('title', 'Overview for category "' . $category->name . '"'); | ||||
|         )->with('subTitle', 'Overview for category "' . $category->name . '"'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| <?php | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Firefly\Exception\FireflyException; | ||||
| use Firefly\Helper\Controllers\ChartInterface; | ||||
| use Firefly\Storage\Account\AccountRepositoryInterface; | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
| /** | ||||
|  * Class ChartController | ||||
| @@ -18,7 +20,7 @@ class ChartController extends BaseController | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * @param ChartInterface             $chart | ||||
|      * @param ChartInterface $chart | ||||
|      * @param AccountRepositoryInterface $accounts | ||||
|      */ | ||||
|     public function __construct(ChartInterface $chart, AccountRepositoryInterface $accounts) | ||||
| @@ -46,7 +48,7 @@ class ChartController extends BaseController | ||||
|             /** @var \LimitRepetition $rep */ | ||||
|             foreach ($limit->limitrepetitions as $rep) { | ||||
|                 // get the amount of money spent in this period on this budget. | ||||
|                 $spentInRep = $rep->amount - $rep->left(); | ||||
|                 $spentInRep = $rep->amount - $rep->leftInRepetition(); | ||||
|                 $pct        = round((floatval($spentInRep) / floatval($limit->amount)) * 100, 2); | ||||
|                 $name       = $rep->periodShow(); | ||||
|                 $envelope[] = [$name, floatval($limit->amount)]; | ||||
| @@ -57,13 +59,13 @@ class ChartController extends BaseController | ||||
|  | ||||
|         $return = [ | ||||
|             'chart_title' => 'Overview for budget ' . $budget->name, | ||||
|             'subtitle'    => 'All envelopes', | ||||
|             'series'      => [ | ||||
|             'subtitle' => 'All envelopes', | ||||
|             'series' => [ | ||||
|                 [ | ||||
|                     'type'  => 'line', | ||||
|                     'type' => 'line', | ||||
|                     'yAxis' => 1, | ||||
|                     'name'  => 'Amount in envelope', | ||||
|                     'data'  => $envelope | ||||
|                     'name' => 'Amount in envelope', | ||||
|                     'data' => $envelope | ||||
|                 ], | ||||
|                 [ | ||||
|                     'type' => 'column', | ||||
| @@ -71,10 +73,10 @@ class ChartController extends BaseController | ||||
|                     'data' => $expense | ||||
|                 ], | ||||
|                 [ | ||||
|                     'type'  => 'line', | ||||
|                     'type' => 'line', | ||||
|                     'yAxis' => 1, | ||||
|                     'name'  => 'Spent percentage for envelope', | ||||
|                     'data'  => $left | ||||
|                     'name' => 'Spent percentage for envelope', | ||||
|                     'data' => $left | ||||
|                 ] | ||||
|  | ||||
|  | ||||
| @@ -111,14 +113,14 @@ class ChartController extends BaseController | ||||
|  | ||||
|         $return = [ | ||||
|             'chart_title' => 'Overview for budget ' . $budget->name, | ||||
|             'subtitle'    => | ||||
|             'subtitle' => | ||||
|                 'Between ' . $rep->startdate->format('M jS, Y') . ' and ' . $rep->enddate->format('M jS, Y'), | ||||
|             'series'      => [ | ||||
|             'series' => [ | ||||
|                 [ | ||||
|                     'type'  => 'column', | ||||
|                     'name'  => 'Expenses per day', | ||||
|                     'type' => 'column', | ||||
|                     'name' => 'Expenses per day', | ||||
|                     'yAxis' => 1, | ||||
|                     'data'  => $expense | ||||
|                     'data' => $expense | ||||
|                 ], | ||||
|                 [ | ||||
|                     'type' => 'line', | ||||
| @@ -175,8 +177,8 @@ class ChartController extends BaseController | ||||
|         } | ||||
|         $return = [ | ||||
|             'chart_title' => 'Overview for ' . $budget->name, | ||||
|             'subtitle'    => 'Not organized by an envelope', | ||||
|             'series'      => [ | ||||
|             'subtitle' => 'Not organized by an envelope', | ||||
|             'series' => [ | ||||
|                 [ | ||||
|                     'type' => 'column', | ||||
|                     'name' => 'Expenses per day', | ||||
| @@ -245,11 +247,11 @@ class ChartController extends BaseController | ||||
|  | ||||
|             // create a serie for the repetition. | ||||
|             $currentSerie = [ | ||||
|                 'type'  => 'spline', | ||||
|                 'id'    => 'rep-' . $repetition->id, | ||||
|                 'type' => 'spline', | ||||
|                 'id' => 'rep-' . $repetition->id, | ||||
|                 'yAxis' => 1, | ||||
|                 'name'  => 'Envelope #' . $repetition->id . ' in ' . $repetition->periodShow(), | ||||
|                 'data'  => [] | ||||
|                 'name' => 'Envelope #' . $repetition->id . ' in ' . $repetition->periodShow(), | ||||
|                 'data' => [] | ||||
|             ]; | ||||
|             $current      = clone $repetition->startdate; | ||||
|             while ($current <= $repetition->enddate) { | ||||
| @@ -271,11 +273,11 @@ class ChartController extends BaseController | ||||
|  | ||||
|         $return = [ | ||||
|             'chart_title' => 'Overview for budget ' . $budget->name, | ||||
|             'subtitle'    => | ||||
|             'subtitle' => | ||||
|                 'Between ' . Session::get('start')->format('M jS, Y') . ' and ' . Session::get('end')->format( | ||||
|                     'M jS, Y' | ||||
|                 ), | ||||
|             'series'      => $series | ||||
|             'series' => $series | ||||
|         ]; | ||||
|  | ||||
|         return Response::json($return); | ||||
| @@ -296,8 +298,8 @@ class ChartController extends BaseController | ||||
|         $serie = $this->_chart->categoryShowChart($category, $range, $start, $end); | ||||
|         $data  = [ | ||||
|             'chart_title' => $category->name, | ||||
|             'subtitle'    => '<a href="' . route('categories.show', [$category->id]) . '">View more</a>', | ||||
|             'series'      => $serie | ||||
|             'subtitle' => '<a href="' . route('categories.show', [$category->id]) . '">View more</a>', | ||||
|             'series' => $serie | ||||
|         ]; | ||||
|  | ||||
|         return Response::json($data); | ||||
| @@ -336,8 +338,8 @@ class ChartController extends BaseController | ||||
|             '<a href="' . route('accounts.index') . '">View more</a>'; | ||||
|         $data = [ | ||||
|             'chart_title' => count($accounts) == 1 ? $accounts[0]->name : 'All accounts', | ||||
|             'subtitle'    => $url, | ||||
|             'series'      => [] | ||||
|             'subtitle' => $url, | ||||
|             'series' => [] | ||||
|         ]; | ||||
|  | ||||
|         foreach ($accounts as $account) { | ||||
| @@ -372,9 +374,102 @@ class ChartController extends BaseController | ||||
|      */ | ||||
|     public function homeBudgets() | ||||
|     { | ||||
|         $start = \Session::get('start'); | ||||
|         $start = Session::get('start'); | ||||
|         $end   = Session::get('end'); | ||||
|         $data  = [ | ||||
|             'labels' => [], | ||||
|             'series' => [ | ||||
|                 [ | ||||
|                     'name' => 'Limit', | ||||
|                     'data' => [] | ||||
|                 ], | ||||
|                 [ | ||||
|                     'name' => 'Spent', | ||||
|                     'data' => [] | ||||
|                 ], | ||||
|             ] | ||||
|         ]; | ||||
|  | ||||
|         // Get all budgets. | ||||
|         $budgets   = \Auth::user()->budgets()->orderBy('name', 'ASC')->get(); | ||||
|         $budgetIds = []; | ||||
|         /** @var \Budget $budget */ | ||||
|         foreach ($budgets as $budget) { | ||||
|             $budgetIds[] = $budget->id; | ||||
|  | ||||
|             // Does the budget have a limit starting on $start? | ||||
|             $rep = \LimitRepetition:: | ||||
|             leftJoin('limits', 'limit_repetitions.limit_id', '=', 'limits.id')->leftJoin( | ||||
|                 'components', 'limits.component_id', '=', 'components.id' | ||||
|             )->where('limit_repetitions.startdate', $start->format('Y-m-d'))->where( | ||||
|                 'components.id', $budget->id | ||||
|             )->first(['limit_repetitions.*']); | ||||
|  | ||||
|             if (is_null($rep)) { | ||||
|                 $limit     = 0.0; | ||||
|                 $id        = null; | ||||
|                 $parameter = 'useSession=true'; | ||||
|             } else { | ||||
|                 $limit     = floatval($rep->amount); | ||||
|                 $id        = $rep->id; | ||||
|                 $parameter = ''; | ||||
|             } | ||||
|  | ||||
|             // Date range to check for expenses made? | ||||
|             if (is_null($rep)) { | ||||
|                 // use the session start and end for our search query | ||||
|                 $expenseStart = Session::get('start'); | ||||
|                 $expenseEnd   = Session::get('end'); | ||||
|  | ||||
|             } else { | ||||
|                 // use the limit's start and end for our search query | ||||
|                 $expenseStart = $rep->startdate; | ||||
|                 $expenseEnd   = $rep->enddate; | ||||
|             } | ||||
|             // How much have we spent on this budget? | ||||
|             $expenses = floatval($budget->transactionjournals()->before($expenseEnd)->after($expenseStart)->lessThan(0)->sum('amount')) * -1; | ||||
|  | ||||
|             // Append to chart: | ||||
|             if ($limit > 0 || $expenses > 0) { | ||||
|                 $data['labels'][]            = $budget->name; | ||||
|                 $data['series'][0]['data'][] = [ | ||||
|                     'y' => $limit, | ||||
|                     'url' => route('budgets.show', [$budget->id, $id]) . '?' . $parameter | ||||
|                 ]; | ||||
|                 $data['series'][1]['data'][] = [ | ||||
|                     'y' => $expenses, | ||||
|                     'url' => route('budgets.show', [$budget->id, $id]) . '?' . $parameter | ||||
|                 ]; | ||||
|             } | ||||
|         } | ||||
|         // Add expenses that have no budget: | ||||
|         $set = \Auth::user()->transactionjournals()->whereNotIn( | ||||
|             'transaction_journals.id', function ($query) use ($start, $end) { | ||||
|                 $query->select('transaction_journals.id')->from('transaction_journals') | ||||
|                       ->leftJoin( | ||||
|                           'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=', | ||||
|                           'transaction_journals.id' | ||||
|                       ) | ||||
|                       ->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id') | ||||
|                       ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) | ||||
|                       ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) | ||||
|                       ->where('components.class', 'Budget'); | ||||
|             } | ||||
|         )->before($end)->after($start)->lessThan(0)->transactionTypes(['Withdrawal'])->sum('amount'); | ||||
|  | ||||
|         // This can be debugged by using get(['transaction_journals.*','transactions.amount']); | ||||
|         $data['labels'][]            = 'No budget'; | ||||
|         $data['series'][0]['data'][] = [ | ||||
|             'y' => 0, | ||||
|             'url' => route('budgets.nobudget', 'session') | ||||
|         ]; | ||||
|         $data['series'][1]['data'][] = [ | ||||
|             'y' => floatval($set) * -1, | ||||
|             'url' => route('budgets.nobudget', 'session') | ||||
|         ]; | ||||
|  | ||||
|         return Response::json($data); | ||||
|  | ||||
|         return Response::json($this->_chart->budgets($start)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -389,4 +484,120 @@ class ChartController extends BaseController | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method checks all recurring transactions, calculates the current "moment" and returns | ||||
|      * a list of yet to be paid (and paid) recurring transactions. This list can be used to show a beautiful chart | ||||
|      * to the end user who will love it and cherish it. | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public function homeRecurring() | ||||
|     { | ||||
|         /** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */ | ||||
|         $toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface'); | ||||
|  | ||||
|         /* | ||||
|          * Set of paid transaction journals. | ||||
|          * Set of unpaid recurring transactions. | ||||
|          */ | ||||
|         $paid   = []; | ||||
|         $unpaid = []; | ||||
|  | ||||
|         /* | ||||
|          * Loop the recurring transactions. | ||||
|          */ | ||||
|  | ||||
|         /** @var \RecurringTransaction $recurring */ | ||||
|         foreach (\Auth::user()->recurringtransactions()->get() as $recurring) { | ||||
|             /* | ||||
|              * Start another loop starting at the $date. | ||||
|              */ | ||||
|             $start = clone $recurring->date; | ||||
|             $end   = Carbon::now(); | ||||
|  | ||||
|             /* | ||||
|              * The jump we make depends on the $repeat_freq | ||||
|              */ | ||||
|             $current = clone $start; | ||||
|  | ||||
|             while ($current <= $end) { | ||||
|                 /* | ||||
|                  * Get end of period for $current: | ||||
|                  */ | ||||
|                 $currentEnd = clone $current; | ||||
|                 $toolkit->endOfPeriod($currentEnd, $recurring->repeat_freq); | ||||
|  | ||||
|                 /* | ||||
|                  * In the current session range? | ||||
|                  */ | ||||
|                 if (\Session::get('end') >= $current and $currentEnd >= \Session::get('start')) { | ||||
|                     /* | ||||
|                      * Lets see if we've already spent money on this recurring transaction (it hath recurred). | ||||
|                      */ | ||||
|                     /** @var TransactionJournal $set */ | ||||
|                     $transaction = \Auth::user()->transactionjournals()->where('recurring_transaction_id', $recurring->id)->after($current)->before($currentEnd)->first(); | ||||
|  | ||||
|                     if(is_null($transaction)) { | ||||
|                         $unpaid[] = $recurring; | ||||
|                     } else { | ||||
|                         $paid[] = $transaction; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 /* | ||||
|                  * Add some time for the next loop! | ||||
|                  */ | ||||
|                 $toolkit->addPeriod($current, $recurring->repeat_freq, intval($recurring->skip)); | ||||
|  | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         /* | ||||
|          * Get some colors going. | ||||
|          */ | ||||
|         $unPaidColours = $toolkit->colorRange('AA4643', 'FFFFFF', count($unpaid) == 0 ? 1 : count($unpaid)); | ||||
|         $paidColours   = $toolkit->colorRange('4572A7', 'FFFFFF', count($paid) == 0 ? 1 : count($paid)); | ||||
|  | ||||
|         /* | ||||
|          * The chart serie: | ||||
|          */ | ||||
|         $serie         = [ | ||||
|             'type' => 'pie', | ||||
|             'name' => 'Amount', | ||||
|             'data' => [] | ||||
|         ]; | ||||
|  | ||||
|         /* | ||||
|          * Loop paid and unpaid to make two haves for a pie chart. | ||||
|          */ | ||||
|         /** @var TransactionJournal $entry */ | ||||
|         foreach ($paid as $index => $entry) { | ||||
|             $transactions    = $entry->transactions()->get(); | ||||
|             $amount          = max(floatval($transactions[0]->amount), floatval($transactions[1]->amount)); | ||||
|             $serie['data'][] = [ | ||||
|                 'name' => 'Already paid "'.$entry->description.'"', | ||||
|                 'y' => $amount, | ||||
|                 'url' => route('transactions.show',$entry->id), | ||||
|                 'objType' => 'paid', | ||||
|                 'color' => $paidColours[$index] | ||||
|             ]; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /** @var RecurringTransaction $entry */ | ||||
|         foreach ($unpaid as $index => $entry) { | ||||
|             $amount          = (floatval($entry->amount_max) + floatval($entry->amount_min)) / 2; | ||||
|             $serie['data'][] = [ | ||||
|                 'name' => 'Still due: '.$entry->name, | ||||
|                 'y' => $amount, | ||||
|                 'url' => route('recurring.show',$entry->id), | ||||
|                 'objType' => 'unpaid', | ||||
|                 'color' => $unPaidColours[$index] | ||||
|             ]; | ||||
|         } | ||||
|  | ||||
|         return Response::json([$serie]); | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -1,7 +1,6 @@ | ||||
| <?php | ||||
| use Firefly\Helper\Preferences\PreferencesHelperInterface as PHI; | ||||
| use Firefly\Storage\Account\AccountRepositoryInterface as ARI; | ||||
| use Firefly\Storage\Reminder\ReminderRepositoryInterface as RRI; | ||||
| use Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface as TJRI; | ||||
|  | ||||
| /** | ||||
| @@ -14,20 +13,61 @@ class HomeController extends BaseController | ||||
|     protected $_accounts; | ||||
|     protected $_preferences; | ||||
|     protected $_journal; | ||||
|     protected $_reminders; | ||||
|  | ||||
|     /** | ||||
|      * @param ARI  $accounts | ||||
|      * @param PHI  $preferences | ||||
|      * @param ARI $accounts | ||||
|      * @param PHI $preferences | ||||
|      * @param TJRI $journal | ||||
|      * @param RRI  $reminders | ||||
|      */ | ||||
|     public function __construct(ARI $accounts, PHI $preferences, TJRI $journal, RRI $reminders) | ||||
|     public function __construct(ARI $accounts, PHI $preferences, TJRI $journal) | ||||
|     { | ||||
|         $this->_accounts    = $accounts; | ||||
|         $this->_preferences = $preferences; | ||||
|         $this->_journal     = $journal; | ||||
|         $this->_reminders   = $reminders; | ||||
|     } | ||||
|  | ||||
|     public function jobDev() | ||||
|     { | ||||
|         $fullName = storage_path() . DIRECTORY_SEPARATOR . 'firefly-export-2014-07-23.json'; | ||||
|         \Log::notice('Pushed start job.'); | ||||
|         Queue::push('Firefly\Queue\Import@start', ['file' => $fullName, 'user' => 1]); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * | ||||
|      */ | ||||
|     public function sessionPrev() | ||||
|     { | ||||
|         /** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */ | ||||
|         $toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface'); | ||||
|         $toolkit->prev(); | ||||
|         return Redirect::back(); | ||||
|         //return Redirect::route('index'); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * | ||||
|      */ | ||||
|     public function sessionNext() | ||||
|     { | ||||
|         /** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */ | ||||
|         $toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface'); | ||||
|         $toolkit->next(); | ||||
|         return Redirect::back(); | ||||
|         //return Redirect::route('index'); | ||||
|     } | ||||
|  | ||||
|     public function rangeJump($range) | ||||
|     { | ||||
|  | ||||
|         $valid = ['1D', '1W', '1M', '3M', '6M', '1Y',]; | ||||
|  | ||||
|         if (in_array($range, $valid)) { | ||||
|             $this->_preferences->set('viewRange', $range); | ||||
|             Session::forget('range'); | ||||
|         } | ||||
|         return Redirect::back(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -71,15 +111,8 @@ class HomeController extends BaseController | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (count($transactions) % 2 == 0) { | ||||
|             $transactions = array_chunk($transactions, 2); | ||||
|         } elseif (count($transactions) == 1) { | ||||
|             $transactions = array_chunk($transactions, 3); | ||||
|         } else { | ||||
|             $transactions = array_chunk($transactions, 3); | ||||
|         } | ||||
|  | ||||
|         // build the home screen: | ||||
|         return View::make('index')->with('count', $count)->with('transactions', $transactions); | ||||
|         return View::make('index')->with('count', $count)->with('transactions', $transactions)->with('title', 'Firefly') | ||||
|                    ->with('subTitle', 'What\'s playing?')->with('mainTitleIcon', 'fa-fire'); | ||||
|     } | ||||
| } | ||||
| @@ -1,9 +1,8 @@ | ||||
| <?php | ||||
|  | ||||
| use Firefly\Storage\Account\AccountRepositoryInterface as ARI; | ||||
| use Firefly\Storage\Budget\BudgetRepositoryInterface as Bud; | ||||
| use Firefly\Storage\Category\CategoryRepositoryInterface as Cat; | ||||
| use Firefly\Storage\Component\ComponentRepositoryInterface as CRI; | ||||
| use Firefly\Helper\Controllers\JsonInterface as JI; | ||||
| use Illuminate\Support\Collection; | ||||
| use LaravelBook\Ardent\Builder; | ||||
|  | ||||
| /** | ||||
|  * Class JsonController | ||||
| @@ -12,32 +11,47 @@ use Firefly\Storage\Component\ComponentRepositoryInterface as CRI; | ||||
|  */ | ||||
| class JsonController extends BaseController | ||||
| { | ||||
|     protected $_accounts; | ||||
|     protected $_components; | ||||
|     protected $_categories; | ||||
|     protected $_budgets; | ||||
|     /** @var \Firefly\Helper\Controllers\JsonInterface $helper */ | ||||
|     protected $helper; | ||||
|  | ||||
|     public function __construct(JI $helper) | ||||
|     { | ||||
|         $this->helper = $helper; | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param ARI $accounts | ||||
|      * @param CRI $components | ||||
|      * @param Cat $categories | ||||
|      * @param Bud $budgets | ||||
|      * Returns a list of categories. | ||||
|      * | ||||
|      * @return \Illuminate\Http\JsonResponse | ||||
|      */ | ||||
|     public function __construct(ARI $accounts, CRI $components, Cat $categories, Bud $budgets) | ||||
|     public function categories() | ||||
|     { | ||||
|         $this->_components = $components; | ||||
|         $this->_accounts   = $accounts; | ||||
|         $this->_categories = $categories; | ||||
|         $this->_budgets    = $budgets; | ||||
|         /** @var \Firefly\Storage\Category\EloquentCategoryRepository $categories */ | ||||
|         $categories = App::make('Firefly\Storage\Category\CategoryRepositoryInterface'); | ||||
|         $list       = $categories->get(); | ||||
|         $return     = []; | ||||
|         foreach ($list as $entry) { | ||||
|             $return[] = $entry->name; | ||||
|         } | ||||
|  | ||||
|         return Response::json($return); | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a JSON list of all beneficiaries. | ||||
|      * | ||||
|      * @return \Illuminate\Http\JsonResponse | ||||
|      */ | ||||
|     public function beneficiaries() | ||||
|     public function expenseAccounts() | ||||
|     { | ||||
|         $list   = $this->_accounts->getBeneficiaries(); | ||||
|         $return = []; | ||||
|         /** @var \Firefly\Storage\Account\EloquentAccountRepository $accounts */ | ||||
|         $accounts = App::make('Firefly\Storage\Account\AccountRepositoryInterface'); | ||||
|         $list     = $accounts->getOfTypes(['Expense account', 'Beneficiary account']); | ||||
|         $return   = []; | ||||
|         foreach ($list as $entry) { | ||||
|             $return[] = $entry->name; | ||||
|         } | ||||
| @@ -47,18 +61,126 @@ class JsonController extends BaseController | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Responds some JSON for typeahead fields. | ||||
|      * Returns a list of transactions, expenses only, using the given parameters. | ||||
|      * | ||||
|      * @return \Illuminate\Http\JsonResponse | ||||
|      */ | ||||
|     public function categories() | ||||
|     public function expenses() | ||||
|     { | ||||
|         $list   = $this->_categories->get(); | ||||
|         $return = []; | ||||
|  | ||||
|         /* | ||||
|          * Gets most parameters from the Input::all() array: | ||||
|          */ | ||||
|         $parameters = $this->helper->dataTableParameters(); | ||||
|  | ||||
|         /* | ||||
|          * Add some more parameters to fine tune the query: | ||||
|          */ | ||||
|         $parameters['transactionTypes'] = ['Withdrawal']; | ||||
|         $parameters['amount']           = 'negative'; | ||||
|  | ||||
|         /* | ||||
|          * Get the query: | ||||
|          */ | ||||
|         $query = $this->helper->journalQuery($parameters); | ||||
|  | ||||
|         /* | ||||
|          * Build result set: | ||||
|          */ | ||||
|         $resultSet = $this->helper->journalDataset($parameters, $query); | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * Build return data: | ||||
|          */ | ||||
|         return Response::json($resultSet); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      */ | ||||
|     public function recurringjournals(RecurringTransaction $recurringTransaction) | ||||
|     { | ||||
|         $parameters                     = $this->helper->dataTableParameters(); | ||||
|         $parameters['transactionTypes'] = ['Withdrawal']; | ||||
|         $parameters['amount']           = 'negative'; | ||||
|  | ||||
|         $query = $this->helper->journalQuery($parameters); | ||||
|  | ||||
|         $query->where('recurring_transaction_id', $recurringTransaction->id); | ||||
|         $resultSet = $this->helper->journalDataset($parameters, $query); | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * Build return data: | ||||
|          */ | ||||
|         return Response::json($resultSet); | ||||
|     } | ||||
|  | ||||
|     public function recurring() | ||||
|     { | ||||
|         $parameters = $this->helper->dataTableParameters(); | ||||
|         $query      = $this->helper->recurringTransactionsQuery($parameters); | ||||
|         $resultSet  = $this->helper->recurringTransactionsDataset($parameters, $query); | ||||
|         return Response::json($resultSet); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return \Illuminate\Http\JsonResponse|string | ||||
|      */ | ||||
|     public function revenue() | ||||
|     { | ||||
|         $parameters                     = $this->helper->dataTableParameters(); | ||||
|         $parameters['transactionTypes'] = ['Deposit']; | ||||
|         $parameters['amount']           = 'positive'; | ||||
|  | ||||
|         $query     = $this->helper->journalQuery($parameters); | ||||
|         $resultSet = $this->helper->journalDataset($parameters, $query); | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * Build return data: | ||||
|          */ | ||||
|         return Response::json($resultSet); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a JSON list of all revenue accounts. | ||||
|      * | ||||
|      * @return \Illuminate\Http\JsonResponse | ||||
|      */ | ||||
|     public function revenueAccounts() | ||||
|     { | ||||
|         /** @var \Firefly\Storage\Account\EloquentAccountRepository $accounts */ | ||||
|         $accounts = App::make('Firefly\Storage\Account\AccountRepositoryInterface'); | ||||
|         $list     = $accounts->getOfTypes(['Revenue account']); | ||||
|         $return   = []; | ||||
|         foreach ($list as $entry) { | ||||
|             $return[] = $entry->name; | ||||
|         } | ||||
|  | ||||
|         return Response::json($return); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a list of all transfers. | ||||
|      * | ||||
|      * @return \Illuminate\Http\JsonResponse | ||||
|      */ | ||||
|     public function transfers() | ||||
|     { | ||||
|         $parameters                     = $this->helper->dataTableParameters(); | ||||
|         $parameters['transactionTypes'] = ['Transfer']; | ||||
|         $parameters['amount']           = 'positive'; | ||||
|  | ||||
|         $query     = $this->helper->journalQuery($parameters); | ||||
|         $resultSet = $this->helper->journalDataset($parameters, $query); | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * Build return data: | ||||
|          */ | ||||
|         return Response::json($resultSet); | ||||
|     } | ||||
| }  | ||||
| @@ -22,6 +22,9 @@ class LimitController extends BaseController | ||||
|     { | ||||
|         $this->_budgets = $budgets; | ||||
|         $this->_limits  = $limits; | ||||
|  | ||||
|         View::share('title','Envelopes'); | ||||
|         View::share('mainTitleIcon', 'fa-tasks'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -38,11 +41,13 @@ class LimitController extends BaseController | ||||
|             'budget_id'   => $budget ? $budget->id : null | ||||
|         ]; | ||||
|  | ||||
|         $budgets = $this->_budgets->getAsSelectList(); | ||||
|         /** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */ | ||||
|         $toolkit = App::make('Firefly\Helper\Toolkit\Toolkit'); | ||||
|         $budgets = $toolkit->makeSelectList($this->_budgets->get()); | ||||
|  | ||||
|         return View::make('limits.create')->with('budgets', $budgets)->with( | ||||
|             'periods', $periods | ||||
|         )->with('prefilled', $prefilled); | ||||
|         )->with('prefilled', $prefilled)->with('subTitle','New envelope'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -52,7 +57,7 @@ class LimitController extends BaseController | ||||
|      */ | ||||
|     public function delete(\Limit $limit) | ||||
|     { | ||||
|         return View::make('limits.delete')->with('limit', $limit); | ||||
|         return View::make('limits.delete')->with('limit', $limit)->with('subTitle','Delete envelope'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -84,12 +89,15 @@ class LimitController extends BaseController | ||||
|      */ | ||||
|     public function edit(Limit $limit) | ||||
|     { | ||||
|         $budgets = $this->_budgets->getAsSelectList(); | ||||
|         /** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */ | ||||
|         $toolkit = App::make('Firefly\Helper\Toolkit\Toolkit'); | ||||
|  | ||||
|         $budgets    = $toolkit->makeSelectList($this->_budgets->get()); | ||||
|         $periods = \Config::get('firefly.periods_to_text'); | ||||
|  | ||||
|         return View::make('limits.edit')->with('limit', $limit)->with('budgets', $budgets)->with( | ||||
|             'periods', $periods | ||||
|         ); | ||||
|         )->with('subTitle','Edit envelope'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -11,7 +11,8 @@ class MigrateController extends BaseController | ||||
|      */ | ||||
|     public function index() | ||||
|     { | ||||
|         return View::make('migrate.index')->with('index', 'Migration'); | ||||
|         return View::make('migrate.index')->with('index', 'Migration')->with('title','Migrate')-> | ||||
|             with('subTitle','From Firefly II to Firefly III'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -20,13 +21,10 @@ class MigrateController extends BaseController | ||||
|     public function upload() | ||||
|     { | ||||
|         if (Input::hasFile('file') && Input::file('file')->isValid()) { | ||||
|             // move file to storage: | ||||
|             // ->move($destinationPath, $fileName); | ||||
|             $path     = storage_path(); | ||||
|             $fileName = 'firefly-iii-import-' . date('Y-m-d-H-i') . '.json'; | ||||
|             $fullName = $path . DIRECTORY_SEPARATOR . $fileName; | ||||
|             if (is_writable($path)) { | ||||
|                 Input::file('file')->move($path, $fileName); | ||||
|             if (Input::file('file')->move($path, $fileName)) { | ||||
|                 // so now Firefly pushes something in a queue and does something with it! Yay! | ||||
|                 \Log::debug('Pushed a job to start the import.'); | ||||
|                 Queue::push('Firefly\Queue\Import@start', ['file' => $fullName, 'user' => \Auth::user()->id]); | ||||
|   | ||||
| @@ -15,8 +15,8 @@ use Firefly\Storage\Piggybank\PiggybankRepositoryInterface as PRI; | ||||
| class PiggybankController extends BaseController | ||||
| { | ||||
|  | ||||
|     protected $_repository; | ||||
|     protected $_accounts; | ||||
|     protected $_repository; | ||||
|  | ||||
|     /** | ||||
|      * @param PRI $repository | ||||
| @@ -49,10 +49,20 @@ class PiggybankController extends BaseController | ||||
|      */ | ||||
|     public function createPiggybank() | ||||
|     { | ||||
|         $periods  = Config::get('firefly.piggybank_periods'); | ||||
|         $accounts = $this->_accounts->getActiveDefaultAsSelectList(); | ||||
|         /** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */ | ||||
|         $toolkit = App::make('Firefly\Helper\Toolkit\Toolkit'); | ||||
|  | ||||
|         return View::make('piggybanks.create-piggybank')->with('accounts', $accounts)->with('periods', $periods); | ||||
|  | ||||
|         $periods  = Config::get('firefly.piggybank_periods'); | ||||
|         $list     = $this->_accounts->getActiveDefault(); | ||||
|         $accounts = $toolkit->makeSelectList($list); | ||||
|  | ||||
|         View::share('title', 'Piggy banks'); | ||||
|         View::share('subTitle', 'Create new'); | ||||
|         View::share('mainTitleIcon', 'fa-sort-amount-asc'); | ||||
|  | ||||
|         return View::make('piggybanks.create-piggybank')->with('accounts', $accounts) | ||||
|             ->with('periods', $periods); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -60,8 +70,16 @@ class PiggybankController extends BaseController | ||||
|      */ | ||||
|     public function createRepeated() | ||||
|     { | ||||
|         /** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */ | ||||
|         $toolkit = App::make('Firefly\Helper\Toolkit\Toolkit'); | ||||
|  | ||||
|         $periods  = Config::get('firefly.piggybank_periods'); | ||||
|         $accounts = $this->_accounts->getActiveDefaultAsSelectList(); | ||||
|         $list     = $this->_accounts->getActiveDefault(); | ||||
|         $accounts = $toolkit->makeSelectList($list); | ||||
|  | ||||
|         View::share('title', 'Repeated expenses'); | ||||
|         View::share('subTitle', 'Create new'); | ||||
|         View::share('mainTitleIcon', 'fa-rotate-right'); | ||||
|  | ||||
|         return View::make('piggybanks.create-repeated')->with('accounts', $accounts)->with('periods', $periods); | ||||
|     } | ||||
| @@ -73,6 +91,15 @@ class PiggybankController extends BaseController | ||||
|      */ | ||||
|     public function delete(Piggybank $piggyBank) | ||||
|     { | ||||
|         View::share('subTitle', 'Delete "' . $piggyBank->name . '"'); | ||||
|         if ($piggyBank->repeats == 1) { | ||||
|             View::share('title', 'Repeated expenses'); | ||||
|             View::share('mainTitleIcon', 'fa-rotate-right'); | ||||
|         } else { | ||||
|             View::share('title', 'Piggy banks'); | ||||
|             View::share('mainTitleIcon', 'fa-sort-amount-asc'); | ||||
|         } | ||||
|  | ||||
|         return View::make('piggybanks.delete')->with('piggybank', $piggyBank); | ||||
|     } | ||||
|  | ||||
| @@ -84,11 +111,18 @@ class PiggybankController extends BaseController | ||||
|     public function destroy(Piggybank $piggyBank) | ||||
|     { | ||||
|         Event::fire('piggybanks.destroy', [$piggyBank]); | ||||
|         if ($piggyBank->repeats == 1) { | ||||
|             $route   = 'piggybanks.index.repeated'; | ||||
|             $message = 'Repeated expense'; | ||||
|         } else { | ||||
|             $route   = 'piggybanks.index.piggybanks'; | ||||
|             $message = 'Piggybank'; | ||||
|         } | ||||
|         $this->_repository->destroy($piggyBank); | ||||
|  | ||||
|         Session::flash('success', 'Piggy bank deleted.'); | ||||
|         Session::flash('success', $message . ' deleted.'); | ||||
|  | ||||
|         return Redirect::route('piggybanks.index'); | ||||
|         return Redirect::route($route); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -98,12 +132,28 @@ class PiggybankController extends BaseController | ||||
|      */ | ||||
|     public function edit(Piggybank $piggyBank) | ||||
|     { | ||||
|         $accounts = $this->_accounts->getActiveDefaultAsSelectList(); | ||||
|         /** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */ | ||||
|         $toolkit = App::make('Firefly\Helper\Toolkit\Toolkit'); | ||||
|  | ||||
|         $list     = $this->_accounts->getActiveDefault(); | ||||
|         $accounts = $toolkit->makeSelectList($list); | ||||
|         $periods  = Config::get('firefly.piggybank_periods'); | ||||
|  | ||||
|  | ||||
|         View::share('subTitle', 'Edit "' . $piggyBank->name . '"'); | ||||
|  | ||||
|  | ||||
|         if ($piggyBank->repeats == 1) { | ||||
|             View::share('title', 'Repeated expenses'); | ||||
|             View::share('mainTitleIcon', 'fa-rotate-left'); | ||||
|  | ||||
|             return View::make('piggybanks.edit-repeated')->with('piggybank', $piggyBank)->with('accounts', $accounts) | ||||
|                 ->with('periods', $periods); | ||||
|         } else { | ||||
|             // piggy bank. | ||||
|             View::share('title', 'Piggy banks'); | ||||
|             View::share('mainTitleIcon', 'fa-sort-amount-asc'); | ||||
|  | ||||
|             return View::make('piggybanks.edit-piggybank')->with('piggybank', $piggyBank)->with('accounts', $accounts) | ||||
|                 ->with('periods', $periods); | ||||
|         } | ||||
| @@ -111,35 +161,6 @@ class PiggybankController extends BaseController | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function index() | ||||
|     { | ||||
|         $countRepeating    = $this->_repository->countRepeating(); | ||||
|         $countNonRepeating = $this->_repository->countNonrepeating(); | ||||
|  | ||||
|         $piggybanks = $this->_repository->get(); | ||||
|  | ||||
|         // get the accounts with each piggy bank and check their balance; Fireflyy might needs to | ||||
|         // show the user a correction. | ||||
|  | ||||
|         $accounts = []; | ||||
|         /** @var \Piggybank $piggybank */ | ||||
|         foreach ($piggybanks as $piggybank) { | ||||
|             $account = $piggybank->account; | ||||
|             $id      = $account->id; | ||||
|             if (!isset($accounts[$id])) { | ||||
|                 $accounts[$id] = ['account' => $account, 'left' => $this->_repository->leftOnAccount($account)]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return View::make('piggybanks.index')->with('piggybanks', $piggybanks) | ||||
|             ->with('countRepeating', $countRepeating) | ||||
|             ->with('countNonRepeating', $countNonRepeating) | ||||
|             ->with('accounts', $accounts); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Piggybank $piggyBank | ||||
|      * | ||||
| @@ -175,8 +196,47 @@ class PiggybankController extends BaseController | ||||
|                 } | ||||
|                 break; | ||||
|         } | ||||
|         if($piggyBank->repeats == 1) { | ||||
|             $route   = 'piggybanks.index.repeated'; | ||||
|  | ||||
|         return Redirect::route('piggybanks.index'); | ||||
|         } else { | ||||
|             $route   = 'piggybanks.index.piggybanks'; | ||||
|         } | ||||
|         return Redirect::route($route); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function piggybanks() | ||||
|     { | ||||
|         $countRepeating    = $this->_repository->countRepeating(); | ||||
|         $countNonRepeating = $this->_repository->countNonrepeating(); | ||||
|  | ||||
|         $piggybanks = $this->_repository->get(); | ||||
|  | ||||
|         // get the accounts with each piggy bank and check their balance; Fireflyy might needs to | ||||
|         // show the user a correction. | ||||
|  | ||||
|         $accounts = []; | ||||
|         /** @var \Piggybank $piggybank */ | ||||
|         foreach ($piggybanks as $piggybank) { | ||||
|             $account = $piggybank->account; | ||||
|             $id      = $account->id; | ||||
|             if (!isset($accounts[$id])) { | ||||
|                 $account->leftOnAccount = $this->_repository->leftOnAccount($account); | ||||
|                 $accounts[$id]          = ['account' => $account, 'left' => $this->_repository->leftOnAccount($account)]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         View::share('title', 'Piggy banks'); | ||||
|         View::share('subTitle', 'Save for big expenses'); | ||||
|         View::share('mainTitleIcon', 'fa-sort-amount-asc'); | ||||
|  | ||||
|         return View::make('piggybanks.index')->with('piggybanks', $piggybanks) | ||||
|             ->with('countRepeating', $countRepeating) | ||||
|             ->with('countNonRepeating', $countNonRepeating) | ||||
|             ->with('accounts', $accounts); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -195,6 +255,41 @@ class PiggybankController extends BaseController | ||||
|         )->with('piggybank', $piggyBank); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function repeated() | ||||
|     { | ||||
|         $countRepeating    = $this->_repository->countRepeating(); | ||||
|         $countNonRepeating = $this->_repository->countNonrepeating(); | ||||
|  | ||||
|         $piggybanks = $this->_repository->get(); | ||||
|  | ||||
|         // get the accounts with each piggy bank and check their balance; Fireflyy might needs to | ||||
|         // show the user a correction. | ||||
|  | ||||
|         $accounts = []; | ||||
|         /** @var \Piggybank $piggybank */ | ||||
|         foreach ($piggybanks as $piggybank) { | ||||
|             $account = $piggybank->account; | ||||
|             $id      = $account->id; | ||||
|             if (!isset($accounts[$id])) { | ||||
|                 $account->leftOnAccount = $this->_repository->leftOnAccount($account); | ||||
|                 $accounts[$id]          = ['account' => $account, 'left' => $this->_repository->leftOnAccount($account)]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         View::share('title', 'Repeated expenses'); | ||||
|         View::share('subTitle', 'Save for returning bills'); | ||||
|         View::share('mainTitleIcon', 'fa-rotate-left'); | ||||
|  | ||||
|  | ||||
|         return View::make('piggybanks.index')->with('piggybanks', $piggybanks) | ||||
|             ->with('countRepeating', $countRepeating) | ||||
|             ->with('countNonRepeating', $countNonRepeating) | ||||
|             ->with('accounts', $accounts); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      */ | ||||
| @@ -203,6 +298,18 @@ class PiggybankController extends BaseController | ||||
|         $leftOnAccount = $this->_repository->leftOnAccount($piggyBank->account); | ||||
|         $balance       = $piggyBank->account->balance(); | ||||
|  | ||||
|         View::share('subTitle', $piggyBank->name); | ||||
|  | ||||
|         if ($piggyBank->repeats == 1) { | ||||
|             // repeated expense. | ||||
|             View::share('title', 'Repeated expenses'); | ||||
|             View::share('mainTitleIcon', 'fa-rotate-left'); | ||||
|         } else { | ||||
|             // piggy bank. | ||||
|             View::share('title', 'Piggy banks'); | ||||
|             View::share('mainTitleIcon', 'fa-sort-amount-asc'); | ||||
|         } | ||||
|  | ||||
|         return View::make('piggybanks.show')->with('piggyBank', $piggyBank)->with('leftOnAccount', $leftOnAccount) | ||||
|             ->with('balance', $balance); | ||||
|     } | ||||
| @@ -226,7 +333,7 @@ class PiggybankController extends BaseController | ||||
|             Session::flash('success', 'New piggy bank "' . $piggyBank->name . '" created!'); | ||||
|             Event::fire('piggybanks.store', [$piggyBank]); | ||||
|  | ||||
|             return Redirect::route('piggybanks.index'); | ||||
|             return Redirect::route('piggybanks.index.piggybanks'); | ||||
|  | ||||
|  | ||||
|         } else { | ||||
| @@ -254,8 +361,7 @@ class PiggybankController extends BaseController | ||||
|         if ($piggyBank->id) { | ||||
|             Session::flash('success', 'New piggy bank "' . $piggyBank->name . '" created!'); | ||||
|             Event::fire('piggybanks.store', [$piggyBank]); | ||||
|  | ||||
|             return Redirect::route('piggybanks.index'); | ||||
|             return Redirect::route('piggybanks.index.repeated'); | ||||
|  | ||||
|         } else { | ||||
|             Session::flash('error', 'Could not save piggy bank: ' . $piggyBank->errors()->first()); | ||||
| @@ -274,10 +380,19 @@ class PiggybankController extends BaseController | ||||
|     { | ||||
|         $piggyBank = $this->_repository->update($piggyBank, Input::all()); | ||||
|         if ($piggyBank->validate()) { | ||||
|             Session::flash('success', 'Piggy bank "' . $piggyBank->name . '" updated.'); | ||||
|             if ($piggyBank->repeats == 1) { | ||||
|                 $route   = 'piggybanks.index.repeated'; | ||||
|                 $message = 'Repeated expense'; | ||||
|             } else { | ||||
|                 $route   = 'piggybanks.index.piggybanks'; | ||||
|                 $message = 'Piggy bank'; | ||||
|             } | ||||
|  | ||||
|  | ||||
|             Session::flash('success', $message . ' "' . $piggyBank->name . '" updated.'); | ||||
|             Event::fire('piggybanks.update', [$piggyBank]); | ||||
|  | ||||
|             return Redirect::route('piggybanks.index'); | ||||
|             return Redirect::route($route); | ||||
|         } else { | ||||
|             Session::flash('error', 'Could not update piggy bank: ' . $piggyBank->errors()->first()); | ||||
|  | ||||
|   | ||||
| @@ -22,6 +22,8 @@ class PreferencesController extends BaseController | ||||
|  | ||||
|         $this->_accounts    = $accounts; | ||||
|         $this->_preferences = $preferences; | ||||
|         View::share('title','Preferences'); | ||||
|         View::share('mainTitleIcon','fa-gear'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -22,6 +22,9 @@ class ProfileController extends BaseController | ||||
|      */ | ||||
|     public function index() | ||||
|     { | ||||
|         View::share('title', 'Profile'); | ||||
|         View::share('subTitle', Auth::user()->email); | ||||
|         View::share('mainTitleIcon', 'fa-user'); | ||||
|         return View::make('profile.index'); | ||||
|     } | ||||
|  | ||||
| @@ -30,6 +33,9 @@ class ProfileController extends BaseController | ||||
|      */ | ||||
|     public function changePassword() | ||||
|     { | ||||
|         View::share('title', Auth::user()->email); | ||||
|         View::share('subTitle', 'Change your password'); | ||||
|         View::share('mainTitleIcon', 'fa-user'); | ||||
|         return View::make('profile.change-password'); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| <?php | ||||
|  | ||||
| use Firefly\Exception\FireflyException; | ||||
| use Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface as RTR; | ||||
| use Firefly\Helper\Controllers\RecurringInterface as RI; | ||||
|  | ||||
| /** | ||||
|  * Class RecurringController | ||||
| @@ -10,13 +12,19 @@ use Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface | ||||
| class RecurringController extends BaseController | ||||
| { | ||||
|     protected $_repository; | ||||
|     protected $_helper; | ||||
|  | ||||
|     /** | ||||
|      * @param RTR $repository | ||||
|      * @param RI $helper | ||||
|      */ | ||||
|     public function __construct(RTR $repository) | ||||
|     public function __construct(RTR $repository, RI $helper) | ||||
|     { | ||||
|         $this->_repository = $repository; | ||||
|         $this->_helper     = $helper; | ||||
|  | ||||
|         View::share('title', 'Recurring transactions'); | ||||
|         View::share('mainTitleIcon', 'fa-rotate-right'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -24,6 +32,7 @@ class RecurringController extends BaseController | ||||
|      */ | ||||
|     public function create() | ||||
|     { | ||||
|         View::share('subTitle', 'Create new'); | ||||
|         $periods = \Config::get('firefly.periods_to_text'); | ||||
|  | ||||
|         return View::make('recurring.create')->with('periods', $periods); | ||||
| @@ -36,6 +45,7 @@ class RecurringController extends BaseController | ||||
|      */ | ||||
|     public function delete(RecurringTransaction $recurringTransaction) | ||||
|     { | ||||
|         View::share('subTitle', 'Delete "' . $recurringTransaction->name . '"'); | ||||
|         return View::make('recurring.delete')->with('recurringTransaction', $recurringTransaction); | ||||
|     } | ||||
|  | ||||
| @@ -46,7 +56,7 @@ class RecurringController extends BaseController | ||||
|      */ | ||||
|     public function destroy(RecurringTransaction $recurringTransaction) | ||||
|     { | ||||
|         Event::fire('recurring.destroy', [$recurringTransaction]); | ||||
|         //Event::fire('recurring.destroy', [$recurringTransaction]); | ||||
|         $result = $this->_repository->destroy($recurringTransaction); | ||||
|         if ($result === true) { | ||||
|             Session::flash('success', 'The recurring transaction was deleted.'); | ||||
| @@ -67,6 +77,8 @@ class RecurringController extends BaseController | ||||
|     { | ||||
|         $periods = \Config::get('firefly.periods_to_text'); | ||||
|  | ||||
|         View::share('subTitle', 'Edit "' . $recurringTransaction->name . '"'); | ||||
|  | ||||
|         return View::make('recurring.edit')->with('periods', $periods)->with( | ||||
|             'recurringTransaction', $recurringTransaction | ||||
|         ); | ||||
| @@ -77,9 +89,7 @@ class RecurringController extends BaseController | ||||
|      */ | ||||
|     public function index() | ||||
|     { | ||||
|         $list = $this->_repository->get(); | ||||
|  | ||||
|         return View::make('recurring.index')->with('list', $list); | ||||
|         return View::make('recurring.index'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -87,55 +97,142 @@ class RecurringController extends BaseController | ||||
|      */ | ||||
|     public function show(RecurringTransaction $recurringTransaction) | ||||
|     { | ||||
|         View::share('subTitle', $recurringTransaction->name); | ||||
|         return View::make('recurring.show')->with('recurring', $recurringTransaction); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return $this|\Illuminate\Http\RedirectResponse | ||||
|      * @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(); | ||||
|         } | ||||
|         // do something! | ||||
|         /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $repo */ | ||||
|         $repo = App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); | ||||
|         $set  = $repo->get(); | ||||
|  | ||||
|         /** @var TransactionJournal $journal */ | ||||
|         foreach ($set as $journal) { | ||||
|             Event::fire('recurring.rescan', [$recurringTransaction, $journal]); | ||||
|         } | ||||
|         Session::flash('success', 'Rescanned everything.'); | ||||
|         return Redirect::back(); | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public function store() | ||||
|     { | ||||
|         $recurringTransaction = $this->_repository->store(Input::all()); | ||||
|         if ($recurringTransaction->validate()) { | ||||
|             Session::flash('success', 'Recurring transaction "' . $recurringTransaction->name . '" saved!'); | ||||
|             Event::fire('recurring.store', [$recurringTransaction]); | ||||
|             if (Input::get('create') == '1') { | ||||
|                 return Redirect::route('recurring.create')->withInput(); | ||||
|             } else { | ||||
|                 return Redirect::route('recurring.index'); | ||||
|             } | ||||
|         } else { | ||||
|             Session::flash( | ||||
|                 'error', 'Could not save the recurring transaction: ' . $recurringTransaction->errors()->first() | ||||
|             ); | ||||
|         $data = Input::except(['_token', 'post_submit_action']); | ||||
|         switch (Input::get('post_submit_action')) { | ||||
|             default: | ||||
|                 throw new FireflyException('Method ' . Input::get('post_submit_action') . ' not implemented yet.'); | ||||
|                 break; | ||||
|             case 'store': | ||||
|             case 'create_another': | ||||
|                 /* | ||||
|                  * Try to store: | ||||
|                  */ | ||||
|                 $messageBag = $this->_repository->store($data); | ||||
|  | ||||
|             return Redirect::route('recurring.create')->withInput()->withErrors($recurringTransaction->errors()); | ||||
|                 /* | ||||
|                  * Failure! | ||||
|                  */ | ||||
|                 if ($messageBag->count() > 0) { | ||||
|                     Session::flash('error', 'Could not save recurring transaction: ' . $messageBag->first()); | ||||
|                     return Redirect::route('recurring.create')->withInput()->withErrors($messageBag); | ||||
|                 } | ||||
|  | ||||
|                 /* | ||||
|                  * Success! | ||||
|                  */ | ||||
|                 Session::flash('success', 'Recurring transaction "' . e(Input::get('name')) . '" saved!'); | ||||
|  | ||||
|                 /* | ||||
|                  * Redirect to original location or back to the form. | ||||
|                  */ | ||||
|                 if (Input::get('post_submit_action') == 'create_another') { | ||||
|                     return Redirect::route('recurring.create')->withInput(); | ||||
|                 } else { | ||||
|                     return Redirect::route('recurring.index'); | ||||
|                 } | ||||
|                 break; | ||||
|             case 'validate_only': | ||||
|                 $messageBags = $this->_helper->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|\Illuminate\Http\RedirectResponse | ||||
|      */ | ||||
|     public function update(RecurringTransaction $recurringTransaction) | ||||
|     { | ||||
|         /** @var \RecurringTransaction $recurringTransaction */ | ||||
|         $recurringTransaction = $this->_repository->update($recurringTransaction, Input::all()); | ||||
|         if ($recurringTransaction->errors()->count() == 0) { | ||||
|             Session::flash('success', 'The recurring transaction has been updated.'); | ||||
|             Event::fire('recurring.update', [$recurringTransaction]); | ||||
|         $data = Input::except(['_token', 'post_submit_action']); | ||||
|         switch (Input::get('post_submit_action')) { | ||||
|             case 'update': | ||||
|             case 'return_to_edit': | ||||
|                 $messageBag = $this->_repository->update($recurringTransaction, $data); | ||||
|                 if ($messageBag->count() == 0) { | ||||
|                     // has been saved, return to index: | ||||
|                     Session::flash('success', 'Recurring transaction updated!'); | ||||
|  | ||||
|             return Redirect::route('recurring.index'); | ||||
|         } else { | ||||
|             Session::flash( | ||||
|                 'error', 'Could not update the recurring transaction: ' . $recurringTransaction->errors()->first() | ||||
|             ); | ||||
|                     if (Input::get('post_submit_action') == 'return_to_edit') { | ||||
|                         return Redirect::route('recurring.edit', $recurringTransaction->id)->withInput(); | ||||
|                     } else { | ||||
|                         return Redirect::route('recurring.index'); | ||||
|                     } | ||||
|                 } else { | ||||
|                     Session::flash('error', 'Could not update recurring transaction: ' . $messageBag->first()); | ||||
|  | ||||
|             return Redirect::route('recurring.edit', $recurringTransaction->id)->withInput()->withErrors( | ||||
|                 $recurringTransaction->errors() | ||||
|             ); | ||||
|                     return Redirect::route('transactions.edit', $recurringTransaction->id)->withInput() | ||||
|                                    ->withErrors($messageBag); | ||||
|                 } | ||||
|  | ||||
|  | ||||
|                 break; | ||||
|             case 'validate_only': | ||||
|                 $data        = Input::all(); | ||||
|                 $data['id']  = $recurringTransaction->id; | ||||
|                 $messageBags = $this->_helper->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; | ||||
|             // update | ||||
|             default: | ||||
|                 throw new FireflyException('Method ' . Input::get('post_submit_action') . ' not implemented yet.'); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|  | ||||
| //        /** @var \RecurringTransaction $recurringTransaction */ | ||||
| //        $recurringTransaction = $this->_repository->update($recurringTransaction, Input::all()); | ||||
| //        if ($recurringTransaction->errors()->count() == 0) { | ||||
| //            Session::flash('success', 'The recurring transaction has been updated.'); | ||||
| //            //Event::fire('recurring.update', [$recurringTransaction]); | ||||
| // | ||||
| //            return Redirect::route('recurring.index'); | ||||
| //        } else { | ||||
| //            Session::flash( | ||||
| //                'error', 'Could not update the recurring transaction: ' . $recurringTransaction->errors()->first() | ||||
| //            ); | ||||
| // | ||||
| //            return Redirect::route('recurring.edit', $recurringTransaction->id)->withInput()->withErrors( | ||||
| //                $recurringTransaction->errors() | ||||
| //            ); | ||||
| //        } | ||||
|     } | ||||
| } | ||||
| @@ -1,97 +1,10 @@ | ||||
| <?php | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Firefly\Storage\Reminder\ReminderRepositoryInterface as RRI; | ||||
|  | ||||
| /** | ||||
|  * Class ReminderController | ||||
|  * | ||||
|  * @SuppressWarnings(PHPMD.CamelCasePropertyName) | ||||
|  */ | ||||
| class ReminderController extends BaseController | ||||
| { | ||||
|  | ||||
|     protected $_repository; | ||||
|  | ||||
|     /** | ||||
|      * @param RRI $repository | ||||
|      */ | ||||
|     public function __construct(RRI $repository) | ||||
|     { | ||||
|         $this->_repository = $repository; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Reminder $reminder | ||||
|      * | ||||
|      * @return \Illuminate\Http\JsonResponse | ||||
|      */ | ||||
|     public function dismiss(\Reminder $reminder) | ||||
|     { | ||||
|         $reminder = $this->_repository->deactivate($reminder); | ||||
|  | ||||
|         return Response::json($reminder->id); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the reminders currently active for the modal dialog. | ||||
|      */ | ||||
|     public function modalDialog() | ||||
|     { | ||||
|         $today     = new Carbon; | ||||
|         $reminders = $this->_repository->getPiggybankReminders(); | ||||
|  | ||||
|         /** @var \Reminder $reminder */ | ||||
|         foreach ($reminders as $index => $reminder) { | ||||
|             if (\Session::has('dismissal-' . $reminder->id)) { | ||||
|                 $time = \Session::get('dismissal-' . $reminder->id); | ||||
|                 if ($time >= $today) { | ||||
|                     unset($reminders[$index]); | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return View::make('reminders.popup')->with('reminders', $reminders); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Reminder $reminder | ||||
|      * | ||||
|      * @return \Illuminate\Http\JsonResponse | ||||
|      */ | ||||
|     public function postpone(\Reminder $reminder) | ||||
|     { | ||||
|         $now = new Carbon; | ||||
|         $now->addDay(); | ||||
|         Session::put('dismissal-' . $reminder->id, $now); | ||||
|  | ||||
|         return Response::json($reminder->id); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Reminder $reminder | ||||
|      * | ||||
|      * @return $this|\Illuminate\Http\RedirectResponse | ||||
|      */ | ||||
|     public function redirect(\Reminder $reminder) | ||||
|     { | ||||
|         if ($reminder instanceof PiggybankReminder) { | ||||
|             // fields to prefill: | ||||
|             $parameters = [ | ||||
|                 'account_to_id' => $reminder->piggybank->account->id, | ||||
|                 'amount'        => round($reminder->amountToSave(), 2), | ||||
|                 'description'   => 'Money for ' . $reminder->piggybank->name, | ||||
|                 'piggybank_id'  => $reminder->piggybank->id, | ||||
|                 'reminder_id'   => $reminder->id | ||||
|             ]; | ||||
|  | ||||
|             return Redirect::to( | ||||
|                 route('transactions.create', ['what' => 'transfer']) . '?' . http_build_query($parameters) | ||||
|             ); | ||||
|         } | ||||
|         return View::make('error')->with('message', 'No such reminder.'); | ||||
|  | ||||
|     } | ||||
|  | ||||
| }  | ||||
| } | ||||
| @@ -12,7 +12,7 @@ class ReportController extends BaseController | ||||
|      */ | ||||
|     public function index() | ||||
|     { | ||||
|  | ||||
|         return View::make('reports.index')->with('title','Reports')->with('mainTitleIcon','fa-line-chart'); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,16 +1,50 @@ | ||||
| <?php | ||||
|  | ||||
| use Firefly\Helper\Controllers\SearchInterface as SI; | ||||
|  | ||||
| /** | ||||
|  * Class SearchController | ||||
|  */ | ||||
| class SearchController extends BaseController | ||||
| { | ||||
|     protected $_helper; | ||||
|  | ||||
|     public function __construct(SI $helper) | ||||
|     { | ||||
|         $this->_helper = $helper; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      * Results always come in the form of an array [results, count, fullCount] | ||||
|      */ | ||||
|     public function index() | ||||
|     { | ||||
|         $subTitle = null; | ||||
|         $rawQuery = null; | ||||
|         $result = []; | ||||
|         if (!is_null(Input::get('q'))) { | ||||
|             $rawQuery = trim(Input::get('q')); | ||||
|             $words    = explode(' ', $rawQuery); | ||||
|             $subTitle = 'Results for "' . e($rawQuery) . '"'; | ||||
|  | ||||
|             $transactions = $this->_helper->searchTransactions($words); | ||||
|             $accounts     = $this->_helper->searchAccounts($words); | ||||
|             $categories   = $this->_helper->searchCategories($words); | ||||
|             $budgets      = $this->_helper->searchBudgets($words); | ||||
|             $tags         = $this->_helper->searchTags($words); | ||||
|             $result = [ | ||||
|                 'transactions' => $transactions, | ||||
|                 'accounts' => $accounts, | ||||
|                 'categories' => $categories, | ||||
|                 'budgets' => $budgets, | ||||
|                 'tags' => $tags | ||||
|             ]; | ||||
|  | ||||
|         } | ||||
|  | ||||
|         return View::make('search.index')->with('title', 'Search')->with('subTitle', $subTitle)->with( | ||||
|             'mainTitleIcon', 'fa-search' | ||||
|         )->with('query', $rawQuery)->with('result',$result); | ||||
|     } | ||||
| } | ||||
| @@ -1,63 +1,103 @@ | ||||
| <?php | ||||
|  | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Firefly\Exception\FireflyException; | ||||
| use Firefly\Helper\Controllers\TransactionInterface as TI; | ||||
| use Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface as TJRI; | ||||
| use Illuminate\Support\MessageBag; | ||||
|  | ||||
| /** | ||||
|  * Class TransactionController | ||||
|  * | ||||
|  * @SuppressWarnings(PHPMD.CamelCasePropertyName) | ||||
|  * | ||||
|  */ | ||||
| class TransactionController extends BaseController | ||||
| { | ||||
|  | ||||
|     protected $_helper; | ||||
|     protected $_repository; | ||||
|  | ||||
|     /** | ||||
|      * Construct a new transaction controller with two of the most often used helpers. | ||||
|      * | ||||
|      * @param TJRI $repository | ||||
|      * @param TI   $helper | ||||
|      */ | ||||
|     public function __construct(TJRI $repository) | ||||
|     public function __construct(TJRI $repository, TI $helper) | ||||
|     { | ||||
|         $this->_repository = $repository; | ||||
|         $this->_helper = $helper; | ||||
|         View::share('title', 'Transactions'); | ||||
|         View::share('mainTitleIcon', 'fa-repeat'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Shows the view helping the user to create a new transaction journal. | ||||
|      * | ||||
|      * @param string $what | ||||
|      * | ||||
|      * @return \Illuminate\View\View | ||||
|      */ | ||||
|     public function create($what = 'deposit') | ||||
|     { | ||||
|         // get accounts with names and id's. | ||||
|         /* | ||||
|          * The repositories we need: | ||||
|          */ | ||||
|         /** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */ | ||||
|         $toolkit = App::make('Firefly\Helper\Toolkit\Toolkit'); | ||||
|  | ||||
|         /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accountRepository */ | ||||
|         $accountRepository = App::make('Firefly\Storage\Account\AccountRepositoryInterface'); | ||||
|         $accounts          = $accountRepository->getActiveDefaultAsSelectList(); | ||||
|  | ||||
|         // get budgets as a select list. | ||||
|         /** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budgetRepository */ | ||||
|         $budgetRepository = App::make('Firefly\Storage\Budget\BudgetRepositoryInterface'); | ||||
|         $budgets          = $budgetRepository->getAsSelectList(); | ||||
|         $budgets[0]       = '(no budget)'; | ||||
|  | ||||
|         // get the piggy banks. | ||||
|         /** @var \Firefly\Storage\Piggybank\PiggybankRepositoryInterface $piggyRepository */ | ||||
|         $piggyRepository = App::make('Firefly\Storage\Piggybank\PiggybankRepositoryInterface'); | ||||
|         $piggies         = $piggyRepository->get(); | ||||
|  | ||||
|         return View::make('transactions.create')->with('accounts', $accounts)->with('budgets', $budgets)->with( | ||||
|         // get asset accounts with names and id's. | ||||
|         $assetAccounts = $toolkit->makeSelectList($accountRepository->getActiveDefault()); | ||||
|  | ||||
|         // get budgets as a select list. | ||||
|         $budgets = $toolkit->makeSelectList($budgetRepository->get()); | ||||
|         $budgets[0] = '(no budget)'; | ||||
|  | ||||
|         // get the piggy banks. | ||||
|         $piggies = $toolkit->makeSelectList($piggyRepository->get()); | ||||
|         $piggies[0] = '(no piggy bank)'; | ||||
|  | ||||
|         /* | ||||
|          * respond to a possible given values in the URL. | ||||
|          */ | ||||
|         $prefilled = Session::has('prefilled') ? Session::get('prefilled') : []; | ||||
|         $respondTo = ['account_id', 'account_from_id']; | ||||
|         foreach ($respondTo as $r) { | ||||
|             if (!is_null(Input::get($r))) { | ||||
|                 $prefilled[$r] = Input::get($r); | ||||
|             } | ||||
|         } | ||||
|         Session::put('prefilled', $prefilled); | ||||
|  | ||||
|         return View::make('transactions.create')->with('accounts', $assetAccounts)->with('budgets', $budgets)->with( | ||||
|             'what', $what | ||||
|         )->with('piggies', $piggies); | ||||
|         )->with('piggies', $piggies)->with('subTitle', 'Add a new ' . $what); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Shows the form that allows a user to delete a transaction journal. | ||||
|      * | ||||
|      * @param TransactionJournal $transactionJournal | ||||
|      * | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function delete(TransactionJournal $transactionJournal) | ||||
|     { | ||||
|         return View::make('transactions.delete')->with('journal', $transactionJournal); | ||||
|         $type = strtolower($transactionJournal->transactionType->type); | ||||
|  | ||||
|         return View::make('transactions.delete')->with('journal', $transactionJournal)->with( | ||||
|             'subTitle', 'Delete ' . $type . ' "' . $transactionJournal->description . '"' | ||||
|         ); | ||||
|  | ||||
|  | ||||
|     } | ||||
| @@ -70,103 +110,142 @@ class TransactionController extends BaseController | ||||
|      */ | ||||
|     public function destroy(TransactionJournal $transactionJournal) | ||||
|     { | ||||
|         $type = $transactionJournal->transactionType->type; | ||||
|         $transactionJournal->delete(); | ||||
|  | ||||
|         return Redirect::route('transactions.index'); | ||||
|  | ||||
|         switch ($type) { | ||||
|             case 'Withdrawal': | ||||
|                 return Redirect::route('transactions.expenses'); | ||||
|                 break; | ||||
|             case 'Deposit': | ||||
|                 return Redirect::route('transactions.revenue'); | ||||
|                 break; | ||||
|             case 'Transfer': | ||||
|                 return Redirect::route('transactions.transfers'); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Shows the view to edit a transaction. | ||||
|      * | ||||
|      * @param TransactionJournal $journal | ||||
|      * | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function edit(TransactionJournal $journal) | ||||
|     { | ||||
|         /* | ||||
|          * All the repositories we need: | ||||
|          */ | ||||
|         /** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */ | ||||
|         $toolkit = App::make('Firefly\Helper\Toolkit\Toolkit'); | ||||
|  | ||||
|         /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accountRepository */ | ||||
|         $accountRepository = App::make('Firefly\Storage\Account\AccountRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budgetRepository */ | ||||
|         $budgetRepository = App::make('Firefly\Storage\Budget\BudgetRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Firefly\Storage\Piggybank\PiggybankRepositoryInterface $piggyRepository */ | ||||
|         $piggyRepository = App::make('Firefly\Storage\Piggybank\PiggybankRepositoryInterface'); | ||||
|  | ||||
|         // type is useful for display: | ||||
|         $what = strtolower($journal->transactiontype->type); | ||||
|  | ||||
|         // some lists prefilled: | ||||
|         // get accounts with names and id's. | ||||
|         /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accountRepository */ | ||||
|         $accountRepository = App::make('Firefly\Storage\Account\AccountRepositoryInterface'); | ||||
|         $accounts          = $accountRepository->getActiveDefaultAsSelectList(); | ||||
|         // get asset accounts with names and id's. | ||||
|         $accounts = $toolkit->makeSelectList($accountRepository->getActiveDefault()); | ||||
|  | ||||
|         // get budgets as a select list. | ||||
|         /** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budgetRepository */ | ||||
|         $budgetRepository = App::make('Firefly\Storage\Budget\BudgetRepositoryInterface'); | ||||
|         $budgets          = $budgetRepository->getAsSelectList(); | ||||
|         $budgets[0]       = '(no budget)'; | ||||
|         $budgets = $toolkit->makeSelectList($budgetRepository->get()); | ||||
|         $budgets[0] = '(no budget)'; | ||||
|  | ||||
|         /* | ||||
|          * Get all piggy banks plus (if any) the relevant piggy bank. Since just one | ||||
|          * of the transactions in the journal has this field, it should all fill in nicely. | ||||
|          */ | ||||
|         // get the piggy banks. | ||||
|         /** @var \Firefly\Storage\Piggybank\PiggybankRepositoryInterface $piggyRepository */ | ||||
|         $piggyRepository = App::make('Firefly\Storage\Piggybank\PiggybankRepositoryInterface'); | ||||
|         $piggies         = $piggyRepository->get(); | ||||
|         // piggy bank id? | ||||
|         $piggyBankId = null; | ||||
|         $piggies = $toolkit->makeSelectList($piggyRepository->get()); | ||||
|         $piggies[0] = '(no piggy bank)'; | ||||
|         $piggyBankId = 0; | ||||
|         foreach ($journal->transactions as $t) { | ||||
|             $piggyBankId = $t->piggybank_id; | ||||
|             if (!is_null($t->piggybank_id)) { | ||||
|                 $piggyBankId = $t->piggybank_id; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // data to properly display form: | ||||
|         $data     = [ | ||||
|         /* | ||||
|          * Data to properly display the edit form. | ||||
|          */ | ||||
|         $prefilled = [ | ||||
|             'date'         => $journal->date->format('Y-m-d'), | ||||
|             'category'     => '', | ||||
|             'budget_id'    => 0, | ||||
|             'piggybank_id' => $piggyBankId | ||||
|         ]; | ||||
|  | ||||
|         /* | ||||
|          * Fill in the category. | ||||
|          */ | ||||
|         $category = $journal->categories()->first(); | ||||
|         if (!is_null($category)) { | ||||
|             $data['category'] = $category->name; | ||||
|             $prefilled['category'] = $category->name; | ||||
|         } | ||||
|         switch ($journal->transactiontype->type) { | ||||
|             case 'Withdrawal': | ||||
|                 $data['account_id']  = $journal->transactions[0]->account->id; | ||||
|                 $data['beneficiary'] = $journal->transactions[1]->account->name; | ||||
|                 $data['amount']      = floatval($journal->transactions[1]->amount); | ||||
|                 $budget              = $journal->budgets()->first(); | ||||
|  | ||||
|         /* | ||||
|          * Switch on the type of transaction edited by the user and fill in other | ||||
|          * relevant fields: | ||||
|          */ | ||||
|         switch ($what) { | ||||
|             case 'withdrawal': | ||||
|                 $prefilled['account_id'] = $journal->transactions[0]->account->id; | ||||
|                 $prefilled['expense_account'] = $journal->transactions[1]->account->name; | ||||
|                 $prefilled['amount'] = floatval($journal->transactions[1]->amount); | ||||
|                 $budget = $journal->budgets()->first(); | ||||
|                 if (!is_null($budget)) { | ||||
|                     $data['budget_id'] = $budget->id; | ||||
|                     $prefilled['budget_id'] = $budget->id; | ||||
|                 } | ||||
|                 break; | ||||
|             case 'Deposit': | ||||
|                 $data['account_id']  = $journal->transactions[1]->account->id; | ||||
|                 $data['beneficiary'] = $journal->transactions[0]->account->name; | ||||
|                 $data['amount']      = floatval($journal->transactions[1]->amount); | ||||
|             case 'deposit': | ||||
|                 $prefilled['account_id'] = $journal->transactions[1]->account->id; | ||||
|                 $prefilled['revenue_account'] = $journal->transactions[0]->account->name; | ||||
|                 $prefilled['amount'] = floatval($journal->transactions[1]->amount); | ||||
|                 break; | ||||
|             case 'Transfer': | ||||
|                 $data['account_from_id'] = $journal->transactions[1]->account->id; | ||||
|                 $data['account_to_id']   = $journal->transactions[0]->account->id; | ||||
|                 $data['amount']          = floatval($journal->transactions[1]->amount); | ||||
|             case 'transfer': | ||||
|                 $prefilled['account_from_id'] = $journal->transactions[1]->account->id; | ||||
|                 $prefilled['account_to_id'] = $journal->transactions[0]->account->id; | ||||
|                 $prefilled['amount'] = floatval($journal->transactions[1]->amount); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Show the view. | ||||
|          */ | ||||
|         return View::make('transactions.edit')->with('journal', $journal)->with('accounts', $accounts)->with( | ||||
|             'what', $what | ||||
|         )->with('budgets', $budgets)->with('data', $data)->with('piggies', $piggies); | ||||
|         )->with('budgets', $budgets)->with('data', $prefilled)->with('piggies', $piggies)->with( | ||||
|             'subTitle', 'Edit ' . $what . ' "' . $journal->description . '"' | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return $this|\Illuminate\View\View | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function index() | ||||
|     public function expenses() | ||||
|     { | ||||
|         $start = is_null(Input::get('startdate')) ? null : new Carbon(Input::get('startdate')); | ||||
|         $end   = is_null(Input::get('enddate')) ? null : new Carbon(Input::get('enddate')); | ||||
|         if ($start <= $end && !is_null($start) && !is_null($end)) { | ||||
|             $journals = $this->_repository->paginate(25, $start, $end); | ||||
|             $filtered = true; | ||||
|             $filters  = ['start' => $start, 'end' => $end]; | ||||
|         } else { | ||||
|             $journals = $this->_repository->paginate(25); | ||||
|             $filtered = false; | ||||
|             $filters  = null; | ||||
|         } | ||||
|         return View::make('transactions.list')->with('subTitle', 'Expenses')->with( | ||||
|             'subTitleIcon', 'fa-long-arrow-left' | ||||
|         )->with('what', 'expenses'); | ||||
|     } | ||||
|  | ||||
|  | ||||
|         return View::make('transactions.index')->with('journals', $journals)->with('filtered', $filtered)->with( | ||||
|             'filters', $filters | ||||
|         ); | ||||
|     /** | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function revenue() | ||||
|     { | ||||
|         return View::make('transactions.list')->with('subTitle', 'Revenue')->with( | ||||
|             'subTitleIcon', 'fa-long-arrow-right' | ||||
|         )->with('what', 'revenue'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -176,65 +255,122 @@ class TransactionController extends BaseController | ||||
|      */ | ||||
|     public function show(TransactionJournal $journal) | ||||
|     { | ||||
|         return View::make('transactions.show')->with('journal', $journal); | ||||
|         return View::make('transactions.show')->with('journal', $journal)->with( | ||||
|             'subTitle', $journal->transactionType->type . ' "' . $journal->description . '"' | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $what | ||||
|      * | ||||
|      * @return \Illuminate\Http\RedirectResponse | ||||
|      * @return $this|\Illuminate\Http\RedirectResponse | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public function store($what) | ||||
|     { | ||||
|         $journal = $this->_repository->store($what, Input::all()); | ||||
|         if ($journal->validate()) { | ||||
|             Session::flash('success', 'Transaction "' . $journal->description . '" saved!'); | ||||
|         /* | ||||
|          * Collect data to process: | ||||
|          */ | ||||
|         $data = Input::except(['_token']); | ||||
|         $data['what'] = $what; | ||||
|  | ||||
|             // if reminder present, deactivate it: | ||||
|             if (Input::get('reminder')) { | ||||
|                 /** @var \Firefly\Storage\Reminder\ReminderRepositoryInterface $reminders */ | ||||
|                 $reminders = App::make('Firefly\Storage\Reminder\ReminderRepositoryInterface'); | ||||
|                 $reminder  = $reminders->find(Input::get('reminder')); | ||||
|                 $reminders->deactivate($reminder); | ||||
|             } | ||||
|         switch (Input::get('post_submit_action')) { | ||||
|             case 'store': | ||||
|             case 'create_another': | ||||
|                 /* | ||||
|                  * Try to store: | ||||
|                  */ | ||||
|                 $messageBag = $this->_helper->store($data); | ||||
|  | ||||
|             // trigger the creation for recurring transactions. | ||||
|             Event::fire('journals.store', [$journal]); | ||||
|                 /* | ||||
|                  * Failure! | ||||
|                  */ | ||||
|                 if ($messageBag->count() > 0) { | ||||
|                     Session::flash('error', 'Could not save transaction: ' . $messageBag->first()); | ||||
|                     return Redirect::route('transactions.create', [$what])->withInput()->withErrors($messageBag); | ||||
|                 } | ||||
|  | ||||
|             if (Input::get('create') == '1') { | ||||
|                 /* | ||||
|                  * Success! | ||||
|                  */ | ||||
|                 Session::flash('success', 'Transaction "' . e(Input::get('description')) . '" saved!'); | ||||
|  | ||||
|                 /* | ||||
|                  * Redirect to original location or back to the form. | ||||
|                  */ | ||||
|                 if (Input::get('post_submit_action') == 'create_another') { | ||||
|                     return Redirect::route('transactions.create', $what)->withInput(); | ||||
|                 } else { | ||||
|                     return Redirect::route('transactions.index.' . $what); | ||||
|                 } | ||||
|  | ||||
|                 break; | ||||
|             case 'validate_only': | ||||
|                 $messageBags = $this->_helper->validate($data); | ||||
|  | ||||
|                 Session::flash('warnings', $messageBags['warnings']); | ||||
|                 Session::flash('successes', $messageBags['successes']); | ||||
|                 Session::flash('errors', $messageBags['errors']); | ||||
|                 return Redirect::route('transactions.create', [$what])->withInput(); | ||||
|             } else { | ||||
|                 return Redirect::route('transactions.index'); | ||||
|             } | ||||
|         } else { | ||||
|             Session::flash('error', 'Could not save transaction: ' . $journal->errors()->first()); | ||||
|  | ||||
|             return Redirect::route('transactions.create', [$what])->withInput()->withErrors( | ||||
|                 $journal->errors() | ||||
|             ); | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new FireflyException('Method ' . Input::get('post_submit_action') . ' not implemented yet.'); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function transfers() | ||||
|     { | ||||
|         return View::make('transactions.list')->with('subTitle', 'Transfers')->with( | ||||
|             'subTitleIcon', 'fa-arrows-h' | ||||
|         )->with('what', 'transfers'); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param TransactionJournal $journal | ||||
|      * | ||||
|      * @return $this|\Illuminate\Http\RedirectResponse | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public function update(TransactionJournal $journal) | ||||
|     { | ||||
|         $journal = $this->_repository->update($journal, Input::all()); | ||||
|         if ($journal->validate()) { | ||||
|             // has been saved, return to index: | ||||
|             Session::flash('success', 'Transaction updated!'); | ||||
|             Event::fire('journals.update', [$journal]); | ||||
|         switch (Input::get('post_submit_action')) { | ||||
|             case 'update': | ||||
|             case 'return_to_edit': | ||||
|                 $what = strtolower($journal->transactionType->type); | ||||
|                 $messageBag = $this->_helper->update($journal, Input::all()); | ||||
|                 if ($messageBag->count() == 0) { | ||||
|                     // has been saved, return to index: | ||||
|                     Session::flash('success', 'Transaction updated!'); | ||||
|                     Event::fire('journals.update', [$journal]); | ||||
|  | ||||
|             return Redirect::route('transactions.index'); | ||||
|         } else { | ||||
|             Session::flash('error', 'Could not update transaction: ' . $journal->errors()->first()); | ||||
|                     if (Input::get('post_submit_action') == 'return_to_edit') { | ||||
|                         return Redirect::route('transactions.edit', $journal->id)->withInput(); | ||||
|                     } else { | ||||
|                         return Redirect::route('transactions.index.' . $what); | ||||
|                     } | ||||
|                 } else { | ||||
|                     Session::flash('error', 'Could not update transaction: ' . $journal->errors()->first()); | ||||
|  | ||||
|             return Redirect::route('transactions.edit', $journal->id)->withInput()->withErrors($journal->errors()); | ||||
|                     return Redirect::route('transactions.edit', $journal->id)->withInput()->withErrors( | ||||
|                         $journal->errors() | ||||
|                     ); | ||||
|                 } | ||||
|  | ||||
|                 break; | ||||
|             case 'validate_only': | ||||
|                 $data = Input::all(); | ||||
|                 $data['what'] = strtolower($journal->transactionType->type); | ||||
|                 $messageBags = $this->_helper->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; | ||||
|         } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -47,8 +47,6 @@ class UserController extends BaseController | ||||
|         ]; | ||||
|         $result     = Auth::attempt($data, $rememberMe); | ||||
|         if ($result) { | ||||
|             Session::flash('success', 'Logged in!'); | ||||
|  | ||||
|             return Redirect::route('index'); | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -27,26 +27,11 @@ class CreateRemindersTable extends Migration | ||||
|             'reminders', function (Blueprint $table) { | ||||
|                 $table->increments('id'); | ||||
|                 $table->timestamps(); | ||||
|                 $table->string('class', 40); | ||||
|                 $table->integer('piggybank_id')->unsigned()->nullable(); | ||||
|                 $table->integer('recurring_transaction_id')->unsigned()->nullable(); | ||||
|                 $table->integer('user_id')->unsigned(); | ||||
|                 $table->date('startdate'); | ||||
|                 $table->date('enddate')->nullable(); | ||||
|                 $table->boolean('active'); | ||||
|  | ||||
|  | ||||
|                 // connect reminders to piggy banks. | ||||
|                 $table->foreign('piggybank_id') | ||||
|                     ->references('id')->on('piggybanks') | ||||
|                     ->onDelete('set null'); | ||||
|  | ||||
|                 // connect reminders to recurring transactions. | ||||
|                 $table->foreign('recurring_transaction_id') | ||||
|                     ->references('id')->on('recurring_transactions') | ||||
|                     ->onDelete('set null'); | ||||
|  | ||||
|  | ||||
|                 // connect reminders to users | ||||
|                 $table->foreign('user_id') | ||||
|                     ->references('id')->on('users') | ||||
|   | ||||
| @@ -18,6 +18,8 @@ class CreateImportmapsTable extends Migration { | ||||
| 			$table->timestamps(); | ||||
|             $table->integer('user_id')->unsigned(); | ||||
|             $table->string('file',500); | ||||
|             $table->integer('totaljobs')->unsigned(); | ||||
|             $table->integer('jobsdone')->unsigned(); | ||||
|  | ||||
|             // connect maps to users | ||||
|             $table->foreign('user_id') | ||||
|   | ||||
| @@ -11,20 +11,29 @@ class AccountTypeSeeder extends Seeder | ||||
|         DB::table('account_types')->delete(); | ||||
|  | ||||
|         AccountType::create( | ||||
|                    ['type' => 'Default account', 'editable' => true] | ||||
|             ['type' => 'Default account', 'editable' => true] | ||||
|         ); | ||||
|         AccountType::create( | ||||
|                    ['type' => 'Cash account', 'editable' => false] | ||||
|             ['type' => 'Cash account', 'editable' => false] | ||||
|         ); | ||||
|         AccountType::create( | ||||
|                    ['type' => 'Initial balance account', 'editable' => false] | ||||
|             ['type' => 'Asset account', 'editable' => true] | ||||
|         ); | ||||
|         AccountType::create( | ||||
|                    ['type' => 'Beneficiary account', 'editable' => true] | ||||
|             ['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] | ||||
|             ['type' => 'Import account', 'editable' => false] | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -6,10 +6,11 @@ App::before( | ||||
|     function ($request) { | ||||
|  | ||||
|         if (Auth::check()) { | ||||
|             /** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */ | ||||
|             $toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface'); | ||||
|             $toolkit->getDateRange($request); | ||||
|             $toolkit->getReminders(); | ||||
|  | ||||
|             $toolkit->getDateRange(); | ||||
|             $toolkit->checkImportJobs(); | ||||
|             Event::fire('recurring.verify'); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|   | ||||
| @@ -1,7 +1,4 @@ | ||||
| <?php | ||||
|  | ||||
|  | ||||
|  | ||||
| namespace Firefly\Database; | ||||
|  | ||||
| use LaravelBook\Ardent\Ardent; | ||||
|   | ||||
| @@ -1,14 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Firefly\Helper; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Class MigrationException | ||||
|  * | ||||
|  * @package Firefly\Helper | ||||
|  */ | ||||
| class MigrationException extends \Exception | ||||
| { | ||||
|  | ||||
| }  | ||||
							
								
								
									
										11
									
								
								app/lib/Firefly/Exception/ValidationException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/lib/Firefly/Exception/ValidationException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?php | ||||
| namespace Firefly\Exception; | ||||
|  | ||||
| /** | ||||
|  * Class ValidationException | ||||
|  * | ||||
|  * @package Firefly\Exception | ||||
|  */ | ||||
| class ValidationException extends \Exception { | ||||
|  | ||||
| }  | ||||
							
								
								
									
										327
									
								
								app/lib/Firefly/Form/Form.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								app/lib/Firefly/Form/Form.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,327 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Firefly\Form; | ||||
|  | ||||
|  | ||||
| use Firefly\Exception\FireflyException; | ||||
| use Illuminate\Support\MessageBag; | ||||
|  | ||||
| class Form | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * @param null $value | ||||
|      * @param array $options | ||||
|      * @return string | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public static function ffInteger($name, $value = null, array $options = []) | ||||
|     { | ||||
|         $options['step'] = '1'; | ||||
|         return self::ffInput('number', $name, $value, $options); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public static function ffCheckbox($name, $value = 1, $checked = null, $options = []) | ||||
|     { | ||||
|         $options['checked'] = $checked ? true : null; | ||||
|         return self::ffInput('checkbox', $name, $value, $options); | ||||
|     } | ||||
|  | ||||
|     public static function ffAmount($name, $value = null, array $options = []) | ||||
|     { | ||||
|         $options['step'] = 'any'; | ||||
|         $options['min'] = '0.01'; | ||||
|         return self::ffInput('amount', $name, $value, $options); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * @param null $value | ||||
|      * @param array $options | ||||
|      * @return string | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public static function ffDate($name, $value = null, array $options = []) | ||||
|     { | ||||
|         return self::ffInput('date', $name, $value, $options); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * @param null $value | ||||
|      * @param array $options | ||||
|      * @return string | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public static function ffTags($name, $value = null, array $options = []) | ||||
|     { | ||||
|         $options['data-role'] = 'tagsinput'; | ||||
|         return self::ffInput('text', $name, $value, $options); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * @param array $list | ||||
|      * @param null $selected | ||||
|      * @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); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * @param null $value | ||||
|      * @param array $options | ||||
|      * @return string | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public static function ffText($name, $value = null, array $options = array()) | ||||
|     { | ||||
|         return self::ffInput('text', $name, $value, $options); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public static function label($name) | ||||
|     { | ||||
|         $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' | ||||
|         ]; | ||||
|  | ||||
|         return isset($labels[$name]) ? $labels[$name] : str_replace('_', ' ', ucfirst($name)); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Return buttons for update/validate/return. | ||||
|      * | ||||
|      * @param $type | ||||
|      * @param $name | ||||
|      */ | ||||
|     public static function ffOptionsList($type, $name) | ||||
|     { | ||||
|         $previousValue = \Input::old('post_submit_action'); | ||||
|         $previousValue = is_null($previousValue) ? 'store' : $previousValue; | ||||
|         /* | ||||
|          * Store. | ||||
|          */ | ||||
|         $store = ''; | ||||
|         switch ($type) { | ||||
|             case 'create': | ||||
|                 $store = '<div class="form-group"><label for="default" 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'); | ||||
|                 $store .= 'Store ' . $name . '</label></div></div></div>'; | ||||
|                 break; | ||||
|             case 'update': | ||||
|                 $store = '<div class="form-group"><label for="default" 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 == 'store'); | ||||
|                 $store .= 'Update ' . $name . '</label></div></div></div>'; | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new FireflyException('Cannot create ffOptionsList for option (store) ' . $type); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * validate is always the same: | ||||
|          */ | ||||
|         $validate = '<div class="form-group"><label for="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'); | ||||
|         $validate .= 'Only validate, do not save</label></div></div></div>'; | ||||
|  | ||||
|         /* | ||||
|          * Store & return: | ||||
|          */ | ||||
|         switch ($type) { | ||||
|             case 'create': | ||||
|                 $return = '<div class="form-group"><label for="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'); | ||||
|                 $return .= 'After storing, return here to create another one.</label></div></div></div>'; | ||||
|                 break; | ||||
|             case 'update': | ||||
|                 $return = '<div class="form-group"><label for="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'); | ||||
|                 $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; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $type | ||||
|      * @param $name | ||||
|      * @param null $value | ||||
|      * @param array $options | ||||
|      * @param array $list | ||||
|      * @return string | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public static function ffInput($type, $name, $value = null, array $options = array(), $list = []) | ||||
|     { | ||||
|         /* | ||||
|          * add some defaults to this method: | ||||
|          */ | ||||
|         $options['class'] = 'form-control'; | ||||
|         $options['id'] = 'ffInput_' . $name; | ||||
|         $options['autocomplete'] = 'off'; | ||||
|         $label = self::label($name); | ||||
|         /* | ||||
|          * Make label and placeholder look nice. | ||||
|          */ | ||||
|         $options['placeholder'] = ucfirst($name); | ||||
|  | ||||
|         /* | ||||
|          * Get prefilled 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">€</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['checked'], $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>'; | ||||
|  | ||||
|         return $html; | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -17,7 +17,7 @@ class Account implements AccountInterface | ||||
|     public function openingBalanceTransaction(\Account $account) | ||||
|     { | ||||
|         return \TransactionJournal::withRelevantData() | ||||
|                                   ->account($account) | ||||
|                                   ->accountIs($account) | ||||
|                                   ->leftJoin('transaction_types', 'transaction_types.id', '=', | ||||
|                 'transaction_journals.transaction_type_id') | ||||
|                                   ->where('transaction_types.type', 'Opening balance') | ||||
| @@ -54,7 +54,7 @@ class Account implements AccountInterface | ||||
|         // build a query: | ||||
|         $query = \TransactionJournal::withRelevantData() | ||||
|                                     ->defaultSorting() | ||||
|                                     ->account($account) | ||||
|                                     ->accountIs($account) | ||||
|                                     ->after($start) | ||||
|                                     ->before($end); | ||||
|         // filter some: | ||||
| @@ -110,16 +110,16 @@ class Account implements AccountInterface | ||||
|  | ||||
|  | ||||
|         // statistics (transactions) | ||||
|         $trIn   = floatval(\Transaction::before($end)->after($start)->account($account)->moreThan(0) | ||||
|         $trIn   = floatval(\Transaction::before($end)->after($start)->accountIs($account)->moreThan(0) | ||||
|                                        ->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount')); | ||||
|         $trOut  = floatval(\Transaction::before($end)->after($start)->account($account)->lessThan(0) | ||||
|         $trOut  = floatval(\Transaction::before($end)->after($start)->accountIs($account)->lessThan(0) | ||||
|                                        ->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount')); | ||||
|         $trDiff = $trIn + $trOut; | ||||
|  | ||||
|         // statistics (transfers) | ||||
|         $trfIn   = floatval(\Transaction::before($end)->after($start)->account($account)->moreThan(0) | ||||
|         $trfIn   = floatval(\Transaction::before($end)->after($start)->accountIs($account)->moreThan(0) | ||||
|                                         ->transactionTypes(['Transfer'])->sum('transactions.amount')); | ||||
|         $trfOut  = floatval(\Transaction::before($end)->after($start)->account($account)->lessThan(0) | ||||
|         $trfOut  = floatval(\Transaction::before($end)->after($start)->accountIs($account)->lessThan(0) | ||||
|                                         ->transactionTypes(['Transfer'])->sum('transactions.amount')); | ||||
|         $trfDiff = $trfIn + $trfOut; | ||||
|  | ||||
|   | ||||
| @@ -34,7 +34,7 @@ class Budget implements BudgetInterface | ||||
|  | ||||
|                 /** @var \LimitRepetition $repetition */ | ||||
|                 foreach ($limit->limitrepetitions as $repetition) { | ||||
|                     $repetition->left = $repetition->left(); | ||||
|                     $repetition->left = $repetition->leftInRepetition(); | ||||
|                     $periodOrder      = $repetition->periodOrder(); | ||||
|                     $period           = $repetition->periodShow(); | ||||
|                     if (!isset($return[$periodOrder])) { | ||||
|   | ||||
| @@ -102,119 +102,6 @@ class Chart implements ChartInterface | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $start | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function budgets(Carbon $start) | ||||
|     { | ||||
|         // grab all budgets in the time period, like the index does: | ||||
|         // get the budgets for this period: | ||||
|  | ||||
|         $data = []; | ||||
|  | ||||
|         $budgets       = \Auth::user()->budgets()->with( | ||||
|             ['limits'                        => function ($q) { | ||||
|                     $q->orderBy('limits.startdate', 'ASC'); | ||||
|                 }, 'limits.limitrepetitions' => function ($q) use ($start) { | ||||
|                     $q->orderBy('limit_repetitions.startdate', 'ASC'); | ||||
|                     $q->where('startdate', $start->format('Y-m-d')); | ||||
|                 }] | ||||
|         )->orderBy('name', 'ASC')->get(); | ||||
|         $limitInPeriod = ''; | ||||
|         $spentInPeriod = ''; | ||||
|  | ||||
|         /** @var \Budget $budget */ | ||||
|         foreach ($budgets as $budget) { | ||||
|             $budget->count = 0; | ||||
|             foreach ($budget->limits as $limit) { | ||||
|                 /** @var $rep \LimitRepetition */ | ||||
|                 foreach ($limit->limitrepetitions as $index => $rep) { | ||||
|                     if ($index == 0) { | ||||
|                         $limitInPeriod = 'Envelope for ' . $rep->periodShow(); | ||||
|                         $spentInPeriod = 'Spent in ' . $rep->periodShow(); | ||||
|                     } | ||||
|                     $rep->left = $rep->left(); | ||||
|                     // overspent: | ||||
|                     if ($rep->left < 0) { | ||||
|                         $rep->spent         = ($rep->left * -1) + $rep->amount; | ||||
|                         $rep->overspent     = $rep->left * -1; | ||||
|                         $total              = $rep->spent + $rep->overspent; | ||||
|                         $rep->spent_pct     = round(($rep->spent / $total) * 100); | ||||
|                         $rep->overspent_pct = 100 - $rep->spent_pct; | ||||
|                     } else { | ||||
|                         $rep->spent     = $rep->amount - $rep->left; | ||||
|                         $rep->spent_pct = round(($rep->spent / $rep->amount) * 100); | ||||
|                         $rep->left_pct  = 100 - $rep->spent_pct; | ||||
|  | ||||
|  | ||||
|                     } | ||||
|                 } | ||||
|                 $budget->count += count($limit->limitrepetitions); | ||||
|             } | ||||
|             if ($budget->count == 0) { | ||||
|                 // get expenses in period until today, starting at $start. | ||||
|                 $end                   = \Session::get('end'); | ||||
|                 $expenses              = $budget->transactionjournals()->after($start)->before($end) | ||||
|                     ->transactionTypes( | ||||
|                         ['Withdrawal'] | ||||
|                     )->get(); | ||||
|                 $budget->spentInPeriod = 0; | ||||
|                 /** @var \TransactionJournal $expense */ | ||||
|                 foreach ($expenses as $expense) { | ||||
|                     $transaction = $expense->transactions[1]; | ||||
|                     if (!is_null($transaction)) { | ||||
|                         $budget->spentInPeriod += floatval($transaction->amount); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         $data['series'] = [ | ||||
|             [ | ||||
|                 'name' => $limitInPeriod, | ||||
|                 'data' => [] | ||||
|             ], | ||||
|             [ | ||||
|                 'name' => $spentInPeriod, | ||||
|                 'data' => [] | ||||
|             ], | ||||
|         ]; | ||||
|  | ||||
|  | ||||
|         foreach ($budgets as $budget) { | ||||
|             if ($budget->count > 0) { | ||||
|                 $data['labels'][] = $budget->name; | ||||
|                 foreach ($budget->limits as $limit) { | ||||
|                     foreach ($limit->limitrepetitions as $rep) { | ||||
|                         //0: envelope for period: | ||||
|                         $amount                      = floatval($rep->amount); | ||||
|                         $spent                       = $rep->spent; | ||||
|                         $color                       = $spent > $amount ? '#FF0000' : null; | ||||
|                         $data['series'][0]['data'][] = ['y' => $amount, 'id' => 'amount-' . $rep->id]; | ||||
|                         $data['series'][1]['data'][] = ['y'  => $rep->spent, 'color' => $color, | ||||
|                                                         'id' => 'spent-' . $rep->id]; | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 // add for "empty" budget: | ||||
|                 if ($budget->spentInPeriod > 0) { | ||||
|                     $data['labels'][]            = $budget->name; | ||||
|                     $data['series'][0]['data'][] = ['y' => null, 'id' => 'amount-norep-' . $budget->id]; | ||||
|                     $data['series'][1]['data'][] = ['y'  => $budget->spentInPeriod, | ||||
|                                                     'id' => 'spent-norep-' . $budget->id]; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|  | ||||
|         } | ||||
|  | ||||
|         return $data; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|   | ||||
| @@ -30,13 +30,6 @@ interface ChartInterface | ||||
|      */ | ||||
|     public function categories(Carbon $start, Carbon $end); | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $start | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function budgets(Carbon $start); | ||||
|  | ||||
|     /** | ||||
|      * @param \Account $account | ||||
|      * @param Carbon   $date | ||||
|   | ||||
							
								
								
									
										403
									
								
								app/lib/Firefly/Helper/Controllers/Json.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										403
									
								
								app/lib/Firefly/Helper/Controllers/Json.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,403 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Created by PhpStorm. | ||||
|  * User: sander | ||||
|  * Date: 27/09/14 | ||||
|  * Time: 07:39 | ||||
|  */ | ||||
|  | ||||
| namespace Firefly\Helper\Controllers; | ||||
|  | ||||
| use LaravelBook\Ardent\Builder; | ||||
|  | ||||
| /** | ||||
|  * Class Json | ||||
|  * | ||||
|  * @package Firefly\Helper\Controllers | ||||
|  */ | ||||
| class Json implements JsonInterface | ||||
| { | ||||
|     /** | ||||
|      * Grabs all the parameters entered by the DataTables JQuery plugin and creates | ||||
|      * a nice array to be used by the other methods. It's also cleaning up and what-not. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function dataTableParameters() | ||||
|     { | ||||
|         /* | ||||
|          * Process all parameters! | ||||
|          */ | ||||
|         if (intval(\Input::get('length')) < 0) { | ||||
|             $length = 10000; // we get them all if no length is defined. | ||||
|         } else { | ||||
|             $length = intval(\Input::get('length')); | ||||
|         } | ||||
|         $parameters = [ | ||||
|             'start' => intval(\Input::get('start')), | ||||
|             'length' => $length, | ||||
|             'draw' => intval(\Input::get('draw')), | ||||
|         ]; | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * Columns: | ||||
|          */ | ||||
|         if (!is_null(\Input::get('columns')) && is_array(\Input::get('columns'))) { | ||||
|             foreach (\Input::get('columns') as $column) { | ||||
|                 $parameters['columns'][] = [ | ||||
|                     'data' => $column['data'], | ||||
|                     'name' => $column['name'], | ||||
|                     'searchable' => $column['searchable'] == 'true' ? true : false, | ||||
|                     'orderable' => $column['orderable'] == 'true' ? true : false, | ||||
|                     'search' => [ | ||||
|                         'value' => $column['search']['value'], | ||||
|                         'regex' => $column['search']['regex'] == 'true' ? true : false, | ||||
|                     ] | ||||
|                 ]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * Sorting. | ||||
|          */ | ||||
|         $parameters['orderOnAccount'] = false; | ||||
|         if (!is_null(\Input::get('order')) && is_array(\Input::get('order'))) { | ||||
|             foreach (\Input::get('order') as $order) { | ||||
|                 $columnIndex           = intval($order['column']); | ||||
|                 $columnName            = $parameters['columns'][$columnIndex]['name']; | ||||
|                 $parameters['order'][] = [ | ||||
|                     'name' => $columnName, | ||||
|                     'dir' => strtoupper($order['dir']) | ||||
|                 ]; | ||||
|                 if ($columnName == 'to' || $columnName == 'from') { | ||||
|                     $parameters['orderOnAccount'] = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         /* | ||||
|          * Search parameters: | ||||
|          */ | ||||
|         $parameters['search'] = [ | ||||
|             'value' => '', | ||||
|             'regex' => false | ||||
|         ]; | ||||
|         if (!is_null(\Input::get('search')) && is_array(\Input::get('search'))) { | ||||
|             $search               = \Input::get('search'); | ||||
|             $parameters['search'] = [ | ||||
|                 'value' => $search['value'], | ||||
|                 'regex' => $search['regex'] == 'true' ? true : false | ||||
|             ]; | ||||
|         } | ||||
|         return $parameters; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Do some sorting, counting and ordering on the query and return a nicely formatted array | ||||
|      * that can be used by the DataTables JQuery plugin. | ||||
|      * | ||||
|      * @param array $parameters | ||||
|      * @param Builder $query | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function journalDataset(array $parameters, Builder $query) | ||||
|     { | ||||
|         /* | ||||
|          * Count query: | ||||
|          */ | ||||
|         $count = $query->count(); | ||||
|  | ||||
|         /* | ||||
|          * Update the selection: | ||||
|          */ | ||||
|  | ||||
|         $query->take($parameters['length']); | ||||
|         if ($parameters['start'] > 0) { | ||||
|             $query->skip($parameters['start']); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Input search parameters: | ||||
|          */ | ||||
|         $filtered = $count; | ||||
|         if (strlen($parameters['search']['value']) > 0) { | ||||
|             $query->where('transaction_journals.description', 'LIKE', '%' . e($parameters['search']['value']) . '%'); | ||||
|             $filtered = $query->count(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * Build return array: | ||||
|          */ | ||||
|         $data = [ | ||||
|             'draw' => $parameters['draw'], | ||||
|             'recordsTotal' => $count, | ||||
|             'recordsFiltered' => $filtered, | ||||
|             'data' => [], | ||||
|  | ||||
|         ]; | ||||
|  | ||||
|         /* | ||||
|          * Get paginated result set: | ||||
|          */ | ||||
|         if ($parameters['orderOnAccount'] === true) { | ||||
|             /** @var Collection $set */ | ||||
|             $set = $query->get( | ||||
|                 [ | ||||
|                     'transaction_journals.*', | ||||
|                     't1.amount', | ||||
|                     't1.account_id AS from_id', | ||||
|                     'a1.name AS from', | ||||
|                     't2.account_id AS to_id', | ||||
|                     'a2.name AS to', | ||||
|                 ] | ||||
|             ); | ||||
|         } else { | ||||
|             /** @var Collection $set */ | ||||
|             $set = $query->get( | ||||
|                 [ | ||||
|                     'transaction_journals.*', | ||||
|                     'transactions.amount', | ||||
|                 ] | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Loop set and create entries to return. | ||||
|          */ | ||||
|         /** @var \TransactionJournal $entry */ | ||||
|         foreach ($set as $entry) { | ||||
|             $from      = $entry->transactions[0]->account; | ||||
|             $to        = $entry->transactions[1]->account; | ||||
|             $budget    = $entry->budgets()->first(); | ||||
|             $category  = $entry->categories()->first(); | ||||
|             $recurring = $entry->recurringTransaction()->first(); | ||||
|             $arr       = [ | ||||
|                 'date' => $entry->date->format('j F Y'), | ||||
|                 'description' => [ | ||||
|                     'description' => $entry->description, | ||||
|                     'url' => route('transactions.show', $entry->id) | ||||
|                 ], | ||||
|                 'amount' => floatval($entry->amount), | ||||
|                 'from' => ['name' => $from->name, 'url' => route('accounts.show', $from->id)], | ||||
|                 'to' => ['name' => $to->name, 'url' => route('accounts.show', $to->id)], | ||||
|                 'components' => [ | ||||
|                     'budget_id' => 0, | ||||
|                     'budget_url' => '', | ||||
|                     'budget_name' => '', | ||||
|                     'category_id' => 0, | ||||
|                     'category_url' => '', | ||||
|                     'category_name' => '' | ||||
|                 ], | ||||
|                 'id' => [ | ||||
|                     'edit' => route('transactions.edit', $entry->id), | ||||
|                     'delete' => route('transactions.delete', $entry->id) | ||||
|                 ] | ||||
|             ]; | ||||
|             if ($budget) { | ||||
|                 $arr['components']['budget_id']   = $budget->id; | ||||
|                 $arr['components']['budget_name'] = $budget->name; | ||||
|                 $arr['components']['budget_url']  = route('budgets.show', $budget->id); | ||||
|             } | ||||
|             if ($category) { | ||||
|                 $arr['components']['category_id']   = $category->id; | ||||
|                 $arr['components']['category_name'] = $category->name; | ||||
|                 $arr['components']['category_url']  = route('categories.show', $category->id); | ||||
|             } | ||||
|             if ($recurring) { | ||||
|                 $arr['components']['recurring_id']   = $recurring->id; | ||||
|                 $arr['components']['recurring_name'] = e($recurring->name); | ||||
|                 $arr['components']['recurring_url']  = route('recurring.show', $recurring->id); | ||||
|             } | ||||
|  | ||||
|             $data['data'][] = $arr; | ||||
|  | ||||
|         } | ||||
|         return $data; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Builds most of the query required to grab transaction journals from the database. | ||||
|      * This is useful because all three pages showing different kinds of transactions use | ||||
|      * the exact same query with only slight differences. | ||||
|      * | ||||
|      * @param array $parameters | ||||
|      * | ||||
|      * @return Builder | ||||
|      */ | ||||
|     public function journalQuery(array $parameters) | ||||
|     { | ||||
|         /* | ||||
|          * We need the following vars to fine tune the query: | ||||
|          */ | ||||
|         if ($parameters['amount'] == 'negative') { | ||||
|             $operator        = '<'; | ||||
|             $operatorNegated = '>'; | ||||
|             $function        = 'lessThan'; | ||||
|         } else { | ||||
|             $operator        = '>'; | ||||
|             $operatorNegated = '<'; | ||||
|             $function        = 'moreThan'; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Build query: | ||||
|          */ | ||||
|         $query = \TransactionJournal::transactionTypes($parameters['transactionTypes'])->withRelevantData(); | ||||
|         $query->where('user_id', \Auth::user()->id); | ||||
|         $query->where('completed', 1); | ||||
|         /* | ||||
|          * This is complex. Join `transactions` twice, once for the "to" account and once for the | ||||
|          * "from" account. Then get the amount from one of these (depends on type). | ||||
|          * | ||||
|          * Only need to do this when there's a sort order for "from" or "to". | ||||
|          * | ||||
|          * Also need the table prefix for this to work. | ||||
|          */ | ||||
|         if ($parameters['orderOnAccount'] === true) { | ||||
|             $connection = \Config::get('database.default'); | ||||
|             $prefix     = \Config::get('database.connections.' . $connection . '.prefix'); | ||||
|             // left join first table for "from" account: | ||||
|             $query->leftJoin( | ||||
|                 'transactions AS ' . $prefix . 't1', function ($join) use ($operator) { | ||||
|                     $join->on('t1.transaction_journal_id', '=', 'transaction_journals.id') | ||||
|                          ->on('t1.amount', $operator, \DB::Raw(0)); | ||||
|                 } | ||||
|             ); | ||||
|             // left join second table for "to" account: | ||||
|             $query->leftJoin( | ||||
|                 'transactions AS ' . $prefix . 't2', function ($join) use ($operatorNegated) { | ||||
|                     $join->on('t2.transaction_journal_id', '=', 'transaction_journals.id') | ||||
|                          ->on('t2.amount', $operatorNegated, \DB::Raw(0)); | ||||
|                 } | ||||
|             ); | ||||
|  | ||||
|             // also join accounts twice to get the account's name, which we need for sorting. | ||||
|             $query->leftJoin('accounts as ' . $prefix . 'a1', 'a1.id', '=', 't1.account_id'); | ||||
|             $query->leftJoin('accounts as ' . $prefix . 'a2', 'a2.id', '=', 't2.account_id'); | ||||
|         } else { | ||||
|             // less complex | ||||
|             $query->$function(0); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Add sort parameters to query: | ||||
|          */ | ||||
|         if (isset($parameters['order']) && count($parameters['order']) > 0) { | ||||
|             foreach ($parameters['order'] as $order) { | ||||
|                 $query->orderBy($order['name'], $order['dir']); | ||||
|             } | ||||
|         } else { | ||||
|             $query->defaultSorting(); | ||||
|         } | ||||
|         return $query; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Do some sorting, counting and ordering on the query and return a nicely formatted array | ||||
|      * that can be used by the DataTables JQuery plugin. | ||||
|      * | ||||
|      * @param array $parameters | ||||
|      * @param Builder $query | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function recurringTransactionsDataset(array $parameters, Builder $query) | ||||
|     { | ||||
|         /* | ||||
|  * Count query: | ||||
|  */ | ||||
|         $count = $query->count(); | ||||
|  | ||||
|         /* | ||||
|          * Update the selection: | ||||
|          */ | ||||
|  | ||||
|         $query->take($parameters['length']); | ||||
|         if ($parameters['start'] > 0) { | ||||
|             $query->skip($parameters['start']); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Input search parameters: | ||||
|          */ | ||||
|         $filtered = $count; | ||||
|         if (strlen($parameters['search']['value']) > 0) { | ||||
|             $query->where('recurring_transactions.description', 'LIKE', '%' . e($parameters['search']['value']) . '%'); | ||||
|             $filtered = $query->count(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * Build return array: | ||||
|          */ | ||||
|         $data = [ | ||||
|             'draw' => $parameters['draw'], | ||||
|             'recordsTotal' => $count, | ||||
|             'recordsFiltered' => $filtered, | ||||
|             'data' => [], | ||||
|  | ||||
|         ]; | ||||
|  | ||||
|         /* | ||||
|          * Get paginated result set: | ||||
|          */ | ||||
|         /** @var Collection $set */ | ||||
|         $set = $query->get( | ||||
|             [ | ||||
|                 'recurring_transactions.*', | ||||
|             ] | ||||
|         ); | ||||
|  | ||||
|         /* | ||||
|          * Loop set and create entries to return. | ||||
|          */ | ||||
|         foreach ($set as $entry) { | ||||
|             $set = [ | ||||
|  | ||||
|                 'name' => ['name' => $entry->name, 'url' => route('recurring.show', $entry->id)], | ||||
|                 'match' => explode(' ', $entry->match), | ||||
|                 'amount_max' => floatval($entry->amount_max), | ||||
|                 'amount_min' => floatval($entry->amount_min), | ||||
|                 'date' => $entry->date->format('j F Y'), | ||||
|                 'active' => intval($entry->active), | ||||
|                 'automatch' => intval($entry->automatch), | ||||
|                 'repeat_freq' => $entry->repeat_freq, | ||||
|                 'id' => [ | ||||
|                     'edit' => route('recurring.edit', $entry->id), | ||||
|                     'delete' => route('recurring.delete', $entry->id) | ||||
|                 ] | ||||
|             ]; | ||||
|             if (intval($entry->skip) > 0) { | ||||
|                 $set['repeat_freq'] = $entry->repeat_freq . ' (skip ' . $entry->skip . ')'; | ||||
|             } | ||||
|             $data['data'][] = $set; | ||||
|  | ||||
|  | ||||
|         } | ||||
|         return $data; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create a query that will pick up all recurring transactions from the database. | ||||
|      * | ||||
|      * @param array $parameters | ||||
|      * | ||||
|      * @return Builder | ||||
|      */ | ||||
|     public function recurringTransactionsQuery(array $parameters) | ||||
|     { | ||||
|         $query = \RecurringTransaction::where('user_id', \Auth::user()->id); | ||||
|  | ||||
|         if (isset($parameters['order']) && count($parameters['order']) > 0) { | ||||
|             foreach ($parameters['order'] as $order) { | ||||
|                 $query->orderBy($order['name'], $order['dir']); | ||||
|             } | ||||
|         } else { | ||||
|             $query->orderBy('name', 'ASC'); | ||||
|         } | ||||
|         return $query; | ||||
|     } | ||||
| }  | ||||
							
								
								
									
										64
									
								
								app/lib/Firefly/Helper/Controllers/JsonInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								app/lib/Firefly/Helper/Controllers/JsonInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Firefly\Helper\Controllers; | ||||
|  | ||||
| use LaravelBook\Ardent\Builder; | ||||
|  | ||||
| /** | ||||
|  * Interface JsonInterface | ||||
|  * | ||||
|  * @package Firefly\Helper\Controllers | ||||
|  */ | ||||
| interface JsonInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * Grabs all the parameters entered by the DataTables JQuery plugin and creates | ||||
|      * a nice array to be used by the other methods. It's also cleaning up and what-not. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function dataTableParameters(); | ||||
|  | ||||
|     /** | ||||
|      * Do some sorting, counting and ordering on the query and return a nicely formatted array | ||||
|      * that can be used by the DataTables JQuery plugin. | ||||
|      * | ||||
|      * @param array   $parameters | ||||
|      * @param Builder $query | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function journalDataset(array $parameters, Builder $query); | ||||
|  | ||||
|     /** | ||||
|      * Builds most of the query required to grab transaction journals from the database. | ||||
|      * This is useful because all three pages showing different kinds of transactions use | ||||
|      * the exact same query with only slight differences. | ||||
|      * | ||||
|      * @param array $parameters | ||||
|      * | ||||
|      * @return Builder | ||||
|      */ | ||||
|     public function journalQuery(array $parameters); | ||||
|  | ||||
|     /** | ||||
|      * Do some sorting, counting and ordering on the query and return a nicely formatted array | ||||
|      * that can be used by the DataTables JQuery plugin. | ||||
|      * | ||||
|      * @param array   $parameters | ||||
|      * @param Builder $query | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function recurringTransactionsDataset(array $parameters, Builder $query); | ||||
|  | ||||
|     /** | ||||
|      * Create a query that will pick up all recurring transactions from the database. | ||||
|      * | ||||
|      * @param array $parameters | ||||
|      * | ||||
|      * @return Builder | ||||
|      */ | ||||
|     public function recurringTransactionsQuery(array $parameters); | ||||
| }  | ||||
							
								
								
									
										120
									
								
								app/lib/Firefly/Helper/Controllers/Recurring.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								app/lib/Firefly/Helper/Controllers/Recurring.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Firefly\Helper\Controllers; | ||||
|  | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Exception; | ||||
| use Illuminate\Support\MessageBag; | ||||
|  | ||||
| class Recurring implements RecurringInterface | ||||
| { | ||||
|     /** | ||||
|      * Returns messages about the validation. | ||||
|      * | ||||
|      * @param array $data | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function validate(array $data) | ||||
|     { | ||||
|         $errors = new MessageBag; | ||||
|         $warnings = new MessageBag; | ||||
|         $successes = new MessageBag; | ||||
|  | ||||
|         /* | ||||
|          * Name: | ||||
|          */ | ||||
|         if (strlen($data['name']) == 0) { | ||||
|             $errors->add('name', 'The name should not be this short.'); | ||||
|         } | ||||
|         if (strlen($data['name']) > 250) { | ||||
|             $errors->add('name', 'The name should not be this long.'); | ||||
|         } | ||||
|         if (!   isset($data['id'])) { | ||||
|             $count = \Auth::user()->recurringtransactions()->whereName($data['name'])->count(); | ||||
|         } else { | ||||
|             $count = \Auth::user()->recurringtransactions()->whereName($data['name'])->where('id', '!=', $data['id'])->count(); | ||||
|         } | ||||
|         if ($count > 0) { | ||||
|             $errors->add('name', 'A recurring transaction with this name already exists.'); | ||||
|         } | ||||
|         if (count($errors->get('name')) == 0) { | ||||
|             $successes->add('name', 'OK!'); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Match | ||||
|          */ | ||||
|         if (count(explode(',', $data['match'])) > 10) { | ||||
|             $warnings->add('match', 'This many matches is pretty pointless'); | ||||
|         } | ||||
|         if (strlen($data['match']) == 0) { | ||||
|             $errors->add('match', 'Cannot match on nothing.'); | ||||
|         } | ||||
|         if (count($errors->get('match')) == 0) { | ||||
|             $successes->add('match', 'OK!'); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Amount | ||||
|          */ | ||||
|         if (floatval($data['amount_max']) == 0 && floatval($data['amount_min']) == 0) { | ||||
|             $errors->add('amount_min', 'Amount max and min cannot both be zero.'); | ||||
|             $errors->add('amount_max', 'Amount max and min cannot both be zero.'); | ||||
|         } | ||||
|  | ||||
|         if (floatval($data['amount_max']) < floatval($data['amount_min'])) { | ||||
|             $errors->add('amount_max', 'Amount max must be more than amount min.'); | ||||
|         } | ||||
|  | ||||
|         if (floatval($data['amount_min']) > floatval($data['amount_max'])) { | ||||
|             $errors->add('amount_max', 'Amount min must be less than amount max.'); | ||||
|         } | ||||
|         if (count($errors->get('amount_min')) == 0) { | ||||
|             $successes->add('amount_min', 'OK!'); | ||||
|         } | ||||
|         if (count($errors->get('amount_max')) == 0) { | ||||
|             $successes->add('amount_max', 'OK!'); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * Date | ||||
|          */ | ||||
|         try { | ||||
|             $date = new Carbon($data['date']); | ||||
|         } catch (Exception $e) { | ||||
|             $errors->add('date', 'The date entered was invalid'); | ||||
|         } | ||||
|         if (strlen($data['date']) == 0) { | ||||
|             $errors->add('date', 'The date entered was invalid'); | ||||
|         } | ||||
|         if (!$errors->has('date')) { | ||||
|             $successes->add('date', 'OK!'); | ||||
|         } | ||||
|  | ||||
|         $successes->add('active', 'OK!'); | ||||
|         $successes->add('automatch', 'OK!'); | ||||
|  | ||||
|         if (intval($data['skip']) < 0) { | ||||
|             $errors->add('skip', 'Cannot be below zero.'); | ||||
|         } else if (intval($data['skip']) > 31) { | ||||
|             $errors->add('skip', 'Cannot be above 31.'); | ||||
|         } | ||||
|         if (count($errors->get('skip')) == 0) { | ||||
|             $successes->add('skip', 'OK!'); | ||||
|         } | ||||
|  | ||||
|         $set = \Config::get('firefly.budget_periods'); | ||||
|         if (!in_array($data['repeat_freq'], $set)) { | ||||
|             $errors->add('repeat_freq', 'Invalid value.'); | ||||
|         } | ||||
|         if (count($errors->get('repeat_freq')) == 0) { | ||||
|             $successes->add('repeat_freq', 'OK!'); | ||||
|         } | ||||
|  | ||||
|         return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; | ||||
|  | ||||
|     } | ||||
| }  | ||||
							
								
								
									
										15
									
								
								app/lib/Firefly/Helper/Controllers/RecurringInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/lib/Firefly/Helper/Controllers/RecurringInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Firefly\Helper\Controllers; | ||||
|  | ||||
|  | ||||
| interface RecurringInterface { | ||||
|     /** | ||||
|      * Returns messages about the validation. | ||||
|      * | ||||
|      * @param array $data | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function validate(array $data); | ||||
| }  | ||||
							
								
								
									
										101
									
								
								app/lib/Firefly/Helper/Controllers/Search.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								app/lib/Firefly/Helper/Controllers/Search.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| <?php | ||||
| namespace Firefly\Helper\Controllers; | ||||
|  | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
| /** | ||||
|  * Class Search | ||||
|  * | ||||
|  * @package Firefly\Helper\Controllers | ||||
|  */ | ||||
| class Search implements SearchInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * @param array $words | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function searchTransactions(array $words) | ||||
|     { | ||||
|         return \Auth::user()->transactionjournals()->withRelevantData()->where( | ||||
|             function ($q) use ($words) { | ||||
|                 foreach ($words as $word) { | ||||
|                     $q->orWhere('description', 'LIKE', '%' . e($word) . '%'); | ||||
|                 } | ||||
|             } | ||||
|         )->get(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param array $words | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function searchAccounts(array $words) | ||||
|     { | ||||
|         return \Auth::user()->accounts()->with('accounttype')->where( | ||||
|             function ($q) use ($words) { | ||||
|                 foreach ($words as $word) { | ||||
|                     $q->orWhere('name', 'LIKE', '%' . e($word) . '%'); | ||||
|                 } | ||||
|             } | ||||
|         )->get(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param array $words | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function searchCategories(array $words) | ||||
|     { | ||||
|         /** @var Collection $set */ | ||||
|         $set = \Auth::user()->categories()->get(); | ||||
|         $newSet = $set->filter( | ||||
|             function (\Category $c) use ($words) { | ||||
|                 $found = 0; | ||||
|                 foreach ($words as $word) { | ||||
|                     if (!(strpos(strtolower($c->name), strtolower($word)) === false)) { | ||||
|                         $found++; | ||||
|                     } | ||||
|                 } | ||||
|                 return $found > 0; | ||||
|             } | ||||
|         ); | ||||
|         return $newSet; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param array $words | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function searchBudgets(array $words) | ||||
|     { | ||||
|         /** @var Collection $set */ | ||||
|         $set = \Auth::user()->budgets()->get(); | ||||
|         $newSet = $set->filter( | ||||
|             function (\Budget $b) use ($words) { | ||||
|                 $found = 0; | ||||
|                 foreach ($words as $word) { | ||||
|                     if (!(strpos(strtolower($b->name), strtolower($word)) === false)) { | ||||
|                         $found++; | ||||
|                     } | ||||
|                 } | ||||
|                 return $found > 0; | ||||
|             } | ||||
|         ); | ||||
|         return $newSet; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param array $words | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function searchTags(array $words) | ||||
|     { | ||||
|         return new Collection; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										36
									
								
								app/lib/Firefly/Helper/Controllers/SearchInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								app/lib/Firefly/Helper/Controllers/SearchInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| <?php | ||||
| namespace Firefly\Helper\Controllers; | ||||
|  | ||||
| /** | ||||
|  * Interface SearchInterface | ||||
|  * | ||||
|  * @package Firefly\Helper\Controllers | ||||
|  */ | ||||
| interface SearchInterface | ||||
| { | ||||
|     /** | ||||
|      * @param array $words | ||||
|      */ | ||||
|     public function searchTransactions(array $words); | ||||
|  | ||||
|     /** | ||||
|      * @param array $words | ||||
|      */ | ||||
|     public function searchAccounts(array $words); | ||||
|  | ||||
|     /** | ||||
|      * @param array $words | ||||
|      */ | ||||
|     public function searchCategories(array $words); | ||||
|  | ||||
|     /** | ||||
|      * @param array $words | ||||
|      */ | ||||
|     public function searchBudgets(array $words); | ||||
|  | ||||
|     /** | ||||
|      * @param array $words | ||||
|      */ | ||||
|     public function searchTags(array $words); | ||||
|  | ||||
| } | ||||
							
								
								
									
										485
									
								
								app/lib/Firefly/Helper/Controllers/Transaction.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										485
									
								
								app/lib/Firefly/Helper/Controllers/Transaction.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,485 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Firefly\Helper\Controllers; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Exception; | ||||
| use Firefly\Exception\FireflyException; | ||||
| use Firefly\Storage\Account\AccountRepositoryInterface as ARI; | ||||
| use Firefly\Storage\Budget\BudgetRepositoryInterface as BRI; | ||||
| use Firefly\Storage\Category\CategoryRepositoryInterface as CRI; | ||||
| use Firefly\Storage\Piggybank\PiggybankRepositoryInterface as PRI; | ||||
| use Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface as TJRI; | ||||
| use Illuminate\Support\MessageBag; | ||||
|  | ||||
| /** | ||||
|  * Class Transaction | ||||
|  * | ||||
|  * @package Firefly\Helper\Controllers | ||||
|  */ | ||||
| class Transaction implements TransactionInterface | ||||
| { | ||||
|     protected $_user = null; | ||||
|  | ||||
|     /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $_journals */ | ||||
|     protected $_journals; | ||||
|  | ||||
|     /** @var \Firefly\Storage\Category\CategoryRepositoryInterface $_categories */ | ||||
|     protected $_categories; | ||||
|  | ||||
|     /** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $_budgets */ | ||||
|     protected $_budgets; | ||||
|  | ||||
|     /** @var \Firefly\Storage\Piggybank\PiggybankRepositoryInterface $_piggybanks */ | ||||
|     protected $_piggybanks; | ||||
|  | ||||
|     /** @var \Firefly\Storage\Account\AccountRepositoryInterface $_accounts */ | ||||
|     protected $_accounts; | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * @param TJRI $journals | ||||
|      * @param CRI $categories | ||||
|      * @param BRI $budgets | ||||
|      * @param PRI $piggybanks | ||||
|      * @param ARI $accounts | ||||
|      */ | ||||
|     public function __construct(TJRI $journals, CRI $categories, BRI $budgets, PRI $piggybanks, ARI $accounts) | ||||
|     { | ||||
|         $this->_journals = $journals; | ||||
|         $this->_categories = $categories; | ||||
|         $this->_budgets = $budgets; | ||||
|         $this->_piggybanks = $piggybanks; | ||||
|         $this->_accounts = $accounts; | ||||
|         $this->overruleUser(\Auth::user()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
|     { | ||||
|         $this->_user = $user; | ||||
|         $this->_journals->overruleUser($user); | ||||
|         $this->_categories->overruleUser($user); | ||||
|         $this->_budgets->overruleUser($user); | ||||
|         $this->_piggybanks->overruleUser($user); | ||||
|         $this->_accounts->overruleUser($user); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \TransactionJournal $journal | ||||
|      * @param array $data | ||||
|      * | ||||
|      * @return MessageBag|\TransactionJournal | ||||
|      */ | ||||
|     public function update(\TransactionJournal $journal, array $data) | ||||
|     { | ||||
|         /* | ||||
|          * Update the journal using the repository. | ||||
|          */ | ||||
|         $journal = $this->_journals->update($journal, $data); | ||||
|  | ||||
|         /* | ||||
|          * If invalid, return the message bag: | ||||
|          */ | ||||
|         if (!$journal->validate()) { | ||||
|             return $journal->errors(); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * find budget using repository | ||||
|          */ | ||||
|  | ||||
|         if (isset($data['budget_id'])) { | ||||
|             $budget = $this->_budgets->find($data['budget_id']); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * find category using repository | ||||
|          */ | ||||
|         $category = $this->_categories->firstOrCreate($data['category']); | ||||
|  | ||||
|         /* | ||||
|          * Find piggy bank using repository: | ||||
|          */ | ||||
|         $piggybank = null; | ||||
|         if (isset($data['piggybank_id'])) { | ||||
|             $piggybank = $this->_piggybanks->find($data['piggybank_id']); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * save accounts using repositories | ||||
|          * this depends on the kind of transaction and i've yet to fix this. | ||||
|          */ | ||||
|  | ||||
|         if (isset($data['account_id'])) { | ||||
|             $from = $this->_accounts->findAssetAccountById($data['account_id']); | ||||
|         } | ||||
|         if (isset($data['expense_account'])) { | ||||
|             $to = $this->_accounts->findExpenseAccountByName($data['expense_account']); | ||||
|         } | ||||
|         if (isset($data['revenue_account'])) { | ||||
|             $from = $this->_accounts->findRevenueAccountByName($data['revenue_account']); | ||||
|             $to = $this->_accounts->findAssetAccountById($data['account_id']); | ||||
|         } | ||||
|         if (isset($data['account_from_id'])) { | ||||
|             $from = $this->_accounts->findAssetAccountById($data['account_from_id']); | ||||
|         } | ||||
|         if (isset($data['account_to_id'])) { | ||||
|             $to = $this->_accounts->findAssetAccountById($data['account_to_id']); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * Add a custom error when they are the same. | ||||
|          */ | ||||
|         if ($to->id == $from->id) { | ||||
|             $bag = new MessageBag; | ||||
|             $bag->add('account_from_id', 'The account from cannot be the same as the account to.'); | ||||
|             return $bag; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Check if the transactions need new data: | ||||
|          */ | ||||
|         $transactions = $journal->transactions()->orderBy('amount', 'ASC')->get(); | ||||
|         /** @var \Transaction $transaction */ | ||||
|         foreach ($transactions as $index => $transaction) { | ||||
|             switch (true) { | ||||
|                 case ($index == 0): // FROM account | ||||
|                     $transaction->account()->associate($from); | ||||
|                     $transaction->amount = floatval($data['amount']) * -1; | ||||
|                     break; | ||||
|                 case ($index == 1): // TO account. | ||||
|                     $transaction->account()->associate($to); | ||||
|                     $transaction->amount = floatval($data['amount']); | ||||
|                     break; | ||||
|             } | ||||
|             $transaction->save(); | ||||
|             // either way, try to attach the piggy bank: | ||||
|             if (!is_null($piggybank)) { | ||||
|                 if ($piggybank->account_id == $transaction->account_id) { | ||||
|                     $transaction->piggybank()->associate($piggybank); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Connect budget and category: | ||||
|          */ | ||||
|         $budgetids = !isset($budget) || (isset($budget) && is_null($budget)) ? [] : [$budget->id]; | ||||
|         $catids = is_null($category) ? [] : [$category->id]; | ||||
|         $components = array_merge($budgetids,$catids); | ||||
|         $journal->components()->sync($components); | ||||
|         $journal->save(); | ||||
|  | ||||
|         if (isset($data['return_journal']) && $data['return_journal'] == true) { | ||||
|             return $journal; | ||||
|         } | ||||
|         return $journal->errors(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns messages about the validation. | ||||
|      * | ||||
|      * @param array $data | ||||
|      * @return array | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public function validate(array $data) | ||||
|     { | ||||
|         $errors = new MessageBag; | ||||
|         $warnings = new MessageBag; | ||||
|         $successes = new MessageBag; | ||||
|  | ||||
|         /* | ||||
|          * Description: | ||||
|          */ | ||||
|         if (strlen($data['description']) == 0) { | ||||
|             $errors->add('description', 'The description should not be this short.'); | ||||
|         } | ||||
|         if (strlen($data['description']) > 250) { | ||||
|             $errors->add('description', 'The description should not be this long.'); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Amount | ||||
|          */ | ||||
|         if (floatval($data['amount']) <= 0) { | ||||
|             $errors->add('amount', 'The amount cannot be zero or less than zero.'); | ||||
|         } | ||||
|         if (floatval($data['amount']) > 10000) { | ||||
|             $warnings->add('amount', 'OK, but that\'s a lot of money dude.'); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Date | ||||
|          */ | ||||
|         try { | ||||
|             $date = new Carbon($data['date']); | ||||
|         } catch (Exception $e) { | ||||
|             $errors->add('date', 'The date entered was invalid'); | ||||
|         } | ||||
|         if (strlen($data['date']) == 0) { | ||||
|             $errors->add('date', 'The date entered was invalid'); | ||||
|         } | ||||
|         if (!$errors->has('date')) { | ||||
|             $successes->add('date', 'OK!'); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Category | ||||
|          */ | ||||
|         $category = $this->_categories->findByName($data['category']); | ||||
|         if (strlen($data['category']) == 0) { | ||||
|             $warnings->add('category', 'No category will be created.'); | ||||
|         } else { | ||||
|             if (is_null($category)) { | ||||
|                 $warnings->add('category', 'Will have to be created.'); | ||||
|             } else { | ||||
|                 $successes->add('category', 'OK!'); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         switch ($data['what']) { | ||||
|             default: | ||||
|                 throw new FireflyException('Cannot validate a ' . $data['what']); | ||||
|                 break; | ||||
|             case 'deposit': | ||||
|                 /* | ||||
|                  * Tests for deposit | ||||
|                  */ | ||||
|                 // asset account | ||||
|                 $accountId = isset($data['account_id']) ? intval($data['account_id']) : 0; | ||||
|                 $account = $this->_accounts->find($accountId); | ||||
|                 if (is_null($account)) { | ||||
|                     $errors->add('account_id', 'Cannot find this asset account.'); | ||||
|                 } else { | ||||
|                     $successes->add('account_id', 'OK!'); | ||||
|                 } | ||||
|  | ||||
|                 // revenue account: | ||||
|                 if (strlen($data['revenue_account']) == 0) { | ||||
|                     $warnings->add('revenue_account', 'Revenue account will be "cash".'); | ||||
|                 } else { | ||||
|                     $exp = $this->_accounts->findRevenueAccountByName($data['revenue_account'], false); | ||||
|                     if (is_null($exp)) { | ||||
|                         $warnings->add('revenue_account', 'Expense account will be created.'); | ||||
|                     } else { | ||||
|                         $successes->add('revenue_account', 'OK!'); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 break; | ||||
|             case 'transfer': | ||||
|                 // account from | ||||
|                 $accountId = isset($data['account_from_id']) ? intval($data['account_from_id']) : 0; | ||||
|                 $account = $this->_accounts->find($accountId); | ||||
|                 if (is_null($account)) { | ||||
|                     $errors->add('account_from_id', 'Cannot find this asset account.'); | ||||
|                 } else { | ||||
|                     $successes->add('account_from_id', 'OK!'); | ||||
|                 } | ||||
|                 unset($accountId); | ||||
|                 // account to | ||||
|                 $accountId = isset($data['account_to_id']) ? intval($data['account_to_id']) : 0; | ||||
|                 $account = $this->_accounts->find($accountId); | ||||
|                 if (is_null($account)) { | ||||
|                     $errors->add('account_to_id', 'Cannot find this asset account.'); | ||||
|                 } else { | ||||
|                     $successes->add('account_to_id', 'OK!'); | ||||
|                 } | ||||
|                 unset($accountId); | ||||
|  | ||||
|                 // piggy bank | ||||
|                 $piggybankId = isset($data['piggybank_id']) ? intval($data['piggybank_id']) : 0; | ||||
|                 $piggybank = $this->_piggybanks->find($piggybankId); | ||||
|                 if (is_null($piggybank)) { | ||||
|                     $warnings->add('piggybank_id', 'No piggy bank will be modified.'); | ||||
|                 } else { | ||||
|                     $successes->add('piggybank_id', 'OK!'); | ||||
|                 } | ||||
|  | ||||
|                 break; | ||||
|             case 'withdrawal': | ||||
|                 /* | ||||
|                  * Tests for withdrawal | ||||
|                  */ | ||||
|                 // asset account | ||||
|                 $accountId = isset($data['account_id']) ? intval($data['account_id']) : 0; | ||||
|                 $account = $this->_accounts->find($accountId); | ||||
|                 if (is_null($account)) { | ||||
|                     $errors->add('account_id', 'Cannot find this asset account.'); | ||||
|                 } else { | ||||
|                     $successes->add('account_id', 'OK!'); | ||||
|                 } | ||||
|  | ||||
|                 // expense account | ||||
|                 if (strlen($data['expense_account']) == 0) { | ||||
|                     $warnings->add('expense_account', 'Expense account will be "cash".'); | ||||
|                 } else { | ||||
|                     $exp = $this->_accounts->findExpenseAccountByName($data['expense_account'], false); | ||||
|                     if (is_null($exp)) { | ||||
|                         $warnings->add('expense_account', 'Expense account will be created.'); | ||||
|                     } else { | ||||
|                         $successes->add('expense_account', 'OK!'); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // budget | ||||
|                 if (!isset($data['budget_id']) || (isset($data['budget_id']) && intval($data['budget_id']) == 0)) { | ||||
|                     $warnings->add('budget_id', 'No budget selected.'); | ||||
|                 } else { | ||||
|                     $budget = $this->_budgets->find(intval($data['budget_id'])); | ||||
|                     if (is_null($budget)) { | ||||
|                         $errors->add('budget_id', 'This budget does not exist'); | ||||
|                     } else { | ||||
|                         $successes->add('budget_id', 'OK!'); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         if (count($errors->get('description')) == 0) { | ||||
|             $successes->add('description', 'OK!'); | ||||
|         } | ||||
|  | ||||
|         if (count($errors->get('amount')) == 0) { | ||||
|             $successes->add('amount', 'OK!'); | ||||
|         } | ||||
|  | ||||
|         return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; | ||||
|         /* | ||||
|          * Tests for deposit | ||||
|          */ | ||||
|         /* | ||||
|          * Tests for transfer | ||||
|          */ | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Store a full transaction journal and associated stuff | ||||
|      * | ||||
|      * @param array $data | ||||
|      * | ||||
|      * @return MessageBag|\TransactionJournal | ||||
|      * | ||||
|      * @SuppressWarnings(PHPMD.ShortVariable) | ||||
|      */ | ||||
|     public function store(array $data) | ||||
|     { | ||||
|         /* | ||||
|          * save journal using repository | ||||
|          */ | ||||
|         $journal = $this->_journals->store($data); | ||||
|  | ||||
|         /* | ||||
|          * If invalid, return the message bag: | ||||
|          */ | ||||
|         if (!$journal->validate()) { | ||||
|             return $journal->errors(); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * find budget using repository | ||||
|          */ | ||||
|         if (isset($data['budget_id'])) { | ||||
|             $budget = $this->_budgets->find($data['budget_id']); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * find category using repository | ||||
|          */ | ||||
|         $category = $this->_categories->firstOrCreate($data['category']); | ||||
|  | ||||
|         /* | ||||
|          * Find piggy bank using repository: | ||||
|          */ | ||||
|         $piggybank = null; | ||||
|         if (isset($data['piggybank_id'])) { | ||||
|             $piggybank = $this->_piggybanks->find($data['piggybank_id']); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * save accounts using repositories | ||||
|          * this depends on the kind of transaction and i've yet to fix this. | ||||
|          */ | ||||
|         if (isset($data['account_id'])) { | ||||
|             $from = $this->_accounts->findAssetAccountById($data['account_id']); | ||||
|         } | ||||
|         if (isset($data['expense_account'])) { | ||||
|             $to = $this->_accounts->findExpenseAccountByName($data['expense_account']); | ||||
|  | ||||
|         } | ||||
|         if (isset($data['revenue_account'])) { | ||||
|             $from = $this->_accounts->findRevenueAccountByName($data['revenue_account']); | ||||
|             $to = $this->_accounts->findAssetAccountById($data['account_id']); | ||||
|         } | ||||
|         if (isset($data['account_from_id'])) { | ||||
|             $from = $this->_accounts->findAssetAccountById($data['account_from_id']); | ||||
|         } | ||||
|         if (isset($data['account_to_id'])) { | ||||
|             $to = $this->_accounts->findAssetAccountById($data['account_to_id']); | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Add a custom error when they are the same. | ||||
|          */ | ||||
|         if ($to->id == $from->id) { | ||||
|             $bag = new MessageBag; | ||||
|             $bag->add('account_from_id', 'The account from cannot be the same as the account to.'); | ||||
|             return $bag; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Save transactions using repository. We try to connect the (possibly existing) | ||||
|          * piggy bank to either transaction, knowing it will only work with one of them. | ||||
|          */ | ||||
|         /** @var \Transaction $one */ | ||||
|         $one = $this->_journals->saveTransaction($journal, $from, floatval($data['amount']) * -1); | ||||
|         $one->connectPiggybank($piggybank); | ||||
|         $two = $this->_journals->saveTransaction($journal, $to, floatval($data['amount'])); | ||||
|         $two->connectPiggybank($piggybank); | ||||
|         /* | ||||
|          * Count for $journal is zero? Then there were errors! | ||||
|          */ | ||||
|         if ($journal->transactions()->count() < 2) { | ||||
|             /* | ||||
|              * Join message bags and return them: | ||||
|              */ | ||||
|             $bag = $one->errors(); | ||||
|             $bag->merge($two->errors()); | ||||
|             return $bag; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Connect budget, category and piggy bank: | ||||
|          */ | ||||
|         if (isset($budget) && !is_null($budget)) { | ||||
|             $journal->budgets()->save($budget); | ||||
|         } | ||||
|         if (!is_null($category)) { | ||||
|             $journal->categories()->save($category); | ||||
|         } | ||||
|         $journal->completed = true; | ||||
|         $journal->save(); | ||||
|  | ||||
|         /* | ||||
|          * Trigger recurring transaction event. | ||||
|          */ | ||||
|         \Event::fire('journals.store',[$journal]); | ||||
|  | ||||
|         if (isset($data['return_journal']) && $data['return_journal'] == true) { | ||||
|             return ['journal' => $journal, 'messagebag' => $journal->errors()]; | ||||
|         } | ||||
|         return $journal->errors(); | ||||
|     } | ||||
|  | ||||
| }  | ||||
							
								
								
									
										48
									
								
								app/lib/Firefly/Helper/Controllers/TransactionInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								app/lib/Firefly/Helper/Controllers/TransactionInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Firefly\Helper\Controllers; | ||||
| use Illuminate\Support\MessageBag; | ||||
|  | ||||
| /** | ||||
|  * Interface TransactionInterface | ||||
|  * | ||||
|  * @package Firefly\Helper\Controllers | ||||
|  */ | ||||
| interface TransactionInterface { | ||||
|  | ||||
|     /** | ||||
|      * Store a full transaction journal and associated stuff | ||||
|      * | ||||
|      * @param array $data | ||||
|      * | ||||
|      * @return MessageBag|\TransactionJournal | ||||
|      */ | ||||
|     public function store(array $data); | ||||
|  | ||||
|     /** | ||||
|      * Returns messages about the validation. | ||||
|      * | ||||
|      * @param array $data | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function validate(array $data); | ||||
|  | ||||
|     /** | ||||
|      * @param \TransactionJournal $journal | ||||
|      * @param array               $data | ||||
|      * | ||||
|      * @return MessageBag|\TransactionJournal | ||||
|      */ | ||||
|     public function update(\TransactionJournal $journal, array $data); | ||||
|  | ||||
|     /** | ||||
|      * Overrule the user used when the class is created. | ||||
|      * | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function overruleUser(\User $user); | ||||
|  | ||||
| }  | ||||
| @@ -26,6 +26,27 @@ class HelperServiceProvider extends ServiceProvider | ||||
|             'Firefly\Helper\Controllers\ChartInterface', | ||||
|             'Firefly\Helper\Controllers\Chart' | ||||
|         ); | ||||
|  | ||||
|         $this->app->bind( | ||||
|             'Firefly\Helper\Controllers\JsonInterface', | ||||
|             'Firefly\Helper\Controllers\Json' | ||||
|         ); | ||||
|  | ||||
|         $this->app->bind( | ||||
|             'Firefly\Helper\Controllers\RecurringInterface', | ||||
|             'Firefly\Helper\Controllers\Recurring' | ||||
|         ); | ||||
|  | ||||
|         $this->app->bind( | ||||
|             'Firefly\Helper\Controllers\SearchInterface', | ||||
|             'Firefly\Helper\Controllers\Search' | ||||
|         ); | ||||
|  | ||||
|         $this->app->bind( | ||||
|             'Firefly\Helper\Controllers\TransactionInterface', | ||||
|             'Firefly\Helper\Controllers\Transaction' | ||||
|         ); | ||||
|  | ||||
|         $this->app->bind( | ||||
|             'Firefly\Helper\Controllers\CategoryInterface', | ||||
|             'Firefly\Helper\Controllers\Category' | ||||
|   | ||||
| @@ -3,140 +3,130 @@ | ||||
| namespace Firefly\Helper\Toolkit; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Illuminate\Http\Request; | ||||
| use Firefly\Exception\FireflyException; | ||||
| use Illuminate\Database\Eloquent\Model; | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
| /** | ||||
|  * Class Toolkit | ||||
|  * | ||||
|  * @package Firefly\Helper\Toolkit | ||||
|  * @SuppressWarnings(PHPMD.CamelCaseMethodName) | ||||
|  * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) | ||||
|  */ | ||||
| class Toolkit implements ToolkitInterface | ||||
| { | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * @param Request $request | ||||
|      * Lots of code in Firefly III still depends on session['start'], session['end'] and | ||||
|      * session['range'] to be available, even though this feature has been removed from Firefly | ||||
|      * in favor of a new reporting feature. This reporting feature can show the user past and future | ||||
|      * date ranges instead of the dashboard (the dashboard always shows "right now"). | ||||
|      * | ||||
|      * @return \Illuminate\Http\RedirectResponse|mixed|null | ||||
|      * The only actual choice the user is left with is the range, which can be changed using the Preferences pane. | ||||
|      * | ||||
|      * The start/end dates are set here, regardless of what the user might want to see. | ||||
|      * | ||||
|      * @return null | ||||
|      */ | ||||
|     public function getDateRange(Request $request) | ||||
|     public function getDateRange() | ||||
|     { | ||||
|         /* | ||||
|          * Get all data from the session: | ||||
|          */ | ||||
|         $range = $this->_getRange(); | ||||
|         $start = $this->_getStartDate(); | ||||
|         $end = $this->_getEndDate(); | ||||
|         #\Log::debug('Range is: ' . $range); | ||||
|         $start = \Session::has('start') ? \Session::get('start') : new Carbon; | ||||
|  | ||||
|         // update start only: | ||||
|         #\Log::debug('Session start is: ' . $start->format('Y-m-d')); | ||||
|         $end = \Session::has('end') ? \Session::get('end') : new Carbon; | ||||
|         #\Log::debug('Session end is  : ' . $end->format('Y-m-d')); | ||||
|  | ||||
|         /* | ||||
|          * Force start date to at the start of the $range. | ||||
|          * Ie. the start of the week, month, year. | ||||
|          */ | ||||
|         $start = $this->_updateStartDate($range, $start); | ||||
|         #\Log::debug('After update, session start is: ' . $start->format('Y-m-d')); | ||||
|  | ||||
|         // update end only: | ||||
|         $end = $this->_updateEndDate($range, $start, $end); | ||||
|         /* | ||||
|          * Force end date to at the END of the $range. Always based on $start. | ||||
|          * Ie. the END of the week, month, year. | ||||
|          */ | ||||
|         $end = $this->_updateEndDate($range, $start); | ||||
|         #\Log::debug('After update, session end is  : ' . $end->format('Y-m-d')); | ||||
|  | ||||
|         if (\Input::get('action') == 'prev') { | ||||
|             $start = $this->_moveStartPrevious($range, $start); | ||||
|             $end = $this->_moveEndPrevious($range, $end); | ||||
|         } | ||||
|         if (\Input::get('action') == 'next') { | ||||
|             $start = $this->_moveStartNext($range, $start); | ||||
|             $end = $this->_moveEndNext($range, $end); | ||||
|         } | ||||
|         /* | ||||
|          * get the name of the month, depending on the range. Purely for astetics | ||||
|          */ | ||||
|         $period = $this->_periodName($range, $start); | ||||
|  | ||||
|         // save in session: | ||||
|         /* | ||||
|          * Get the date for the previous and next period. | ||||
|          * Ie. next week, next month, etc. | ||||
|          */ | ||||
|         $prev = $this->_previous($range, clone $start); | ||||
|         $next = $this->_next($range, clone $start); | ||||
|  | ||||
|         /* | ||||
|          * Save everything in the session: | ||||
|          */ | ||||
|         \Session::put('start', $start); | ||||
|         \Session::put('end', $end); | ||||
|         \Session::put('range', $range); | ||||
|         if (!is_null(\Input::get('action'))) { | ||||
|             return \Redirect::to($request->url()); | ||||
|  | ||||
|         } | ||||
|  | ||||
|         \Session::put('period', $period); | ||||
|         \Session::put('prev', $this->_periodName($range, $prev)); | ||||
|         \Session::put('next', $this->_periodName($range, $next)); | ||||
|         return null; | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array | ||||
|      * | ||||
|      */ | ||||
|     public function getDateRangeDates() | ||||
|     public function checkImportJobs() | ||||
|     { | ||||
|         return [\Session::get('start'), \Session::get('end')]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getReminders() | ||||
|     { | ||||
|         // get reminders, for menu, mumble mumble: | ||||
|         $today = new Carbon; | ||||
|         $reminders = \Auth::user()->reminders()->where('class', 'PiggybankReminder')->validOn($today)->get(); | ||||
|  | ||||
|         /** @var \Reminder $reminder */ | ||||
|         foreach ($reminders as $index => $reminder) { | ||||
|             if (\Session::has('dismissal-' . $reminder->id)) { | ||||
|                 $time = \Session::get('dismissal-' . $reminder->id); | ||||
|                 if ($time >= $today) { | ||||
|                     unset($reminders[$index]); | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         } | ||||
|         \Session::put('reminderCount', count($reminders)); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     protected function _getrange() | ||||
|     { | ||||
|         if (!is_null(\Input::get('range'))) { | ||||
|             $range = \Input::get('range'); | ||||
|         /* | ||||
|          * Get all jobs. | ||||
|          */ | ||||
|         /** @var \Importmap $importJob */ | ||||
|         $importJob = \Importmap::where('user_id', \Auth::user()->id) | ||||
|                                ->where('totaljobs', '>', \DB::Raw('`jobsdone`')) | ||||
|                                ->orderBy('created_at', 'DESC') | ||||
|                                ->first(); | ||||
|         if (!is_null($importJob)) { | ||||
|             $diff  = intval($importJob->totaljobs) - intval($importJob->jobsdone); | ||||
|             $date  = new Carbon; | ||||
|             $today = new Carbon; | ||||
|             $date->addSeconds($diff); | ||||
|             \Session::put('job_pct', $importJob->pct()); | ||||
|             \Session::put('job_text', $date->diffForHumans()); | ||||
|         } else { | ||||
|             if (!is_null(\Session::get('range'))) { | ||||
|                 $range = \Session::get('range'); | ||||
|             } else { | ||||
|                 /** @noinspection PhpUndefinedClassInspection */ | ||||
|                 $preferences = \App::make('Firefly\Helper\Preferences\PreferencesHelperInterface'); | ||||
|                 $viewRange = $preferences->get('viewRange', '1M'); | ||||
|  | ||||
|                 // default range: | ||||
|                 $range = $viewRange->data; | ||||
|             } | ||||
|             \Session::forget('job_pct'); | ||||
|             \Session::forget('job_text'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     protected function _getRange() | ||||
|     { | ||||
|         if (!is_null(\Session::get('range'))) { | ||||
|             $range = \Session::get('range'); | ||||
|         } else { | ||||
|             /** @noinspection PhpUndefinedClassInspection */ | ||||
|             $preferences = \App::make('Firefly\Helper\Preferences\PreferencesHelperInterface'); | ||||
|             $viewRange   = $preferences->get('viewRange', '1M'); | ||||
|  | ||||
|             // default range: | ||||
|             $range = $viewRange->data; | ||||
|             \Session::put('range', $range); | ||||
|         } | ||||
|         return $range; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Carbon|mixed | ||||
|      */ | ||||
|     protected function _getStartDate() | ||||
|     { | ||||
|         $start = \Session::has('start') ? \Session::get('start') : new Carbon; | ||||
|         if (\Input::get('start') && \Input::get('end')) { | ||||
|             $start = new Carbon(\Input::get('start')); | ||||
|         } | ||||
|  | ||||
|         return $start; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Carbon|mixed | ||||
|      */ | ||||
|     protected function _getEndDate() | ||||
|     { | ||||
|         $end = \Session::has('end') ? \Session::get('end') : new Carbon; | ||||
|         if (\Input::get('start') && \Input::get('end')) { | ||||
|             $end = new Carbon(\Input::get('end')); | ||||
|         } | ||||
|  | ||||
|         return $end; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param        $range | ||||
|      * @param Carbon $start | ||||
| @@ -145,7 +135,6 @@ class Toolkit implements ToolkitInterface | ||||
|      */ | ||||
|     protected function _updateStartDate($range, Carbon $start) | ||||
|     { | ||||
|         $today = new Carbon; | ||||
|         switch ($range) { | ||||
|             case '1D': | ||||
|                 $start->startOfDay(); | ||||
| @@ -160,12 +149,15 @@ class Toolkit implements ToolkitInterface | ||||
|                 $start->firstOfQuarter(); | ||||
|                 break; | ||||
|             case '6M': | ||||
|                 if (intval($today->format('m')) >= 7) { | ||||
|                 if (intval($start->format('m')) >= 7) { | ||||
|                     $start->startOfYear()->addMonths(6); | ||||
|                 } else { | ||||
|                     $start->startOfYear(); | ||||
|                 } | ||||
|                 break; | ||||
|             case '1Y': | ||||
|                 $start->startOfYear(); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         return $start; | ||||
| @@ -179,150 +171,337 @@ class Toolkit implements ToolkitInterface | ||||
|      * | ||||
|      * @return Carbon | ||||
|      */ | ||||
|     protected function _updateEndDate($range, Carbon $start, Carbon $end) | ||||
|     protected function _updateEndDate($range, Carbon $start) | ||||
|     { | ||||
|         $today = new Carbon; | ||||
|         $end = clone $start; | ||||
|         switch ($range) { | ||||
|             default: | ||||
|                 throw new FireflyException('_updateEndDate cannot handle $range ' . $range); | ||||
|                 break; | ||||
|             case '1D': | ||||
|                 $end = clone $start; | ||||
|                 $end->endOfDay(); | ||||
|                 break; | ||||
|             case '1W': | ||||
|                 $end = clone $start; | ||||
|                 $end->endOfWeek(); | ||||
|                 break; | ||||
|             case '1M': | ||||
|                 $end = clone $start; | ||||
|                 $end->endOfMonth(); | ||||
|                 break; | ||||
|             case '3M': | ||||
|                 $end = clone $start; | ||||
|                 $end->lastOfQuarter(); | ||||
|                 break; | ||||
|             case '6M': | ||||
|                 $end = clone $start; | ||||
|                 if (intval($today->format('m')) >= 7) { | ||||
|                 if (intval($start->format('m')) >= 7) { | ||||
|                     $end->endOfYear(); | ||||
|                 } else { | ||||
|                     $end->startOfYear()->addMonths(6); | ||||
|                 } | ||||
|                 break; | ||||
|             case '1Y': | ||||
|                 $end->endOfYear(); | ||||
|                 break; | ||||
|  | ||||
|         } | ||||
|  | ||||
|         return $end; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param        $range | ||||
|      * @param Carbon $start | ||||
|      * | ||||
|      * @return Carbon | ||||
|      */ | ||||
|     protected function _moveStartPrevious($range, Carbon $start) | ||||
|     protected function _periodName($range, Carbon $date) | ||||
|     { | ||||
|         switch ($range) { | ||||
|             default: | ||||
|                 throw new FireflyException('No _periodName() for range "' . $range . '"'); | ||||
|                 break; | ||||
|             case '1D': | ||||
|                 return $date->format('jS F Y'); | ||||
|                 break; | ||||
|             case '1W': | ||||
|                 return 'week ' . $date->format('W, Y'); | ||||
|                 break; | ||||
|             case '1M': | ||||
|                 return $date->format('F Y'); | ||||
|                 break; | ||||
|             case '3M': | ||||
|                 $month = intval($date->format('m')); | ||||
|                 return 'Q' . ceil(($month / 12) * 4) . ' ' . $date->format('Y'); | ||||
|                 break; | ||||
|             case '6M': | ||||
|                 $month    = intval($date->format('m')); | ||||
|                 $half     = ceil(($month / 12) * 2); | ||||
|                 $halfName = $half == 1 ? 'first' : 'second'; | ||||
|                 return $halfName . ' half of ' . $date->format('d-m-Y'); | ||||
|                 break; | ||||
|             case '1Y': | ||||
|                 return $date->format('Y'); | ||||
|                 break; | ||||
|  | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected function _previous($range, Carbon $date) | ||||
|     { | ||||
|         switch ($range) { | ||||
|             default: | ||||
|                 throw new FireflyException('Cannot do _previous() on ' . $range); | ||||
|                 break; | ||||
|             case '1D': | ||||
|                 $date->startOfDay()->subDay(); | ||||
|                 break; | ||||
|             case '1W': | ||||
|                 $date->startOfWeek()->subWeek(); | ||||
|                 break; | ||||
|             case '1M': | ||||
|                 $date->startOfMonth()->subMonth(); | ||||
|                 break; | ||||
|             case '3M': | ||||
|                 $date->firstOfQuarter()->subMonths(3)->firstOfQuarter(); | ||||
|                 break; | ||||
|             case '6M': | ||||
|                 $month = intval($date->format('m')); | ||||
|                 if ($month <= 6) { | ||||
|                     $date->startOfYear()->subMonths(6); | ||||
|                 } else { | ||||
|                     $date->startOfYear(); | ||||
|                 } | ||||
|                 break; | ||||
|             case '1Y': | ||||
|                 $date->startOfYear()->subYear(); | ||||
|                 break; | ||||
|  | ||||
|         } | ||||
|         return $date; | ||||
|     } | ||||
|  | ||||
|     protected function _next($range, Carbon $date) | ||||
|     { | ||||
|         switch ($range) { | ||||
|             case '1D': | ||||
|                 $start->subDay(); | ||||
|                 $date->endOfDay()->addDay(); | ||||
|                 break; | ||||
|             case '1W': | ||||
|                 $start->subWeek(); | ||||
|                 $date->endOfWeek()->addDay()->startOfWeek(); | ||||
|                 break; | ||||
|             case '1M': | ||||
|                 $start->subMonth(); | ||||
|                 $date->endOfMonth()->addDay()->startOfMonth(); | ||||
|                 break; | ||||
|             case '3M': | ||||
|                 $start->subMonths(3)->firstOfQuarter(); | ||||
|                 $date->lastOfQuarter()->addDay(); | ||||
|                 break; | ||||
|             case '6M': | ||||
|                 $start->subMonths(6); | ||||
|                 if (intval($date->format('m')) >= 7) { | ||||
|                     $date->startOfYear()->addYear(); | ||||
|                 } else { | ||||
|                     $date->startOfYear()->addMonths(6); | ||||
|                 } | ||||
|                 break; | ||||
|             case '1Y': | ||||
|                 $date->startOfYear()->addYear(); | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new FireflyException('Cannot do _next() on ' . $range); | ||||
|                 break; | ||||
|         } | ||||
|         return $start; | ||||
|         return $date; | ||||
|     } | ||||
|  | ||||
|     public function next() | ||||
|     { | ||||
|         /* | ||||
|          * Get the start date and the range from the session | ||||
|          */ | ||||
|         $range = $this->_getRange(); | ||||
|         $start = \Session::get('start'); | ||||
|  | ||||
|         /* | ||||
|          * Add some period to $start. | ||||
|          */ | ||||
|         $next = $this->_next($range, clone $start); | ||||
|  | ||||
|         /* | ||||
|          * Save in session: | ||||
|          */ | ||||
|         \Session::put('start', $next); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function prev() | ||||
|     { | ||||
|         /* | ||||
|          * Get the start date and the range from the session | ||||
|          */ | ||||
|         $range = $this->_getRange(); | ||||
|         $start = \Session::get('start'); | ||||
|  | ||||
|         /* | ||||
|          * Substract some period to $start. | ||||
|          */ | ||||
|         $prev = $this->_previous($range, clone $start); | ||||
|  | ||||
|         /* | ||||
|          * Save in session: | ||||
|          */ | ||||
|         \Session::put('start', $prev); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param        $range | ||||
|      * @param Carbon $end | ||||
|      * Takes any collection and tries to make a sensible select list compatible array of it. | ||||
|      * | ||||
|      * @return Carbon | ||||
|      * @param Collection $set | ||||
|      * @param null $titleField | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     protected function _moveEndPrevious($range, Carbon $end) | ||||
|     public function makeSelectList(Collection $set, $titleField = null) | ||||
|     { | ||||
|         switch ($range) { | ||||
|             case '1D': | ||||
|                 $end->subDay(); | ||||
|                 break; | ||||
|             case '1W': | ||||
|                 $end->subWeek(); | ||||
|                 break; | ||||
|             case '1M': | ||||
|                 $end->startOfMonth()->subMonth()->endOfMonth(); | ||||
|                 break; | ||||
|             case '3M': | ||||
|                 $end->subMonths(3)->lastOfQuarter(); | ||||
|                 break; | ||||
|             case '6M': | ||||
|                 $end->subMonths(6); | ||||
|                 break; | ||||
|         } | ||||
|         return $end; | ||||
|         $selectList = []; | ||||
|         /** @var Model $entry */ | ||||
|         foreach ($set as $entry) { | ||||
|             $id    = intval($entry->id); | ||||
|             $title = null; | ||||
|             if (is_null($titleField)) { | ||||
|                 // try 'title' field. | ||||
|                 if (isset($entry->title)) { | ||||
|                     $title = $entry->title; | ||||
|                 } | ||||
|                 // try 'name' field | ||||
|                 if (is_null($title)) { | ||||
|                     $title = $entry->name; | ||||
|                 } | ||||
|  | ||||
|                 // try 'description' field | ||||
|                 if (is_null($title)) { | ||||
|                     $title = $entry->description; | ||||
|                 } | ||||
|             } else { | ||||
|                 $title = $entry->$titleField; | ||||
|             } | ||||
|             $selectList[$id] = $title; | ||||
|         } | ||||
|         return $selectList; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param        $range | ||||
|      * @param Carbon $start | ||||
|      * | ||||
|      * @return Carbon | ||||
|      * @param string $start | ||||
|      * @param string $end | ||||
|      * @param int $steps | ||||
|      */ | ||||
|     protected function _moveStartNext($range, Carbon $start) | ||||
|     public function colorRange($start, $end, $steps = 5) | ||||
|     { | ||||
|         switch ($range) { | ||||
|             case '1D': | ||||
|                 $start->addDay(); | ||||
|                 break; | ||||
|             case '1W': | ||||
|                 $start->addWeek(); | ||||
|                 break; | ||||
|             case '1M': | ||||
|                 $start->addMonth(); | ||||
|                 break; | ||||
|             case '3M': | ||||
|                 $start->addMonths(3)->firstOfQuarter(); | ||||
|                 break; | ||||
|             case '6M': | ||||
|                 $start->addMonths(6); | ||||
|                 break; | ||||
|         if (strlen($start) != 6) { | ||||
|             throw new FireflyException('Start, ' . e($start) . ' should be a six character HTML colour.'); | ||||
|         } | ||||
|         return $start; | ||||
|         if (strlen($end) != 6) { | ||||
|             throw new FireflyException('End, ' . e($end) . ' should be a six character HTML colour.'); | ||||
|         } | ||||
|         if ($steps < 1) { | ||||
|             throw new FireflyException('Steps must be > 1'); | ||||
|         } | ||||
|  | ||||
|         $start = '#' . $start; | ||||
|         $end   = '#' . $end; | ||||
|         /* | ||||
|          * Split html colours. | ||||
|          */ | ||||
|         list($rs, $gs, $bs) = sscanf($start, "#%02x%02x%02x"); | ||||
|         list($re, $ge, $be) = sscanf($end, "#%02x%02x%02x"); | ||||
|  | ||||
|         $stepr = ($re - $rs) / $steps; | ||||
|         $stepg = ($ge - $gs) / $steps; | ||||
|         $stepb = ($be - $bs) / $steps; | ||||
|  | ||||
|         $return = []; | ||||
|         for ($i = 0; $i <= $steps; $i++) { | ||||
|             $cr = $rs + ($stepr * $i); | ||||
|             $cg = $gs + ($stepg * $i); | ||||
|             $cb = $bs + ($stepb * $i); | ||||
|  | ||||
|             $return[] = $this->rgb2html($cr, $cg, $cb); | ||||
|         } | ||||
|  | ||||
|         return $return; | ||||
|     } | ||||
|  | ||||
|     protected function rgb2html($r, $g = -1, $b = -1) | ||||
|     { | ||||
|         $r = dechex($r < 0 ? 0 : ($r > 255 ? 255 : $r)); | ||||
|         $g = dechex($g < 0 ? 0 : ($g > 255 ? 255 : $g)); | ||||
|         $b = dechex($b < 0 ? 0 : ($b > 255 ? 255 : $b)); | ||||
|  | ||||
|         $color = (strlen($r) < 2 ? '0' : '') . $r; | ||||
|         $color .= (strlen($g) < 2 ? '0' : '') . $g; | ||||
|         $color .= (strlen($b) < 2 ? '0' : '') . $b; | ||||
|         return '#' . $color; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param        $range | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Carbon | ||||
|      * @param Carbon $currentEnd | ||||
|      * @param $repeatFreq | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     protected function _moveEndNext($range, Carbon $end) | ||||
|     public function endOfPeriod(Carbon $currentEnd, $repeatFreq) | ||||
|     { | ||||
|         switch ($range) { | ||||
|             case '1D': | ||||
|                 $end->addDay(); | ||||
|         switch ($repeatFreq) { | ||||
|             default: | ||||
|                 throw new FireflyException('Cannot do getFunctionForRepeatFreq for $repeat_freq ' . $repeatFreq); | ||||
|                 break; | ||||
|             case '1W': | ||||
|                 $end->addWeek(); | ||||
|             case 'daily': | ||||
|                 $currentEnd->addDay(); | ||||
|                 break; | ||||
|             case '1M': | ||||
|                 $end->addMonth(); | ||||
|             case 'weekly': | ||||
|                 $currentEnd->addWeek()->subDay(); | ||||
|                 break; | ||||
|             case '3M': | ||||
|                 $end->addMonths(6)->lastOfQuarter(); | ||||
|             case 'monthly': | ||||
|                 $currentEnd->addMonth()->subDay(); | ||||
|                 break; | ||||
|             case '6M': | ||||
|                 $end->addMonths(6); | ||||
|             case 'quarterly': | ||||
|                 $currentEnd->addMonths(3)->subDay(); | ||||
|                 break; | ||||
|             case 'half-year': | ||||
|                 $currentEnd->addMonths(6)->subDay(); | ||||
|                 break; | ||||
|             case 'yearly': | ||||
|                 $currentEnd->addYear()->subDay(); | ||||
|                 break; | ||||
|         } | ||||
|         return $end; | ||||
|     } | ||||
|  | ||||
| }  | ||||
|     /** | ||||
|      * @param Carbon $date | ||||
|      * @param $repeatFreq | ||||
|      * @param $skip | ||||
|      * @return Carbon | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public function addPeriod(Carbon $date, $repeatFreq, $skip) | ||||
|     { | ||||
|         $add = ($skip + 1); | ||||
|         switch ($repeatFreq) { | ||||
|             default: | ||||
|                 throw new FireflyException('Cannot do getFunctionForRepeatFreq for $repeat_freq ' . $repeatFreq); | ||||
|                 break; | ||||
|             case 'daily': | ||||
|                 $date->addDays($add); | ||||
|                 break; | ||||
|             case 'weekly': | ||||
|                 $date->addWeeks($add); | ||||
|                 break; | ||||
|             case 'monthly': | ||||
|                 $date->addMonths($add); | ||||
|                 break; | ||||
|             case 'quarterly': | ||||
|                 $months = $add * 3; | ||||
|                 $date->addMonths($months); | ||||
|                 break; | ||||
|             case 'half-year': | ||||
|                 $months = $add * 6; | ||||
|                 $date->addMonths($months); | ||||
|                 break; | ||||
|             case 'yearly': | ||||
|                 $date->addYears($add); | ||||
|                 break; | ||||
|         } | ||||
|         return $date; | ||||
|     } | ||||
| } | ||||
| @@ -2,7 +2,8 @@ | ||||
|  | ||||
| namespace Firefly\Helper\Toolkit; | ||||
|  | ||||
| use Illuminate\Http\Request; | ||||
| use Carbon\Carbon; | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
| /** | ||||
|  * Interface ToolkitInterface | ||||
| @@ -12,20 +13,40 @@ use Illuminate\Http\Request; | ||||
| interface ToolkitInterface | ||||
| { | ||||
|     /** | ||||
|      * @param Request $request | ||||
|      * | ||||
|      * @return null | ||||
|      */ | ||||
|     public function getDateRange(); | ||||
|  | ||||
|     /** | ||||
|      * Takes any collection and tries to make a sensible select list compatible array of it. | ||||
|      * | ||||
|      * @param Collection $set | ||||
|      * @param null $titleField | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getDateRange(Request $request); | ||||
|     public function makeSelectList(Collection $set, $titleField = null); | ||||
|  | ||||
|     public function next(); | ||||
|  | ||||
|     public function prev(); | ||||
|  | ||||
|     public function checkImportJobs(); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      * @param string $start | ||||
|      * @param string $end | ||||
|      * @param int $steps | ||||
|      */ | ||||
|     public function getDateRangeDates(); | ||||
|     public function colorRange($start, $end, $steps = 5); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      * @param Carbon $date | ||||
|      * @param $repeatFreq | ||||
|      * @param $skip | ||||
|      * @return Carbon | ||||
|      */ | ||||
|     public function getReminders(); | ||||
|     public function addPeriod(Carbon $date, $repeatFreq, $skip); | ||||
|  | ||||
| }  | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -3,6 +3,8 @@ | ||||
|  | ||||
| namespace Firefly\Storage\Account; | ||||
|  | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
|  | ||||
| /** | ||||
|  * Interface AccountRepositoryInterface | ||||
|  * | ||||
| @@ -11,25 +13,35 @@ namespace Firefly\Storage\Account; | ||||
| interface AccountRepositoryInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importAccount(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function count(); | ||||
|  | ||||
|     /** | ||||
|      * @param              $name | ||||
|      * @param \AccountType $type | ||||
|      * Gets a list of accounts that have the mentioned type. Will automatically convert | ||||
|      * strings in this array to actual (model) account types. | ||||
|      * | ||||
|      * @return mixed | ||||
|      * @param array $types | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function createOrFind($name, \AccountType $type); | ||||
|     public function getOfTypes(array $types); | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * @param array $data | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function createOrFindBeneficiary($name); | ||||
|     public function firstOrCreate(array $data); | ||||
|  | ||||
|     /** | ||||
|      * @param \Account $account | ||||
| @@ -47,43 +59,49 @@ interface AccountRepositoryInterface | ||||
|  | ||||
|     /** | ||||
|      * @param $type | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function findAccountType($type); | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * @param \AccountType $type | ||||
|      * Takes a transaction/account component and updates the transaction journal to match. | ||||
|      * | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function findByName($name, \AccountType $type = null); | ||||
|     public function importUpdateTransaction(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * @param $id | ||||
|      * | ||||
|      * @return |Account|null | ||||
|      */ | ||||
|     public function findAssetAccountById($id); | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * @return mixed | ||||
|      * @param $create | ||||
|      * | ||||
|      * @return |Account|null | ||||
|      */ | ||||
|     public function findByNameAny($name); | ||||
|     public function findExpenseAccountByName($name, $create = true); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      * @param $name | ||||
|      * @param $create | ||||
|      * | ||||
|      * @return |Account|null | ||||
|      */ | ||||
|     public function get(); | ||||
|     public function findRevenueAccountByName($name, $create = true); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getActiveDefault(); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getActiveDefaultAsSelectList(); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getBeneficiaries(); | ||||
|  | ||||
|     /** | ||||
|      * @param $ids | ||||
|      * | ||||
| @@ -91,11 +109,6 @@ interface AccountRepositoryInterface | ||||
|      */ | ||||
|     public function getByIds(array $ids); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getCashAccount(); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
| @@ -103,12 +116,14 @@ interface AccountRepositoryInterface | ||||
|  | ||||
|     /** | ||||
|      * @param \AccountType $type | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getByAccountType(\AccountType $type); | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function overruleUser(\User $user); | ||||
|   | ||||
| @@ -4,6 +4,8 @@ | ||||
| namespace Firefly\Storage\Account; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Illuminate\Database\QueryException; | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
|  | ||||
| /** | ||||
|  * Class EloquentAccountRepository | ||||
| @@ -32,41 +34,6 @@ class EloquentAccountRepository implements AccountRepositoryInterface | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param              $name | ||||
|      * @param \AccountType $type | ||||
|      * | ||||
|      * @return \Account|mixed | ||||
|      */ | ||||
|     public function createOrFind($name, \AccountType $type = null) | ||||
|     { | ||||
|         $account = $this->findByName($name, $type); | ||||
|         if (!$account) { | ||||
|             $data = [ | ||||
|                 'name'         => $name, | ||||
|                 'account_type' => $type | ||||
|             ]; | ||||
|  | ||||
|             return $this->store($data); | ||||
|         } | ||||
|  | ||||
|         return $account; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * | ||||
|      * @return \Account|mixed|null | ||||
|      */ | ||||
|     public function createOrFindBeneficiary($name) | ||||
|     { | ||||
|         if (is_null($name) || strlen($name) == 0) { | ||||
|             return null; | ||||
|         } | ||||
|         $type = \AccountType::where('type', 'Beneficiary account')->first(); | ||||
|         return $this->createOrFind($name, $type); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Account $account | ||||
|      * | ||||
| @@ -75,7 +42,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface | ||||
|     public function destroy(\Account $account) | ||||
|     { | ||||
|         // find all transaction journals related to this account: | ||||
|         $journals   = \TransactionJournal::withRelevantData()->account($account)->get(['transaction_journals.*']); | ||||
|         $journals = \TransactionJournal::withRelevantData()->accountIs($account)->get(['transaction_journals.*']); | ||||
|         $accountIDs = []; | ||||
|  | ||||
|         /** @var \TransactionJournal $journal */ | ||||
| @@ -109,104 +76,163 @@ class EloquentAccountRepository implements AccountRepositoryInterface | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $accountId | ||||
|      * @param $id | ||||
|      * | ||||
|      * @return mixed | ||||
|      * @return |Account|null | ||||
|      */ | ||||
|     public function find($accountId) | ||||
|     public function findAssetAccountById($id) | ||||
|     { | ||||
|         return $this->_user->accounts()->where('id', $accountId)->first(); | ||||
|         return $this->_user->accounts()->find($id); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method finds the expense account mentioned by name. This method is a sneaky little hobbits, | ||||
|      * because when you feed it "Import account" it will always return an import account of that type. | ||||
|      * | ||||
|      * @param $name | ||||
|      * @param $create | ||||
|      * | ||||
|      * @return null|\Account | ||||
|      */ | ||||
|     public function findExpenseAccountByName($name, $create = true) | ||||
|     { | ||||
|         $cashType = $this->findAccountType('Cash account'); | ||||
|         $importType = $this->findAccountType('Import account'); | ||||
|         // catch Import account: | ||||
|         if ($name == 'Import account') { | ||||
|  | ||||
|             $import = $this->firstOrCreate( | ||||
|                 [ | ||||
|                     'name' => 'Import account', | ||||
|                     'user_id' => $this->_user->id, | ||||
|                     'account_type_id' => $importType->id, | ||||
|                     'active' => 1 | ||||
|                 ] | ||||
|             ); | ||||
|             return $import; | ||||
|         } | ||||
|  | ||||
|         // find account: | ||||
|  | ||||
|         $account = $this->_user->accounts()->where('name', $name)->accountTypeIn( | ||||
|             ['Expense account', 'Beneficiary account'] | ||||
|         )->first(['accounts.*']); | ||||
|  | ||||
|         // create if not found: | ||||
|         if (strlen($name) > 0 && is_null($account) && $create === true) { | ||||
|             $type = $this->findAccountType('Expense account'); | ||||
|             $set = [ | ||||
|                 'name' => $name, | ||||
|                 'user_id' => $this->_user->id, | ||||
|                 'active' => 1, | ||||
|                 'account_type_id' => $type->id | ||||
|             ]; | ||||
|             $account = $this->firstOrCreate($set); | ||||
|         } else if (strlen($name) > 0 && is_null($account) && $create === false) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         // find cash account as fall back: | ||||
|         if (is_null($account)) { | ||||
|  | ||||
|             $account = $this->_user->accounts()->where('account_type_id', $cashType->id)->first(); | ||||
|         } | ||||
|  | ||||
|         // create cash account as ultimate fall back: | ||||
|         if (is_null($account)) { | ||||
|             $set = [ | ||||
|                 'name' => 'Cash account', | ||||
|                 'user_id' => $this->_user->id, | ||||
|                 'active' => 1, | ||||
|                 'account_type_id' => $cashType->id | ||||
|             ]; | ||||
|             $account = $this->firstOrCreate($set); | ||||
|         } | ||||
|  | ||||
|         if ($account->active == 0 && $account->account_type_id != $cashType->id) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         return $account; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $type | ||||
|      * @return mixed | ||||
|      * | ||||
|      * @return \AccountType|null | ||||
|      */ | ||||
|     public function findAccountType($type) | ||||
|     { | ||||
|         return \AccountType::where('type', $type)->first(); | ||||
|     } | ||||
|  | ||||
|     public function firstOrCreate(array $data) | ||||
|     { | ||||
|         return \Account::firstOrCreate($data); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param              $name | ||||
|      * @param \AccountType $type | ||||
|      * @param $name | ||||
|      * @param $create | ||||
|      * | ||||
|      * @return mixed | ||||
|      * @return |Account|null | ||||
|      */ | ||||
|     public function findByName($name, \AccountType $type = null) | ||||
|     public function findRevenueAccountByName($name, $create = true) | ||||
|     { | ||||
|         $type = is_null($type) ? \AccountType::where('type', 'Default account')->first() : $type; | ||||
|  | ||||
|         return $this->_user->accounts()->where('account_type_id', $type->id) | ||||
|                            ->where('name', 'like', '%' . $name . '%') | ||||
|                            ->first(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Used for import | ||||
|      * | ||||
|      * @param              $name | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function findByNameAny($name) | ||||
|     { | ||||
|         return $this->_user->accounts() | ||||
|                            ->where('name', 'like', '%' . $name . '%') | ||||
|                            ->first(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function get() | ||||
|     { | ||||
|         return $this->_user->accounts()->with('accounttype')->orderBy('name', 'ASC')->get(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getActiveDefault() | ||||
|     { | ||||
|         return $this->_user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') | ||||
|                            ->where('account_types.type', 'Default account')->where('accounts.active', 1) | ||||
|  | ||||
|                            ->get(['accounts.*']); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array|mixed | ||||
|      */ | ||||
|     public function  getActiveDefaultAsSelectList() | ||||
|     { | ||||
|         $list   = $this->_user->accounts()->leftJoin( | ||||
|                               'account_types', 'account_types.id', '=', 'accounts.account_type_id' | ||||
|         ) | ||||
|                               ->where('account_types.type', 'Default account')->where('accounts.active', 1) | ||||
|  | ||||
|                               ->orderBy('accounts.name', 'ASC')->get(['accounts.*']); | ||||
|         $return = []; | ||||
|         foreach ($list as $entry) { | ||||
|             $return[intval($entry->id)] = $entry->name; | ||||
|         // catch Import account: | ||||
|         if ($name == 'Import account') { | ||||
|             $importType = $this->findAccountType('Import account'); | ||||
|             $import = $this->firstOrCreate( | ||||
|                 [ | ||||
|                     'name' => 'Import account', | ||||
|                     'user_id' => $this->_user->id, | ||||
|                     'account_type_id' => $importType->id, | ||||
|                     'active' => 1 | ||||
|                 ] | ||||
|             ); | ||||
|             return $import; | ||||
|         } | ||||
|  | ||||
|         return $return; | ||||
|     } | ||||
|         // find account: | ||||
|         $type = $this->findAccountType('Revenue account'); | ||||
|         $account = $this->_user->accounts()->where('name', $name)->where('account_type_id', $type->id)->first(); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getBeneficiaries() | ||||
|     { | ||||
|         $list = $this->_user->accounts()->leftJoin( | ||||
|                             'account_types', 'account_types.id', '=', 'accounts.account_type_id' | ||||
|         ) | ||||
|                             ->where('account_types.type', 'Beneficiary account')->where('accounts.active', 1) | ||||
|         // create if not found: | ||||
|         if (strlen($name) > 0 && is_null($account) && $create === true) { | ||||
|             $set = [ | ||||
|                 'name' => $name, | ||||
|                 'user_id' => $this->_user->id, | ||||
|                 'active' => 1, | ||||
|                 'account_type_id' => $type->id | ||||
|             ]; | ||||
|             $account = $this->firstOrCreate($set); | ||||
|         } else if (strlen($name) > 0 && is_null($account) && $create === false) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|                             ->orderBy('accounts.name', 'ASC')->get(['accounts.*']); | ||||
|         // find cash account as fall back: | ||||
|         if (is_null($account)) { | ||||
|             $cashType = $this->findAccountType('Cash account'); | ||||
|             $account = $this->_user->accounts()->where('account_type_id', $cashType->id)->first(); | ||||
|         } | ||||
|  | ||||
|         return $list; | ||||
|         // create cash account as ultimate fall back: | ||||
|         if (is_null($account)) { | ||||
|             $set = [ | ||||
|                 'name' => 'Cash account', | ||||
|                 'user_id' => $this->_user->id, | ||||
|                 'active' => 1, | ||||
|                 'account_type_id' => $cashType->id | ||||
|             ]; | ||||
|             $account = $this->firstOrCreate($set); | ||||
|         } | ||||
|  | ||||
|         if ($account->active == 0) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         return $account; | ||||
|     } | ||||
|  | ||||
|     public function getByAccountType(\AccountType $type) | ||||
| @@ -228,25 +254,66 @@ class EloquentAccountRepository implements AccountRepositoryInterface | ||||
|             return $this->getActiveDefault(); | ||||
|         } | ||||
|     } | ||||
| // | ||||
| //    /** | ||||
| //     * @param $name | ||||
| //     * | ||||
| //     * @return \Account|mixed|null | ||||
| //     */ | ||||
| //    public function createOrFindBeneficiary($name) | ||||
| //    { | ||||
| //        if (is_null($name) || strlen($name) == 0) { | ||||
| //            return null; | ||||
| //        } | ||||
| //        $type = \AccountType::where('type', 'Expense account')->first(); | ||||
| //        return $this->createOrFind($name, $type); | ||||
| //    } | ||||
| // | ||||
| //    /** | ||||
| //     * @param              $name | ||||
| //     * @param \AccountType $type | ||||
| //     * | ||||
| //     * @return \Account|mixed | ||||
| //     */ | ||||
| //    public function createOrFind($name, \AccountType $type = null) | ||||
| //    { | ||||
| //        $account = $this->findByName($name, $type); | ||||
| //        if (!$account) { | ||||
| //            $data = [ | ||||
| //                'name'         => $name, | ||||
| //                'account_type' => $type | ||||
| //            ]; | ||||
| // | ||||
| //            return $this->store($data); | ||||
| //        } | ||||
| // | ||||
| //        return $account; | ||||
| //    } | ||||
| // | ||||
| //    /** | ||||
| //     * @param              $name | ||||
| //     * @param \AccountType $type | ||||
| //     * | ||||
| //     * @return mixed | ||||
| //     */ | ||||
| //    public function findByName($name, \AccountType $type = null) | ||||
| //    { | ||||
| //        $type = is_null($type) ? \AccountType::where('type', 'Asset account')->first() : $type; | ||||
| // | ||||
| //        return $this->_user->accounts()->where('account_type_id', $type->id) | ||||
| //            ->where('name', 'like', '%' . $name . '%') | ||||
| //            ->first(); | ||||
| //    } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getCashAccount() | ||||
|     public function getActiveDefault() | ||||
|     { | ||||
|         $type = \AccountType::where('type', 'Cash account')->first(); | ||||
|         $cash = $this->_user->accounts()->where('account_type_id', $type->id)->first(); | ||||
|         if (is_null($cash)) { | ||||
|             $cash = new \Account; | ||||
|             $cash->accountType()->associate($type); | ||||
|             $cash->user()->associate($this->_user); | ||||
|             $cash->name   = 'Cash account'; | ||||
|             $cash->active = 1; | ||||
|             $cash->save(); | ||||
|         } | ||||
|  | ||||
|         return $cash; | ||||
|  | ||||
|         return $this->_user->accounts()->accountTypeIn(['Default account', 'Asset account'])->where( | ||||
|             'accounts.active', 1 | ||||
|         ) | ||||
|                            ->get(['accounts.*']); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -254,22 +321,120 @@ class EloquentAccountRepository implements AccountRepositoryInterface | ||||
|      */ | ||||
|     public function getDefault() | ||||
|     { | ||||
|         return $this->_user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') | ||||
|                            ->where('account_types.type', 'Default account') | ||||
|  | ||||
|         return $this->_user->accounts()->accountTypeIn(['Default account', 'Asset account']) | ||||
|                            ->orderBy('accounts.name', 'ASC')->get(['accounts.*']); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * @return mixed|void | ||||
|      * Gets a list of accounts that have the mentioned type. Will automatically convert | ||||
|      * strings in this array to actual (model) account types. | ||||
|      * | ||||
|      * @param array $types | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
|     public function getOfTypes(array $types) | ||||
|     { | ||||
|         $this->_user = $user; | ||||
|         return true; | ||||
|         $accounts = $this->_user->accounts()->accountTypeIn($types)->get(['accounts.*']); | ||||
|         return $accounts; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Job $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importAccount(Job $job, array $payload) | ||||
|     { | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|         /* | ||||
|          * maybe Account is already imported: | ||||
|          */ | ||||
|         $importEntry = $repository->findImportEntry($importMap, 'Account', intval($payload['data']['id'])); | ||||
|  | ||||
|         /* | ||||
|          * if so, delete job and return: | ||||
|          */ | ||||
|         if (!is_null($importEntry)) { | ||||
|             \Log::debug('Already imported ' . $payload['data']['name'] . ' of type ' . $payload['account_type']); | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|             $job->delete(); // count fixed | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * find the payload's account type: | ||||
|          */ | ||||
|         $payload['account_type'] = isset($payload['account_type']) ? $payload['account_type'] : 'Expense account'; | ||||
|         $type = $this->findAccountType($payload['account_type']); | ||||
|  | ||||
|         /* | ||||
|          * Create data array for store() procedure. | ||||
|          */ | ||||
|         $data = [ | ||||
|             'account_type' => $type, | ||||
|             'name' => $payload['data']['name'], | ||||
|         ]; | ||||
|         if (isset($payload['data']['openingbalance'])) { | ||||
|             $data['openingbalance'] = floatval($payload['data']['openingbalance']); | ||||
|             $data['openingbalancedate'] = $payload['data']['openingbalancedate']; | ||||
|         } | ||||
|         if (isset($payload['data']['inactive'])) { | ||||
|             $data['active'] = intval($payload['data']['inactive']) == 0 ? 1 : 0; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Try to store: | ||||
|          */ | ||||
|         $account = $this->store($data); | ||||
|  | ||||
|         /* | ||||
|          * Check for failure. | ||||
|          */ | ||||
|         if (count($account->errors()) > 0) { | ||||
|             \Log::error('Account creation error: ' . $account->errors()->first()); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed | ||||
|             return; | ||||
|         } | ||||
|         \Log::debug('Imported ' . $payload['account_type'] . ': ' . $payload['data']['name']); | ||||
|  | ||||
|         /* | ||||
|          * Save meta data | ||||
|          */ | ||||
|         $repository->store($importMap, 'Account', intval($payload['data']['id']), $account->id); | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|         $job->delete(); // count fixed. | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| //    /** | ||||
| //     * Used for import | ||||
| //     * | ||||
| //     * @param              $name | ||||
| //     * | ||||
| //     * @return mixed | ||||
| //     */ | ||||
| //    public function findByNameAny($name) | ||||
| //    { | ||||
| //        return $this->_user->accounts() | ||||
| //            ->where('name', 'like', '%' . $name . '%') | ||||
| //            ->first(); | ||||
| //    } | ||||
|  | ||||
|     /** | ||||
|      * @param $data | ||||
|      * | ||||
| @@ -286,11 +451,15 @@ class EloquentAccountRepository implements AccountRepositoryInterface | ||||
|         ) { | ||||
|             $accountType = $data['account_type']; | ||||
|         } else if (isset($data['account_type']) && is_string($data['account_type'])) { | ||||
|             // if it isnt but set as string, find it: | ||||
|             $accountType = \AccountType::where('type', $data['account_type'])->first(); | ||||
|  | ||||
|         } else { | ||||
|             $accountType = \AccountType::where('type', 'Default account')->first(); | ||||
|             $accountType = \AccountType::where('type', 'Asset account')->first(); | ||||
|         } | ||||
|         $active = isset($data['active']) && intval($data['active']) >= 0 && intval($data['active']) <= 1 ? intval( | ||||
|             $data['active'] | ||||
|         ) : 1; | ||||
|  | ||||
|         /** | ||||
|          * Create new account: | ||||
| @@ -301,20 +470,24 @@ class EloquentAccountRepository implements AccountRepositoryInterface | ||||
|  | ||||
|         $account->name = $data['name']; | ||||
|         $account->active | ||||
|                        = isset($data['active']) && intval($data['active']) >= 0 && intval($data['active']) <= 1 ? intval( | ||||
|             = isset($data['active']) && intval($data['active']) >= 0 && intval($data['active']) <= 1 ? intval( | ||||
|             $data['active'] | ||||
|         ) : 1; | ||||
|  | ||||
|         // try to save it: | ||||
|         if ($account->save()) { | ||||
|             // create initial balance, if necessary: | ||||
|             if (isset($data['openingbalance']) && isset($data['openingbalancedate'])) { | ||||
|                 $amount = floatval($data['openingbalance']); | ||||
|                 $date   = new Carbon($data['openingbalancedate']); | ||||
|                 if ($amount != 0) { | ||||
|                     $this->_createInitialBalance($account, $amount, $date); | ||||
|         try { | ||||
|             if ($account->save()) { | ||||
|                 // create initial balance, if necessary: | ||||
|                 if (isset($data['openingbalance']) && isset($data['openingbalancedate'])) { | ||||
|                     $amount = floatval($data['openingbalance']); | ||||
|                     $date = new Carbon($data['openingbalancedate']); | ||||
|                     if ($amount != 0) { | ||||
|                         $this->_createInitialBalance($account, $amount, $date); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } catch (QueryException $e) { | ||||
|             // do nothing | ||||
|         } | ||||
|  | ||||
|  | ||||
| @@ -322,6 +495,206 @@ class EloquentAccountRepository implements AccountRepositoryInterface | ||||
|         return $account; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Account $account | ||||
|      * @param int $amount | ||||
|      * @param Carbon $date | ||||
|      * | ||||
|      * @return bool | ||||
|      * @SuppressWarnings(PHPMD.CamelCaseMethodName) | ||||
|      */ | ||||
|     protected function _createInitialBalance(\Account $account, $amount = 0, Carbon $date) | ||||
|     { | ||||
|         /* | ||||
|          * The repositories we need: | ||||
|          */ | ||||
|         /** @var \Firefly\Helper\Controllers\TransactionInterface $transactions */ | ||||
|         $transactions = \App::make('Firefly\Helper\Controllers\TransactionInterface'); | ||||
|         $transactions->overruleUser($this->_user); | ||||
|  | ||||
|  | ||||
|         /* | ||||
|          * get account type: | ||||
|          */ | ||||
|         $initialBalanceAT = $this->findAccountType('Initial balance account'); | ||||
|  | ||||
|         /* | ||||
|          * create new account | ||||
|          */ | ||||
|         $initial = new \Account; | ||||
|         $initial->accountType()->associate($initialBalanceAT); | ||||
|         $initial->user()->associate($this->_user); | ||||
|         $initial->name = $account->name . ' initial balance'; | ||||
|         $initial->active = 0; | ||||
|         if ($initial->validate()) { | ||||
|             $initial->save(); | ||||
|             /* | ||||
|              * create new transaction journal (and transactions): | ||||
|              */ | ||||
|  | ||||
|             $set = [ | ||||
|                 'account_from_id' => $initial->id, | ||||
|                 'account_to_id' => $account->id, | ||||
|                 'description' => 'Initial Balance for ' . $account->name, | ||||
|                 'what' => 'Opening balance', | ||||
|                 'amount' => $amount, | ||||
|                 'category' => '', | ||||
|                 'date' => $date->format('Y-m-d') | ||||
|             ]; | ||||
|             $transactions->store($set); | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Takes a transaction/account component and updates the transaction journal to match. | ||||
|      * | ||||
|      * @param Job $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importUpdateTransaction(Job $job, array $payload) | ||||
|     { | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|         if ($job->attempts() > 10) { | ||||
|             \Log::error('Never found budget/account combination "' . $payload['data']['transaction_id'] . '"'); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed. | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */ | ||||
|         $journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); | ||||
|         $journals->overruleUser($user); | ||||
|  | ||||
|         /* | ||||
|          * Prep some vars from the payload | ||||
|          */ | ||||
|         $transactionId = intval($payload['data']['transaction_id']); | ||||
|         $componentId = intval($payload['data']['component_id']); | ||||
|  | ||||
|         /* | ||||
|          * Find the import map for both: | ||||
|          */ | ||||
|         $accountMap = $repository->findImportEntry($importMap, 'Account', $componentId); | ||||
|         $transactionMap = $repository->findImportEntry($importMap, 'Transaction', $transactionId); | ||||
|  | ||||
|         /* | ||||
|          * Either may be null: | ||||
|          */ | ||||
|         if (is_null($accountMap) || is_null($transactionMap)) { | ||||
|             \Log::notice('No map found in account/transaction mapper. Release.'); | ||||
|             if (\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Find the account and the transaction: | ||||
|          */ | ||||
|         $account = $this->find($accountMap->new); | ||||
|         /** @var \TransactionJournal $journal */ | ||||
|         $journal = $journals->find($transactionMap->new); | ||||
|  | ||||
|         /* | ||||
|          * If either is null, release: | ||||
|          */ | ||||
|         if (is_null($account) || is_null($journal)) { | ||||
|             \Log::notice('Map is incorrect in account/transaction mapper. Release.'); | ||||
|             if (\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Update one of the journal's transactions to have the right account: | ||||
|          */ | ||||
|         $importType = $this->findAccountType('Import account'); | ||||
|         /** @var \Transaction $transaction */ | ||||
|         $updated = false; | ||||
|         \Log::debug( | ||||
|             'Connect "' . $account->name . '" (#' . $account->id . ') to "' . $journal->description . '" (#' | ||||
|             . $journal->id . ')' | ||||
|         ); | ||||
|         foreach ($journal->transactions as $index => $transaction) { | ||||
|             /* | ||||
|              * If it's of the right type, update it! | ||||
|              */ | ||||
|             \Log::debug( | ||||
|                 'Transaction ' . $index . ' (#' . $transaction->id . '): [' . $transaction->account->account_type_id | ||||
|                 . ' vs. ' . $importType->id . ']' | ||||
|             ); | ||||
|             if ($transaction->account->account_type_id == $importType->id) { | ||||
|                 $transaction->account()->associate($account); | ||||
|                 $transaction->save(); | ||||
|                 $updated = true; | ||||
|                 \Log::debug( | ||||
|                     'Connected expense account "' . $account->name . '" to journal "' . $journal->description . '"' | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|         if ($updated === false) { | ||||
|             \Log::error( | ||||
|                 'Did not connect transactions of journal #' . $journal->id . ' to expense account ' . $account->id | ||||
|             ); | ||||
|  | ||||
|         } | ||||
|  | ||||
|         $journal->save(); | ||||
|  | ||||
|  | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|  | ||||
|         $job->delete(); // count fixed | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
|     { | ||||
|         $this->_user = $user; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $accountId | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function find($accountId) | ||||
|     { | ||||
|         return $this->_user->accounts()->where('id', $accountId)->first(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Account $account | ||||
|      * @param          $data | ||||
| @@ -336,17 +709,17 @@ class EloquentAccountRepository implements AccountRepositoryInterface | ||||
|             $account->save(); | ||||
|         } | ||||
|         // update initial balance if necessary: | ||||
|         if (floatval($data['openingbalance']) != 0) { | ||||
|         if (isset($data['openingbalance']) && floatval($data['openingbalance']) != 0) { | ||||
|  | ||||
|             /** @var \Firefly\Helper\Controllers\AccountInterface $interface */ | ||||
|             $interface = \App::make('Firefly\Helper\Controllers\AccountInterface'); | ||||
|  | ||||
|             if ($account->accounttype->type == 'Default account') { | ||||
|             if ($account->accounttype->type == 'Default account' || $account->accounttype->type == 'Asset account') { | ||||
|  | ||||
|  | ||||
|                 $journal = $interface->openingBalanceTransaction($account); | ||||
|                 if ($journal) { | ||||
|                     $journal->date                    = new Carbon($data['openingbalancedate']); | ||||
|                     $journal->date = new Carbon($data['openingbalancedate']); | ||||
|                     $journal->transactions[0]->amount = floatval($data['openingbalance']) * -1; | ||||
|                     $journal->transactions[1]->amount = floatval($data['openingbalance']); | ||||
|                     $journal->transactions[0]->save(); | ||||
| @@ -359,42 +732,5 @@ class EloquentAccountRepository implements AccountRepositoryInterface | ||||
|         return $account; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Account $account | ||||
|      * @param int $amount | ||||
|      * @param Carbon $date | ||||
|      * | ||||
|      * @return bool | ||||
|      * @SuppressWarnings(PHPMD.CamelCaseMethodName) | ||||
|      */ | ||||
|     protected function _createInitialBalance(\Account $account, $amount = 0, Carbon $date) | ||||
|     { | ||||
|         // get account type: | ||||
|         $initialBalanceAT = \AccountType::where('type', 'Initial balance account')->first(); | ||||
|  | ||||
|         // create new account: | ||||
|         $initial = new \Account; | ||||
|         $initial->accountType()->associate($initialBalanceAT); | ||||
|         $initial->user()->associate($this->_user); | ||||
|         $initial->name   = $account->name . ' initial balance'; | ||||
|         $initial->active = 0; | ||||
|         if ($initial->validate()) { | ||||
|             $initial->save(); | ||||
|             // create new transaction journal (and transactions): | ||||
|             /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $transactionJournal */ | ||||
|             $transactionJournal = \App::make( | ||||
|                                       'Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface' | ||||
|             ); | ||||
|             $transactionJournal->overruleUser($this->_user); | ||||
|  | ||||
|             $transactionJournal->createSimpleJournal( | ||||
|                                $initial, $account, 'Initial Balance for ' . $account->name, $amount, $date | ||||
|             ); | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,6 +1,7 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Firefly\Storage\Budget; | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
|  | ||||
| /** | ||||
|  * Interface BudgetRepositoryInterface | ||||
| @@ -9,6 +10,34 @@ namespace Firefly\Storage\Budget; | ||||
|  */ | ||||
| interface BudgetRepositoryInterface | ||||
| { | ||||
|     /** | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importBudget(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * Takes a transaction/budget component and updates the transaction journal to match. | ||||
|      * | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importUpdateTransaction(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * Takes a transfer/budget component and updates the transaction journal to match. | ||||
|      * | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importUpdateTransfer(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * @param \Budget $budget | ||||
|      * | ||||
| @@ -41,11 +70,6 @@ interface BudgetRepositoryInterface | ||||
|      */ | ||||
|     public function get(); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getAsSelectList(); | ||||
|  | ||||
|     /** | ||||
|      * @param $data | ||||
|      * | ||||
|   | ||||
| @@ -4,6 +4,7 @@ namespace Firefly\Storage\Budget; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Illuminate\Database\Eloquent\Collection; | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
|  | ||||
| /** | ||||
|  * Class EloquentBudgetRepository | ||||
| @@ -15,6 +16,7 @@ use Illuminate\Database\Eloquent\Collection; | ||||
|  */ | ||||
| class EloquentBudgetRepository implements BudgetRepositoryInterface | ||||
| { | ||||
|  | ||||
|     protected $_user = null; | ||||
|  | ||||
|     /** | ||||
| @@ -26,79 +28,70 @@ class EloquentBudgetRepository implements BudgetRepositoryInterface | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Budget $budget | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return bool | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function destroy(\Budget $budget) | ||||
|     public function importBudget(Job $job, array $payload) | ||||
|     { | ||||
|         $budget->delete(); | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user      = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|     /** | ||||
|      * @param $budgetId | ||||
|      * | ||||
|      * @return \Budget|null | ||||
|      */ | ||||
|     public function find($budgetId) | ||||
|     { | ||||
|         /* | ||||
|          * maybe Budget is already imported: | ||||
|          */ | ||||
|         $importEntry = $repository->findImportEntry($importMap, 'Budget', intval($payload['data']['id'])); | ||||
|  | ||||
|         return $this->_user->budgets()->find($budgetId); | ||||
|     } | ||||
|         /* | ||||
|          * if so, delete job and return: | ||||
|          */ | ||||
|         if (!is_null($importEntry)) { | ||||
|             \Log::debug('Already imported budget ' . $payload['data']['name']); | ||||
|  | ||||
|     /** | ||||
|      * @param $budgetName | ||||
|      * @return \Budget|null | ||||
|      */ | ||||
|     public function findByName($budgetName) | ||||
|     { | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|         return $this->_user->budgets()->whereName($budgetName)->first(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function get() | ||||
|     { | ||||
|         $set = $this->_user->budgets()->with( | ||||
|                            ['limits'                        => function ($q) { | ||||
|                                    $q->orderBy('limits.startdate', 'DESC'); | ||||
|                                }, 'limits.limitrepetitions' => function ($q) { | ||||
|                                    $q->orderBy('limit_repetitions.startdate', 'ASC'); | ||||
|                                }] | ||||
|         )->orderBy('name', 'ASC')->get(); | ||||
|         foreach ($set as $budget) { | ||||
|             foreach ($budget->limits as $limit) { | ||||
|                 foreach ($limit->limitrepetitions as $rep) { | ||||
|                     $rep->left = $rep->left(); | ||||
|                 } | ||||
|             } | ||||
|             $job->delete(); // count fixed | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         return $set; | ||||
|     } | ||||
|         /* | ||||
|          * maybe Budget is already imported. | ||||
|          */ | ||||
|         $budget = $this->findByName($payload['data']['name']); | ||||
|  | ||||
|     /** | ||||
|      * @return array | ||||
|      */ | ||||
|     public function getAsSelectList() | ||||
|     { | ||||
|         $list   = $this->_user->budgets()->with( | ||||
|                               ['limits', 'limits.limitrepetitions'] | ||||
|         )->orderBy('name', 'ASC')->get(); | ||||
|         $return = []; | ||||
|         foreach ($list as $entry) { | ||||
|             $return[intval($entry->id)] = $entry->name; | ||||
|         if (is_null($budget)) { | ||||
|             /* | ||||
|              * Not imported yet. | ||||
|              */ | ||||
|             $budget = $this->store($payload['data']); | ||||
|             $repository->store($importMap, 'Budget', $payload['data']['id'], $budget->id); | ||||
|             \Log::debug('Imported budget "' . $payload['data']['name'] . '".'); | ||||
|         } else { | ||||
|             /* | ||||
|              * already imported. | ||||
|              */ | ||||
|             $repository->store($importMap, 'Budget', $payload['data']['id'], $budget->id); | ||||
|             \Log::debug('Already had budget "' . $payload['data']['name'] . '".'); | ||||
|         } | ||||
|  | ||||
|         return $return; | ||||
|         // update map: | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|  | ||||
|         // delete job. | ||||
|         $job->delete(); // count fixed | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
| @@ -107,6 +100,17 @@ class EloquentBudgetRepository implements BudgetRepositoryInterface | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $budgetName | ||||
|      * | ||||
|      * @return \Budget|null | ||||
|      */ | ||||
|     public function findByName($budgetName) | ||||
|     { | ||||
|  | ||||
|         return $this->_user->budgets()->whereName($budgetName)->first(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $data | ||||
|      * | ||||
| @@ -135,7 +139,7 @@ class EloquentBudgetRepository implements BudgetRepositoryInterface | ||||
|             $limit = $limitRepository->store($limitData); | ||||
|             \Event::fire('limits.store', [$limit]); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         if ($budget->validate()) { | ||||
|             $budget->save(); | ||||
|         } | ||||
| @@ -143,6 +147,240 @@ class EloquentBudgetRepository implements BudgetRepositoryInterface | ||||
|         return $budget; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Takes a transfer/budget component and updates the transaction journal to match. | ||||
|      * | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importUpdateTransfer(Job $job, array $payload) | ||||
|     { | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user      = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|         if ($job->attempts() > 10) { | ||||
|             \Log::error('Never found budget/transfer combination "' . $payload['data']['transfer_id'] . '"'); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */ | ||||
|         $journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); | ||||
|         $journals->overruleUser($user); | ||||
|  | ||||
|         /* | ||||
|          * Prep some vars from the payload | ||||
|          */ | ||||
|         $transferId = intval($payload['data']['transfer_id']); | ||||
|         $componentId   = intval($payload['data']['component_id']); | ||||
|  | ||||
|         /* | ||||
|          * Find the import map for both: | ||||
|          */ | ||||
|         $budgetMap      = $repository->findImportEntry($importMap, 'Budget', $componentId); | ||||
|         $transferMap = $repository->findImportEntry($importMap, 'Transfer', $transferId); | ||||
|  | ||||
|         /* | ||||
|          * Either may be null: | ||||
|          */ | ||||
|         if (is_null($budgetMap) || is_null($transferMap)) { | ||||
|             \Log::notice('No map found in budget/transfer mapper. Release.'); | ||||
|             if(\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Find the budget and the transaction: | ||||
|          */ | ||||
|         $budget = $this->find($budgetMap->new); | ||||
|         /** @var \TransactionJournal $journal */ | ||||
|         $journal = $journals->find($transferMap->new); | ||||
|  | ||||
|         /* | ||||
|          * If either is null, release: | ||||
|          */ | ||||
|         if (is_null($budget) || is_null($journal)) { | ||||
|             \Log::notice('Map is incorrect in budget/transfer mapper. Release.'); | ||||
|             if(\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Update journal to have budget: | ||||
|          */ | ||||
|         $journal->budgets()->save($budget); | ||||
|         $journal->save(); | ||||
|         \Log::debug('Connected budget "' . $budget->name . '" to journal "' . $journal->description . '"'); | ||||
|  | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|  | ||||
|         $job->delete(); // count fixed | ||||
|  | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Takes a transaction/budget component and updates the transaction journal to match. | ||||
|      * | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importUpdateTransaction(Job $job, array $payload) | ||||
|     { | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user      = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|         if ($job->attempts() > 10) { | ||||
|             \Log::error('Never found budget/transaction combination "' . $payload['data']['transaction_id'] . '"'); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */ | ||||
|         $journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); | ||||
|         $journals->overruleUser($user); | ||||
|  | ||||
|         /* | ||||
|          * Prep some vars from the payload | ||||
|          */ | ||||
|         $transactionId = intval($payload['data']['transaction_id']); | ||||
|         $componentId   = intval($payload['data']['component_id']); | ||||
|  | ||||
|         /* | ||||
|          * Find the import map for both: | ||||
|          */ | ||||
|         $budgetMap      = $repository->findImportEntry($importMap, 'Budget', $componentId); | ||||
|         $transactionMap = $repository->findImportEntry($importMap, 'Transaction', $transactionId); | ||||
|  | ||||
|         /* | ||||
|          * Either may be null: | ||||
|          */ | ||||
|         if (is_null($budgetMap) || is_null($transactionMap)) { | ||||
|             \Log::notice('No map found in budget/transaction mapper. Release.'); | ||||
|             if(\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Find the budget and the transaction: | ||||
|          */ | ||||
|         $budget = $this->find($budgetMap->new); | ||||
|         /** @var \TransactionJournal $journal */ | ||||
|         $journal = $journals->find($transactionMap->new); | ||||
|  | ||||
|         /* | ||||
|          * If either is null, release: | ||||
|          */ | ||||
|         if (is_null($budget) || is_null($journal)) { | ||||
|             \Log::notice('Map is incorrect in budget/transaction mapper. Release.'); | ||||
|             if(\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Update journal to have budget: | ||||
|          */ | ||||
|         $journal->budgets()->save($budget); | ||||
|         $journal->save(); | ||||
|         \Log::debug('Connected budget "' . $budget->name . '" to journal "' . $journal->description . '"'); | ||||
|  | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|  | ||||
|         $job->delete(); // count fixed | ||||
|  | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $budgetId | ||||
|      * | ||||
|      * @return \Budget|null | ||||
|      */ | ||||
|     public function find($budgetId) | ||||
|     { | ||||
|  | ||||
|         return $this->_user->budgets()->find($budgetId); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Budget $budget | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function destroy(\Budget $budget) | ||||
|     { | ||||
|         $budget->delete(); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function get() | ||||
|     { | ||||
|         $set = $this->_user->budgets()->with( | ||||
|             ['limits'                        => function ($q) { | ||||
|                     $q->orderBy('limits.startdate', 'DESC'); | ||||
|                 }, 'limits.limitrepetitions' => function ($q) { | ||||
|                     $q->orderBy('limit_repetitions.startdate', 'ASC'); | ||||
|                 }] | ||||
|         )->orderBy('name', 'ASC')->get(); | ||||
|         return $set; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Budget $budget | ||||
|      * @param         $data | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| <?php | ||||
|  | ||||
| namespace Firefly\Storage\Category; | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
|  | ||||
| /** | ||||
|  * Interface CategoryRepositoryInterface | ||||
| @@ -9,6 +10,33 @@ namespace Firefly\Storage\Category; | ||||
|  */ | ||||
| interface CategoryRepositoryInterface | ||||
| { | ||||
|     /** | ||||
|      * Takes a transaction/category component and updates the transaction journal to match. | ||||
|      * | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importUpdateTransaction(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * Takes a transfer/category component and updates the transaction journal to match. | ||||
|      * | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importUpdateTransfer(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importCategory(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
| @@ -27,7 +55,7 @@ interface CategoryRepositoryInterface | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function createOrFind($name); | ||||
|     public function firstOrCreate($name); | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|   | ||||
| @@ -2,6 +2,8 @@ | ||||
|  | ||||
| namespace Firefly\Storage\Category; | ||||
|  | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
|  | ||||
| /** | ||||
|  * Class EloquentCategoryRepository | ||||
|  * | ||||
| @@ -20,34 +22,112 @@ class EloquentCategoryRepository implements CategoryRepositoryInterface | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * Takes a transfer/category component and updates the transaction journal to match. | ||||
|      * | ||||
|      * @return \Category|mixed | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function createOrFind($name) | ||||
|     public function importUpdateTransfer(Job $job, array $payload) | ||||
|     { | ||||
|         if (strlen($name) == 0) { | ||||
|             return null; | ||||
|         } | ||||
|         $category = $this->findByName($name); | ||||
|         if (!$category) { | ||||
|             return $this->store(['name' => $name]); | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user      = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|  | ||||
|         if ($job->attempts() > 10) { | ||||
|             \Log::error('Never found category/transfer combination "' . $payload['data']['transfer_id'] . '"'); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed. | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         return $category; | ||||
|  | ||||
|         /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */ | ||||
|         $journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); | ||||
|         $journals->overruleUser($user); | ||||
|  | ||||
|         /* | ||||
|          * Prep some vars from the payload | ||||
|          */ | ||||
|         $transferId  = intval($payload['data']['transfer_id']); | ||||
|         $componentId = intval($payload['data']['component_id']); | ||||
|  | ||||
|         /* | ||||
|          * Find the import map for both: | ||||
|          */ | ||||
|         $categoryMap = $repository->findImportEntry($importMap, 'Category', $componentId); | ||||
|         $transferMap = $repository->findImportEntry($importMap, 'Transfer', $transferId); | ||||
|  | ||||
|         /* | ||||
|          * Either may be null: | ||||
|          */ | ||||
|         if (is_null($categoryMap) || is_null($transferMap)) { | ||||
|             \Log::notice('No map found in category/transfer mapper. Release.'); | ||||
|             if (\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Find the budget and the transaction: | ||||
|          */ | ||||
|         $category = $this->find($categoryMap->new); | ||||
|         /** @var \TransactionJournal $journal */ | ||||
|         $journal = $journals->find($transferMap->new); | ||||
|  | ||||
|         /* | ||||
|          * If either is null, release: | ||||
|          */ | ||||
|         if (is_null($category) || is_null($journal)) { | ||||
|             \Log::notice('Map is incorrect in category/transfer mapper. Release.'); | ||||
|             if (\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Update journal to have budget: | ||||
|          */ | ||||
|         $journal->categories()->save($category); | ||||
|         $journal->save(); | ||||
|         \Log::debug('Connected category "' . $category->name . '" to journal "' . $journal->description . '"'); | ||||
|  | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|  | ||||
|         $job->delete(); // count fixed | ||||
|  | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $category | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return bool|mixed | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function destroy($category) | ||||
|     public function overruleUser(\User $user) | ||||
|     { | ||||
|         $category->delete(); | ||||
|  | ||||
|         $this->_user = $user; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @@ -61,6 +141,164 @@ class EloquentCategoryRepository implements CategoryRepositoryInterface | ||||
|         return $this->_user->categories()->find($categoryId); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Takes a transaction/category component and updates the transaction journal to match. | ||||
|      * | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importUpdateTransaction(Job $job, array $payload) | ||||
|     { | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user      = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|  | ||||
|         if ($job->attempts() > 10) { | ||||
|             \Log::error('Never found category/transaction combination "' . $payload['data']['transaction_id'] . '"'); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed. | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */ | ||||
|         $journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); | ||||
|         $journals->overruleUser($user); | ||||
|  | ||||
|         /* | ||||
|          * Prep some vars from the payload | ||||
|          */ | ||||
|         $transactionId = intval($payload['data']['transaction_id']); | ||||
|         $componentId   = intval($payload['data']['component_id']); | ||||
|  | ||||
|         /* | ||||
|          * Find the import map for both: | ||||
|          */ | ||||
|         $categoryMap    = $repository->findImportEntry($importMap, 'Category', $componentId); | ||||
|         $transactionMap = $repository->findImportEntry($importMap, 'Transaction', $transactionId); | ||||
|  | ||||
|         /* | ||||
|          * Either may be null: | ||||
|          */ | ||||
|         if (is_null($categoryMap) || is_null($transactionMap)) { | ||||
|             \Log::notice('No map found in category/transaction mapper. Release.'); | ||||
|             if (\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Find the budget and the transaction: | ||||
|          */ | ||||
|         $category = $this->find($categoryMap->new); | ||||
|         /** @var \TransactionJournal $journal */ | ||||
|         $journal = $journals->find($transactionMap->new); | ||||
|  | ||||
|         /* | ||||
|          * If either is null, release: | ||||
|          */ | ||||
|         if (is_null($category) || is_null($journal)) { | ||||
|             \Log::notice('Map is incorrect in category/transaction mapper. Release.'); | ||||
|             if (\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Update journal to have budget: | ||||
|          */ | ||||
|         $journal->categories()->save($category); | ||||
|         $journal->save(); | ||||
|         \Log::debug('Connected category "' . $category->name . '" to journal "' . $journal->description . '"'); | ||||
|  | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|  | ||||
|         $job->delete(); // count fixed | ||||
|  | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importCategory(Job $job, array $payload) | ||||
|     { | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user      = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|         /* | ||||
|          * Maybe the category has already been imported | ||||
|          */ | ||||
|         $importEntry = $repository->findImportEntry($importMap, 'Category', intval($payload['data']['id'])); | ||||
|  | ||||
|         /* | ||||
|          * if so, delete job and return: | ||||
|          */ | ||||
|         if (!is_null($importEntry)) { | ||||
|             \Log::debug('Already imported category ' . $payload['data']['name']); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * try to find category first | ||||
|          */ | ||||
|         $current = $this->findByName($payload['data']['name']); | ||||
|  | ||||
|         /* | ||||
|          * If not found, create it: | ||||
|          */ | ||||
|         if (is_null($current)) { | ||||
|             $category = $this->store($payload['data']); | ||||
|             $repository->store($importMap, 'Category', $payload['data']['id'], $category->id); | ||||
|             \Log::debug('Imported category "' . $payload['data']['name'] . '".'); | ||||
|         } else { | ||||
|             $repository->store($importMap, 'Category', $payload['data']['id'], $current->id); | ||||
|             \Log::debug('Already had category "' . $payload['data']['name'] . '".'); | ||||
|         } | ||||
|  | ||||
|         // update map: | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|  | ||||
|         $job->delete(); // count fixed | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * | ||||
| @@ -72,18 +310,10 @@ class EloquentCategoryRepository implements CategoryRepositoryInterface | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         return $this->_user->categories()->where('name', 'LIKE', '%' . $name . '%')->first(); | ||||
|         return $this->_user->categories()->where('name', $name)->first(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function get() | ||||
|     { | ||||
|         return $this->_user->categories()->orderBy('name', 'ASC')->get(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $data | ||||
|      * | ||||
| @@ -100,6 +330,44 @@ class EloquentCategoryRepository implements CategoryRepositoryInterface | ||||
|         return $category; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $name | ||||
|      * | ||||
|      * @return \Category|mixed | ||||
|      */ | ||||
|     public function firstOrCreate($name) | ||||
|     { | ||||
|         if (strlen($name) == 0) { | ||||
|             return null; | ||||
|         } | ||||
|         $data = [ | ||||
|             'name'    => $name, | ||||
|             'user_id' => $this->_user->id, | ||||
|         ]; | ||||
|         return \Category::firstOrCreate($data); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $category | ||||
|      * | ||||
|      * @return bool|mixed | ||||
|      */ | ||||
|     public function destroy($category) | ||||
|     { | ||||
|         $category->delete(); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function get() | ||||
|     { | ||||
|         return $this->_user->categories()->orderBy('name', 'ASC')->get(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $category | ||||
|      * @param $data | ||||
| @@ -116,14 +384,4 @@ class EloquentCategoryRepository implements CategoryRepositoryInterface | ||||
|  | ||||
|         return $category; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
|     { | ||||
|         $this->_user = $user; | ||||
|         return true; | ||||
|     } | ||||
| }  | ||||
| @@ -1,37 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
|  | ||||
| namespace Firefly\Storage\Component; | ||||
|  | ||||
| /** | ||||
|  * Interface ComponentRepositoryInterface | ||||
|  * | ||||
|  * @package Firefly\Storage\Component | ||||
|  */ | ||||
| interface ComponentRepositoryInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function count(); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function get(); | ||||
|  | ||||
|     /** | ||||
|      * @param $data | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function store($data); | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function overruleUser(\User $user); | ||||
|  | ||||
| }  | ||||
| @@ -1,89 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
|  | ||||
| namespace Firefly\Storage\Component; | ||||
|  | ||||
| use Firefly\Exception\FireflyException; | ||||
| use Illuminate\Database\QueryException; | ||||
|  | ||||
| /** | ||||
|  * Class EloquentComponentRepository | ||||
|  * | ||||
|  * @package Firefly\Storage\Component | ||||
|  */ | ||||
| class EloquentComponentRepository implements ComponentRepositoryInterface | ||||
| { | ||||
|     public $validator; | ||||
|     protected $_user = null; | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      */ | ||||
|     public function __construct() | ||||
|     { | ||||
|         $this->_user = \Auth::user(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function count() | ||||
|     { | ||||
|         return $this->_user->components()->count(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed|void | ||||
|      * @throws \Firefly\Exception\FireflyException | ||||
|      */ | ||||
|     public function get() | ||||
|     { | ||||
|         throw new FireflyException('No implementation.'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
|     { | ||||
|         $this->_user = $user; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $data | ||||
|      * | ||||
|      * @return \Budget|\Category|mixed | ||||
|      * @throws \Firefly\Exception\FireflyException | ||||
|      */ | ||||
|     public function store($data) | ||||
|     { | ||||
|         if (!isset($data['class'])) { | ||||
|             throw new FireflyException('No class type present.'); | ||||
|         } | ||||
|         switch ($data['class']) { | ||||
|             default: | ||||
|             case 'Budget': | ||||
|                 $component = new \Budget; | ||||
|                 break; | ||||
|             case 'Category': | ||||
|                 $component = new \Category; | ||||
|                 break; | ||||
|  | ||||
|         } | ||||
|         $component->name = $data['name']; | ||||
|         $component->user()->associate($this->_user); | ||||
|         try { | ||||
|             $component->save(); | ||||
|         } catch (QueryException $e) { | ||||
|             \Log::error('DB ERROR: ' . $e->getMessage()); | ||||
|             throw new FireflyException('Could not save component ' . $data['name'] . ' of type' | ||||
|                 . $data['class']); | ||||
|         } | ||||
|  | ||||
|         return $component; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -19,10 +19,28 @@ interface ImportRepositoryInterface | ||||
|      */ | ||||
|     public function store(\Importmap $map, $class, $oldID, $newID); | ||||
|  | ||||
|     /** | ||||
|      * @param $id | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function findImportMap($id); | ||||
|  | ||||
|     /** | ||||
|      * @param \Importmap $map | ||||
|      * @param            $class | ||||
|      * @param            $oldID | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function findImportEntry(\Importmap $map, $class, $oldID); | ||||
|  | ||||
|     /** | ||||
|      * @param \Importmap $map | ||||
|      * @param            $oldComponentId | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function findImportComponentMap(\Importmap $map, $oldComponentId); | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -4,6 +4,7 @@ namespace Firefly\Storage\Limit; | ||||
|  | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
|  | ||||
| /** | ||||
|  * Class EloquentLimitRepository | ||||
| @@ -23,52 +24,103 @@ class EloquentLimitRepository implements LimitRepositoryInterface | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Limit $limit | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function destroy(\Limit $limit) | ||||
|     { | ||||
|         $limit->delete(); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $limitId | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function find($limitId) | ||||
|     public function importLimit(Job $job, array $payload) | ||||
|     { | ||||
|         return \Limit::with('limitrepetitions')->where('limits.id', $limitId)->leftJoin( | ||||
|                      'components', 'components.id', '=', 'limits.component_id' | ||||
|         ) | ||||
|                      ->where('components.user_id', $this->_user->id)->first(['limits.*']); | ||||
|     } | ||||
|  | ||||
|     public function findByBudgetAndDate(\Budget $budget, Carbon $date) | ||||
|     { | ||||
|         return \Limit::whereComponentId($budget->id)->where('startdate', $date->format('Y-m-d'))->first(); | ||||
|     } | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|     /** | ||||
|      * @param \Budget $budget | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getTJByBudgetAndDateRange(\Budget $budget, Carbon $start, Carbon $end) | ||||
|     { | ||||
|         $result = $budget->transactionjournals()->with('transactions')->after($start)->before($end)->get(); | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user      = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|         return $result; | ||||
|         if ($job->attempts() > 10) { | ||||
|             \Log::error( | ||||
|                 'No budget found for limit #' . $payload['data']['id'] . '. Prob. for another component. KILL!' | ||||
|             ); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed. | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budgets */ | ||||
|         $budgets = \App::make('Firefly\Storage\Budget\BudgetRepositoryInterface'); | ||||
|         $budgets->overruleUser($user); | ||||
|  | ||||
|         /* | ||||
|          * Find the budget this limit is part of: | ||||
|          */ | ||||
|         $importEntry = $repository->findImportEntry($importMap, 'Budget', intval($payload['data']['component_id'])); | ||||
|  | ||||
|         /* | ||||
|          * There is no budget (yet?) | ||||
|          */ | ||||
|         if (is_null($importEntry)) { | ||||
|             $componentId = intval($payload['data']['component_id']); | ||||
|             \Log::warning('Budget #' . $componentId . ' not found. Requeue import job.'); | ||||
|             if(\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Find budget import limit is for: | ||||
|          */ | ||||
|         $budget = $budgets->find($importEntry->new); | ||||
|         if (!is_null($budget)) { | ||||
|             /* | ||||
|              * Is actual limit already imported? | ||||
|              */ | ||||
|             $limit = $this->findByBudgetAndDate($budget, new Carbon($payload['data']['date'])); | ||||
|             if (is_null($limit)) { | ||||
|                 /* | ||||
|                  * It isn't imported yet. | ||||
|                  */ | ||||
|                 $payload['data']['budget_id'] = $budget->id; | ||||
|                 $payload['data']['startdate'] = $payload['data']['date']; | ||||
|                 $payload['data']['period']    = 'monthly'; | ||||
|                 /* | ||||
|                  * Store limit, and fire event for LimitRepetition. | ||||
|                  */ | ||||
|                 $limit = $this->store($payload['data']); | ||||
|                 $repository->store($importMap, 'Limit', $payload['data']['id'], $limit->id); | ||||
|                 \Event::fire('limits.store', [$limit]); | ||||
|                 \Log::debug('Imported limit for budget ' . $budget->name); | ||||
|             } else { | ||||
|                 /* | ||||
|                  * Limit already imported: | ||||
|                  */ | ||||
|                 $repository->store($importMap, 'Budget', $payload['data']['id'], $limit->id); | ||||
|             } | ||||
|         } else { | ||||
|             \Log::error(print_r($importEntry,true)); | ||||
|             \Log::error('Cannot import limit! Big bad error!'); | ||||
|         } | ||||
|  | ||||
|         // update map: | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|  | ||||
|         $job->delete(); // count fixed | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
| @@ -77,6 +129,11 @@ class EloquentLimitRepository implements LimitRepositoryInterface | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function findByBudgetAndDate(\Budget $budget, Carbon $date) | ||||
|     { | ||||
|         return \Limit::whereComponentId($budget->id)->where('startdate', $date->format('Y-m-d'))->first(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $data | ||||
|      * | ||||
| @@ -121,9 +178,9 @@ class EloquentLimitRepository implements LimitRepositoryInterface | ||||
|         // find existing: | ||||
|         $count = \Limit:: | ||||
|             leftJoin('components', 'components.id', '=', 'limits.component_id')->where( | ||||
|                        'components.user_id', $this->_user->id | ||||
|                 'components.user_id', $this->_user->id | ||||
|             )->where('startdate', $date->format('Y-m-d'))->where('component_id', $data['budget_id'])->where( | ||||
|                        'repeat_freq', $data['period'] | ||||
|                 'repeat_freq', $data['period'] | ||||
|             )->count(); | ||||
|         if ($count > 0) { | ||||
|             \Session::flash('error', 'There already is an entry for these parameters.'); | ||||
| @@ -144,6 +201,33 @@ class EloquentLimitRepository implements LimitRepositoryInterface | ||||
|         return $limit; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Limit $limit | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function destroy(\Limit $limit) | ||||
|     { | ||||
|         $limit->delete(); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Budget $budget | ||||
|      * @param Carbon  $start | ||||
|      * @param Carbon  $end | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getTJByBudgetAndDateRange(\Budget $budget, Carbon $start, Carbon $end) | ||||
|     { | ||||
|         $result = $budget->transactionjournals()->with('transactions')->after($start)->before($end)->get(); | ||||
|  | ||||
|         return $result; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Limit $limit | ||||
|      * @param        $data | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| namespace Firefly\Storage\Limit; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
|  | ||||
| /** | ||||
|  * Interface LimitRepositoryInterface | ||||
| @@ -12,6 +13,14 @@ use Carbon\Carbon; | ||||
| interface LimitRepositoryInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importLimit(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * @param \Limit $limit | ||||
|      * | ||||
| @@ -19,24 +28,19 @@ interface LimitRepositoryInterface | ||||
|      */ | ||||
|     public function destroy(\Limit $limit); | ||||
|  | ||||
|     /** | ||||
|      * @param $limitId | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function find($limitId); | ||||
|  | ||||
|     /** | ||||
|      * @param \Budget $budget | ||||
|      * @param Carbon $date | ||||
|      * @param Carbon  $date | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function findByBudgetAndDate(\Budget $budget, Carbon $date); | ||||
|  | ||||
|     /** | ||||
|      * @param \Budget $budget | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * @param Carbon  $start | ||||
|      * @param Carbon  $end | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
| @@ -59,6 +63,7 @@ interface LimitRepositoryInterface | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function overruleUser(\User $user); | ||||
|   | ||||
| @@ -4,6 +4,8 @@ namespace Firefly\Storage\Piggybank; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Firefly\Exception\FireflyException; | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
|  | ||||
| /** | ||||
| @@ -25,19 +27,140 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function count() | ||||
|     public function importPiggybank(Job $job, array $payload) | ||||
|     { | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user      = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|         if ($job->attempts() > 10) { | ||||
|             \Log::error('No account available for piggy bank "' . $payload['data']['name'] . '". KILL!'); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */ | ||||
|         $accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface'); | ||||
|         $accounts->overruleUser($user); | ||||
|  | ||||
|         /* | ||||
|          * Maybe the piggy bank has already been imported | ||||
|          */ | ||||
|         $importEntry = $repository->findImportEntry($importMap, 'Piggybank', intval($payload['data']['id'])); | ||||
|  | ||||
|         /* | ||||
|          * if so, delete job and return: | ||||
|          */ | ||||
|         if (!is_null($importEntry)) { | ||||
|             \Log::debug('Already imported piggy bank ' . $payload['data']['name']); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Try to find related piggybank: | ||||
|          */ | ||||
|         $piggyBank = $this->findByName($payload['data']['name']); | ||||
|  | ||||
|         /* | ||||
|          * Find an account (any account, really, at this point). | ||||
|          */ | ||||
|         $accountType = $accounts->findAccountType('Asset account'); | ||||
|  | ||||
|         /** @var Collection $set */ | ||||
|         $set = $accounts->getByAccountType($accountType); | ||||
|  | ||||
|         /* | ||||
|          * If there is an account to attach to this piggy bank, simply use that one. | ||||
|          */ | ||||
|         if ($set->count() > 0) { | ||||
|             /** @var \Account $account */ | ||||
|             $account                       = $set->first(); | ||||
|             $payload['data']['account_id'] = $account->id; | ||||
|         } else { | ||||
|             \Log::notice('No account available yet for piggy bank "' . $payload['data']['name'] . '".'); | ||||
|             if(\Config::get('queue.default') == 'sync') { | ||||
|                 $importMap->jobsdone++; | ||||
|                 $importMap->save(); | ||||
|                 $job->delete(); // count fixed | ||||
|             } else { | ||||
|                 $job->release(300); // proper release. | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * No existing piggy bank, create it: | ||||
|          */ | ||||
|         if (is_null($piggyBank)) { | ||||
|             $payload['data']['targetamount']  = floatval($payload['data']['target']); | ||||
|             $payload['data']['repeats']       = 0; | ||||
|             $payload['data']['rep_every']     = 1; | ||||
|             $payload['data']['reminder_skip'] = 1; | ||||
|             $payload['data']['rep_times']     = 1; | ||||
|             $piggyBank = $this->store($payload['data']); | ||||
|             /* | ||||
|              * Store and fire event. | ||||
|              */ | ||||
|             $repository->store($importMap, 'Piggybank', intval($payload['data']['id']), $piggyBank->id); | ||||
|             \Log::debug('Imported piggy "' . $payload['data']['name'] . '".'); | ||||
|             \Event::fire('piggybanks.store', [$piggyBank]); | ||||
|         } else { | ||||
|             /* | ||||
|              * Already have a piggy bank with this name, we skip it. | ||||
|              */ | ||||
|             $repository->store($importMap, 'Piggybank', $payload['data']['id'], $piggyBank->id); | ||||
|             \Log::debug('Already imported piggy "' . $payload['data']['name'] . '".'); | ||||
|         } | ||||
|         // update map: | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|  | ||||
|         $job->delete(); // count fixed | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
|     { | ||||
|         $this->_user = $user; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function findByName($piggyBankName) | ||||
|     { | ||||
|         return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where( | ||||
|                          'accounts.user_id', $this->_user->id | ||||
|         )->count(); | ||||
|             'accounts.user_id', $this->_user->id | ||||
|         )->where('piggybanks.name', $piggyBankName)->first(['piggybanks.*']); | ||||
|     } | ||||
|  | ||||
|     public function countNonrepeating() | ||||
|     { | ||||
|         return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where( | ||||
|                          'accounts.user_id', $this->_user->id | ||||
|             'accounts.user_id', $this->_user->id | ||||
|         )->where('repeats', 0)->count(); | ||||
|  | ||||
|     } | ||||
| @@ -45,7 +168,7 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface | ||||
|     public function countRepeating() | ||||
|     { | ||||
|         return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where( | ||||
|                          'accounts.user_id', $this->_user->id | ||||
|             'accounts.user_id', $this->_user->id | ||||
|         )->where('repeats', 1)->count(); | ||||
|     } | ||||
|  | ||||
| @@ -69,17 +192,10 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface | ||||
|     public function find($piggyBankId) | ||||
|     { | ||||
|         return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where( | ||||
|                          'accounts.user_id', $this->_user->id | ||||
|             'accounts.user_id', $this->_user->id | ||||
|         )->where('piggybanks.id', $piggyBankId)->first(['piggybanks.*']); | ||||
|     } | ||||
|  | ||||
|     public function findByName($piggyBankName) | ||||
|     { | ||||
|         return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where( | ||||
|                          'accounts.user_id', $this->_user->id | ||||
|         )->where('piggybanks.name', $piggyBankName)->first(['piggybanks.*']); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
| @@ -87,10 +203,6 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface | ||||
|     { | ||||
|         $piggies = $this->_user->piggybanks()->with(['account', 'piggybankrepetitions'])->get(); | ||||
|  | ||||
|         foreach ($piggies as $pig) { | ||||
|             $pig->leftInAccount = $this->leftOnAccount($pig->account); | ||||
|         } | ||||
|  | ||||
|         return $piggies; | ||||
|     } | ||||
|  | ||||
| @@ -130,16 +242,6 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
|     { | ||||
|         $this->_user = $user; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $data | ||||
|      * | ||||
| @@ -160,7 +262,7 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface | ||||
|         /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */ | ||||
|         $accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface'); | ||||
|         $accounts->overruleUser($this->_user); | ||||
|         $account  = isset($data['account_id']) ? $accounts->find($data['account_id']) : null; | ||||
|         $account = isset($data['account_id']) ? $accounts->find($data['account_id']) : null; | ||||
|  | ||||
|  | ||||
|         $piggyBank = new \Piggybank($data); | ||||
| @@ -216,7 +318,7 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface | ||||
|                 } | ||||
|                 if ($firstReminder > $piggyBank->targetdate) { | ||||
|                     $piggyBank->errors()->add( | ||||
|                               'reminder', 'The reminder has been set to remind you after the piggy bank will expire.' | ||||
|                         'reminder', 'The reminder has been set to remind you after the piggy bank will expire.' | ||||
|                     ); | ||||
|                     \Log::error('PiggyBank create-error: ' . $piggyBank->errors()->first()); | ||||
|  | ||||
| @@ -241,7 +343,7 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface | ||||
|         /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */ | ||||
|         $accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface'); | ||||
|         $accounts->overruleUser($this->_user); | ||||
|         $account  = isset($data['account_id']) ? $accounts->find($data['account_id']) : null; | ||||
|         $account = isset($data['account_id']) ? $accounts->find($data['account_id']) : null; | ||||
|  | ||||
|         if (!is_null($account)) { | ||||
|             $piggy->account()->associate($account); | ||||
| @@ -253,7 +355,8 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface | ||||
|         $piggy->reminder_skip = $data['reminder_skip']; | ||||
|         $piggy->targetdate    = strlen($data['targetdate']) > 0 ? new Carbon($data['targetdate']) : null; | ||||
|         $piggy->startdate | ||||
|                               = isset($data['startdate']) && strlen($data['startdate']) > 0 ? new Carbon($data['startdate']) : null; | ||||
|                               = | ||||
|             isset($data['startdate']) && strlen($data['startdate']) > 0 ? new Carbon($data['startdate']) : null; | ||||
|  | ||||
|  | ||||
|         foreach ($piggy->piggybankrepetitions()->get() as $rep) { | ||||
|   | ||||
| @@ -2,6 +2,8 @@ | ||||
|  | ||||
| namespace Firefly\Storage\Piggybank; | ||||
|  | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Interface LimitRepositoryInterface | ||||
| @@ -12,9 +14,12 @@ interface PiggybankRepositoryInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function count(); | ||||
|     public function importPiggybank(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
| @@ -81,6 +86,7 @@ interface PiggybankRepositoryInterface | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function overruleUser(\User $user); | ||||
|   | ||||
| @@ -4,6 +4,8 @@ | ||||
| namespace Firefly\Storage\RecurringTransaction; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
| use Illuminate\Support\MessageBag; | ||||
|  | ||||
| /** | ||||
|  * Class EloquentRecurringTransactionRepository | ||||
| @@ -13,16 +15,6 @@ use Carbon\Carbon; | ||||
| class EloquentRecurringTransactionRepository implements RecurringTransactionRepositoryInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
|     { | ||||
|         $this->_user = $user; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     protected $_user = null; | ||||
|  | ||||
|     /** | ||||
| @@ -45,11 +37,6 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function findByName($name) | ||||
|     { | ||||
|         return $this->_user->recurringtransactions()->where('name', 'LIKE', '%' . $name . '%')->first(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
| @@ -58,70 +45,178 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo | ||||
|         return $this->_user->recurringtransactions()->get(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Job $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importPredictable(Job $job, array $payload) | ||||
|     { | ||||
|         /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ | ||||
|         $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); | ||||
|  | ||||
|         /** @var \Importmap $importMap */ | ||||
|         $importMap = $repository->findImportmap($payload['mapID']); | ||||
|         $user = $importMap->user; | ||||
|         $this->overruleUser($user); | ||||
|  | ||||
|         /* | ||||
|          * maybe the recurring transaction is already imported: | ||||
|          */ | ||||
|         $oldId = intval($payload['data']['id']); | ||||
|         $description = $payload['data']['description']; | ||||
|         $importEntry = $repository->findImportEntry($importMap, 'RecurringTransaction', $oldId); | ||||
|  | ||||
|         /* | ||||
|          * if so, delete job and return: | ||||
|          */ | ||||
|         if (!is_null($importEntry)) { | ||||
|             \Log::debug('Already imported recurring transaction #' . $payload['data']['id']); | ||||
|  | ||||
|             $importMap->jobsdone++; | ||||
|             $importMap->save(); | ||||
|  | ||||
|             $job->delete(); // count fixed | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // try to find related recurring transaction: | ||||
|         $recurringTransaction = $this->findByName($payload['data']['description']); | ||||
|         if (is_null($recurringTransaction)) { | ||||
|             $amount = floatval($payload['data']['amount']); | ||||
|             $pct = intval($payload['data']['pct']); | ||||
|  | ||||
|             $set = [ | ||||
|                 'name' => $description, | ||||
|                 'match' => join(',', explode(' ', $description)), | ||||
|                 'amount_min' => $amount * ($pct / 100) * -1, | ||||
|                 'amount_max' => $amount * (1 + ($pct / 100)) * -1, | ||||
|                 'date' => date('Y-m-') . $payload['data']['dom'], | ||||
|                 'repeat_freq' => 'monthly', | ||||
|                 'active' => intval($payload['data']['inactive']) == 1 ? 0 : 1, | ||||
|                 'automatch' => 1, | ||||
|             ]; | ||||
|  | ||||
|             $recurringTransaction = $this->store($set); | ||||
|             $this->store($importMap, 'RecurringTransaction', $oldId, $recurringTransaction->id); | ||||
|             \Log::debug('Imported predictable ' . $description); | ||||
|         } else { | ||||
|             $this->store($importMap, 'RecurringTransaction', $oldId, $recurringTransaction->id); | ||||
|             \Log::debug('Already had predictable ' . $description); | ||||
|         } | ||||
|         // update map: | ||||
|         $importMap->jobsdone++; | ||||
|         $importMap->save(); | ||||
|  | ||||
|         $job->delete(); // count fixed | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function overruleUser(\User $user) | ||||
|     { | ||||
|         $this->_user = $user; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function findByName($name) | ||||
|     { | ||||
|         return $this->_user->recurringtransactions()->where('name', 'LIKE', '%' . $name . '%')->first(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $data | ||||
|      * | ||||
|      * @return mixed|\RecurringTransaction | ||||
|      * @return MessageBag | ||||
|      */ | ||||
|     public function store($data) | ||||
|     { | ||||
|         $recurringTransaction = new \RecurringTransaction; | ||||
|         $recurringTransaction->user()->associate($this->_user); | ||||
|         $recurringTransaction->name       = $data['name']; | ||||
|         $recurringTransaction->match      = join(' ', explode(',', $data['match'])); | ||||
|         $recurringTransaction->amount_max = floatval($data['amount_max']); | ||||
|         $recurringTransaction->amount_min = floatval($data['amount_min']); | ||||
|         $messageBag = new MessageBag; | ||||
|         $recurringTransaction = new \RecurringTransaction( | ||||
|             [ | ||||
|                 'user_id' => $this->_user->id, | ||||
|                 'name' => $data['name'], | ||||
|                 'match' => join(' ', explode(',', $data['match'])), | ||||
|                 'amount_max' => floatval($data['amount_max']), | ||||
|                 'amount_min' => floatval($data['amount_min']), | ||||
|                 'date' => new Carbon($data['date']), | ||||
|                 'active' => isset($data['active']) ? intval($data['active']) : 0, | ||||
|                 'automatch' => isset($data['automatch']) ? intval($data['automatch']) : 0, | ||||
|                 'skip' => isset($data['skip']) ? intval($data['skip']) : 0, | ||||
|                 'repeat_freq' => $data['repeat_freq'], | ||||
|             ] | ||||
|         ); | ||||
|  | ||||
|         // both amounts zero: | ||||
|         if ($recurringTransaction->amount_max == 0 && $recurringTransaction->amount_min == 0) { | ||||
|             $recurringTransaction->errors()->add('amount_max', 'Amount max and min cannot both be zero.'); | ||||
|  | ||||
|             return $recurringTransaction; | ||||
|         // unique name? | ||||
|         $count = $this->_user->recurringtransactions()->whereName($data['name'])->count(); | ||||
|         if ($count > 0) { | ||||
|             $messageBag->add('name', 'A recurring transaction with this name already exists.'); | ||||
|             return $messageBag; | ||||
|         } | ||||
|  | ||||
|         $recurringTransaction->date        = new Carbon($data['date']); | ||||
|         $recurringTransaction->active      = isset($data['active']) ? intval($data['active']) : 0; | ||||
|         $recurringTransaction->automatch   = isset($data['automatch']) ? intval($data['automatch']) : 0; | ||||
|         $recurringTransaction->skip        = isset($data['skip']) ? intval($data['skip']) : 0; | ||||
|         $recurringTransaction->repeat_freq = $data['repeat_freq']; | ||||
|         // both amounts zero?: | ||||
|         if ($recurringTransaction->amount_max == 0 && $recurringTransaction->amount_min == 0) { | ||||
|             $messageBag->add('amount_max', 'Amount max and min cannot both be zero.'); | ||||
|             return $messageBag; | ||||
|         } | ||||
|  | ||||
|         if ($recurringTransaction->amount_max < $recurringTransaction->amount_min) { | ||||
|             $messageBag->add('amount_max', 'Amount max must be more than amount min.'); | ||||
|             return $messageBag; | ||||
|         } | ||||
|  | ||||
|         if ($recurringTransaction->amount_min > $recurringTransaction->amount_max) { | ||||
|             $messageBag->add('amount_max', 'Amount min must be less than amount max.'); | ||||
|             return $messageBag; | ||||
|         } | ||||
|  | ||||
|         if ($recurringTransaction->validate()) { | ||||
|             $recurringTransaction->save(); | ||||
|         } else { | ||||
|             $messageBag = $recurringTransaction->errors(); | ||||
|         } | ||||
|  | ||||
|         return $recurringTransaction; | ||||
|         return $messageBag; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \RecurringTransaction $recurringTransaction | ||||
|      * @param                       $data | ||||
|      * | ||||
|      * @return mixed|void | ||||
|      * @return MessageBag | ||||
|      */ | ||||
|     public function update(\RecurringTransaction $recurringTransaction, $data) | ||||
|     { | ||||
|         $recurringTransaction->name       = $data['name']; | ||||
|         $recurringTransaction->match      = join(' ', explode(',', $data['match'])); | ||||
|         $messageBag = new MessageBag; | ||||
|         $recurringTransaction->name = $data['name']; | ||||
|         $recurringTransaction->match = join(' ', explode(',', $data['match'])); | ||||
|         $recurringTransaction->amount_max = floatval($data['amount_max']); | ||||
|         $recurringTransaction->amount_min = floatval($data['amount_min']); | ||||
|  | ||||
|         // both amounts zero: | ||||
|         if ($recurringTransaction->amount_max == 0 && $recurringTransaction->amount_min == 0) { | ||||
|             $recurringTransaction->errors()->add('amount_max', 'Amount max and min cannot both be zero.'); | ||||
|             $messageBag->add('amount_max', 'Amount max and min cannot both be zero.'); | ||||
|  | ||||
|             return $recurringTransaction; | ||||
|             return $messageBag; | ||||
|         } | ||||
|         $recurringTransaction->date        = new Carbon($data['date']); | ||||
|         $recurringTransaction->active      = isset($data['active']) ? intval($data['active']) : 0; | ||||
|         $recurringTransaction->automatch   = isset($data['automatch']) ? intval($data['automatch']) : 0; | ||||
|         $recurringTransaction->skip        = isset($data['skip']) ? intval($data['skip']) : 0; | ||||
|         $recurringTransaction->date = new Carbon($data['date']); | ||||
|         $recurringTransaction->active = isset($data['active']) ? intval($data['active']) : 0; | ||||
|         $recurringTransaction->automatch = isset($data['automatch']) ? intval($data['automatch']) : 0; | ||||
|         $recurringTransaction->skip = isset($data['skip']) ? intval($data['skip']) : 0; | ||||
|         $recurringTransaction->repeat_freq = $data['repeat_freq']; | ||||
|  | ||||
|         if ($recurringTransaction->validate()) { | ||||
|             $recurringTransaction->save(); | ||||
|         } else { | ||||
|             $messageBag = $recurringTransaction->errors(); | ||||
|         } | ||||
|  | ||||
|         return $recurringTransaction; | ||||
|         return $messageBag; | ||||
|  | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,8 @@ | ||||
|  | ||||
|  | ||||
| namespace Firefly\Storage\RecurringTransaction; | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
| use Illuminate\Support\MessageBag; | ||||
|  | ||||
| /** | ||||
|  * Interface RecurringTransactionRepositoryInterface | ||||
| @@ -11,6 +13,14 @@ namespace Firefly\Storage\RecurringTransaction; | ||||
| interface RecurringTransactionRepositoryInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importPredictable(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
| @@ -25,7 +35,7 @@ interface RecurringTransactionRepositoryInterface | ||||
|     /** | ||||
|      * @param $data | ||||
|      * | ||||
|      * @return mixed | ||||
|      * @return MessageBag | ||||
|      */ | ||||
|     public function store($data); | ||||
|  | ||||
| @@ -40,7 +50,7 @@ interface RecurringTransactionRepositoryInterface | ||||
|      * @param \RecurringTransaction $recurringTransaction | ||||
|      * @param                       $data | ||||
|      * | ||||
|      * @return mixed | ||||
|      * @return MessageBag | ||||
|      */ | ||||
|     public function update(\RecurringTransaction $recurringTransaction, $data); | ||||
|  | ||||
|   | ||||
| @@ -31,61 +31,4 @@ class EloquentReminderRepository implements ReminderRepositoryInterface | ||||
|     { | ||||
|         $this->_user = \Auth::user(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Reminder $reminder | ||||
|      * | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function deactivate(\Reminder $reminder) | ||||
|     { | ||||
|         $reminder->active = 0; | ||||
|         $reminder->save(); | ||||
|  | ||||
|         return $reminder; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $id | ||||
|      * | ||||
|      * @return mixed|void | ||||
|      */ | ||||
|     public function find($id) | ||||
|     { | ||||
|         return \Reminder::find($id); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function get() | ||||
|     { | ||||
|         $today = new Carbon; | ||||
|  | ||||
|         return $this->_user->reminders()->validOn($today)->get(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getPiggybankReminders() | ||||
|     { | ||||
|         $today = new Carbon; | ||||
|  | ||||
|         return $this->_user->reminders()->where('class','PiggybankReminder')->validOn($today)->get(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      */ | ||||
|     public function getCurrentRecurringReminders() | ||||
|     { | ||||
|         $today = new Carbon; | ||||
|  | ||||
|         return $this->_user->reminders()->with('recurringtransaction')->validOn($today)->where( | ||||
|                     'class', 'RecurringTransactionReminder' | ||||
|         )->get(); | ||||
|  | ||||
|     } | ||||
|  | ||||
| }  | ||||
| } | ||||
| @@ -1,11 +1,4 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Created by PhpStorm. | ||||
|  * User: sander | ||||
|  * Date: 23/08/14 | ||||
|  * Time: 20:59 | ||||
|  */ | ||||
|  | ||||
| namespace Firefly\Storage\Reminder; | ||||
|  | ||||
|  | ||||
| @@ -17,28 +10,6 @@ namespace Firefly\Storage\Reminder; | ||||
| interface ReminderRepositoryInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * @param \Reminder $reminder | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function deactivate(\Reminder $reminder); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function get(); | ||||
|  | ||||
|     /** | ||||
|      * @param $id | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function find($id); | ||||
|  | ||||
|  | ||||
|     public function getCurrentRecurringReminders(); | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * @return mixed | ||||
|   | ||||
| @@ -55,11 +55,6 @@ class StorageServiceProvider extends ServiceProvider | ||||
|                       'Firefly\Storage\TransactionJournal\EloquentTransactionJournalRepository' | ||||
|         ); | ||||
|  | ||||
|         $this->app->bind( | ||||
|                   'Firefly\Storage\Component\ComponentRepositoryInterface', | ||||
|                       'Firefly\Storage\Component\EloquentComponentRepository' | ||||
|         ); | ||||
|  | ||||
|         $this->app->bind( | ||||
|                   'Firefly\Storage\Limit\LimitRepositoryInterface', | ||||
|                       'Firefly\Storage\Limit\EloquentLimitRepository' | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -3,6 +3,8 @@ | ||||
| namespace Firefly\Storage\TransactionJournal; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Illuminate\Queue\Jobs\Job; | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
| /** | ||||
|  * Interface TransactionJournalRepositoryInterface | ||||
| @@ -12,40 +14,58 @@ use Carbon\Carbon; | ||||
| interface TransactionJournalRepositoryInterface | ||||
| { | ||||
|     /** | ||||
|      * @param \Account $from | ||||
|      * @param \Account $toAccount | ||||
|      * @param          $description | ||||
|      * @param          $amount | ||||
|      * @param Carbon $date | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function createSimpleJournal(\Account $from, \Account $toAccount, $description, $amount, Carbon $date); | ||||
|     public function importTransaction(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * @return mixed | ||||
|      * Get them ALL | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function get(); | ||||
|  | ||||
|     /** | ||||
|      * @param Job   $job | ||||
|      * @param array $payload | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function importTransfer(Job $job, array $payload); | ||||
|  | ||||
|     /** | ||||
|      * @param \User $user | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function overruleUser(\User $user); | ||||
|  | ||||
|     /** | ||||
|      * @param $what | ||||
|      * Store a new transaction journal. | ||||
|      * | ||||
|      * @param $data | ||||
|      * | ||||
|      * @return \TransactionJournal|null | ||||
|      */ | ||||
|     public function store(array $data); | ||||
|  | ||||
|     /** | ||||
|      * @param \TransactionJournal $journal | ||||
|      * @param \Account            $account | ||||
|      * @param                     $amount | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function store($what, $data); | ||||
|     public function saveTransaction(\TransactionJournal $journal, \Account $account, $amount); | ||||
|  | ||||
|     /** | ||||
|      * @param \TransactionJournal $journal | ||||
|      * @param                     $data | ||||
|      * | ||||
|      * @return mixed | ||||
|      * @return \Transaction|null | ||||
|      */ | ||||
|     public function update(\TransactionJournal $journal, $data); | ||||
|  | ||||
| @@ -58,27 +78,11 @@ interface TransactionJournalRepositoryInterface | ||||
|  | ||||
|     /** | ||||
|      * @param \Account $account | ||||
|      * @param int $count | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * @param int      $count | ||||
|      * @param Carbon   $start | ||||
|      * @param Carbon   $end | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getByAccountInDateRange(\Account $account, $count = 25, Carbon $start, Carbon $end); | ||||
|  | ||||
|     /** | ||||
|      * @param \Account $account | ||||
|      * @param Carbon $date | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function getByAccountAndDate(\Account $account, Carbon $date); | ||||
|  | ||||
|     /** | ||||
|      * @param int $count | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function paginate($count = 25, Carbon $start = null, Carbon $end = null); | ||||
|  | ||||
| } | ||||
| @@ -17,22 +17,6 @@ class EloquentUserRepository implements UserRepositoryInterface | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $array | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function auth($array) | ||||
|     { | ||||
|         $user = \User::where('email', $array['email'])->first(); | ||||
|         if (!is_null($user)) { | ||||
|             if (\Hash::check($array['password'], $user->password)) { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param $email | ||||
|      * | ||||
|   | ||||
| @@ -17,13 +17,6 @@ interface UserRepositoryInterface | ||||
|      */ | ||||
|     public function register($array); | ||||
|  | ||||
|     /** | ||||
|      * @param $array | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function auth($array); | ||||
|  | ||||
|     /** | ||||
|      * @param $reset | ||||
|      * | ||||
|   | ||||
| @@ -20,54 +20,22 @@ class EloquentJournalTrigger | ||||
|      */ | ||||
|     public function store(\TransactionJournal $journal) | ||||
|     { | ||||
|         // select all reminders for recurring transactions: | ||||
|         if ($journal->transaction_type->type == 'Withdrawal') { | ||||
|             \Log::debug('Trigger on the creation of a withdrawal'); | ||||
|             $transaction = $journal->transactions()->orderBy('amount', 'DESC')->first(); | ||||
|             $amount      = floatval($transaction->amount); | ||||
|             $description = strtolower($journal->description); | ||||
|             $beneficiary = strtolower($transaction->account->name); | ||||
|         /* | ||||
|          * Grab all recurring events. | ||||
|          */ | ||||
|         $set    = $journal->user()->first()->recurringtransactions()->get(); | ||||
|         $result = []; | ||||
|         /* | ||||
|          * Prep vars | ||||
|          */ | ||||
|         $description = strtolower($journal->description); | ||||
|         $result      = [0 => 0]; | ||||
|  | ||||
|             // make an array of parts: | ||||
|             $parts   = explode(' ', $description); | ||||
|             $parts[] = $beneficiary; | ||||
|             $today   = new Carbon; | ||||
|             $set     = \RecurringTransactionReminder:: | ||||
|                 leftJoin( | ||||
|                     'recurring_transactions', 'recurring_transactions.id', '=', 'reminders.recurring_transaction_id' | ||||
|                 ) | ||||
|                 ->where('startdate', '<', $today->format('Y-m-d')) | ||||
|                 ->where('enddate', '>', $today->format('Y-m-d')) | ||||
|                 ->where('amount_min', '<=', $amount) | ||||
|                 ->where('amount_max', '>=', $amount)->get(['reminders.*']); | ||||
|             /** @var \RecurringTransctionReminder $reminder */ | ||||
|             \Log::debug('Have these parts to search for: ' . join('/',$parts)); | ||||
|             \Log::debug('Found ' . count($set).' possible matching recurring transactions'); | ||||
|             foreach ($set as $index => $reminder) { | ||||
|                 /** @var \RecurringTransaction $RT */ | ||||
|                 $RT         = $reminder->recurring_transaction; | ||||
|                 $matches    = explode(' ', strtolower($RT->match)); | ||||
|                 \Log::debug($index.': ' . join('/',$matches)); | ||||
|                 $matchCount = 0; | ||||
|                 foreach ($parts as $part) { | ||||
|                     if (in_array($part, $matches)) { | ||||
|                         $matchCount++; | ||||
|                     } | ||||
|                 } | ||||
|                 if ($matchCount >= count($matches)) { | ||||
|                     // we have a match! | ||||
|                     \Log::debug( | ||||
|                         'Match between new journal "' . join('/', $parts) . '" and RT ' . join('/', $matches) . '.' | ||||
|                     ); | ||||
|                     $journal->recurringTransaction()->associate($RT); | ||||
|                     $journal->save(); | ||||
|                     // also update the reminder. | ||||
|                     $reminder->active = 0; | ||||
|                     $reminder->save(); | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|         /** @var \RecurringTransaction $recurring */ | ||||
|         foreach ($set as $recurring) { | ||||
|             \Event::fire('recurring.rescan', [$recurring, $journal]); | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|  | ||||
|     } | ||||
|   | ||||
| @@ -85,7 +85,7 @@ class EloquentLimitTrigger | ||||
|      */ | ||||
|     public function madeRepetition(\LimitRepetition $repetition) | ||||
|     { | ||||
|         \Log::info('TRIGGER: Created a limit repetition  (#' . $repetition->id . ')'); | ||||
|         \Log::debug('TRIGGER: Created a limit repetition  (#' . $repetition->id . ')'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -107,159 +107,6 @@ class EloquentPiggybankTrigger | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Whenever a repetition is made, the decision is there to make reminders for it. Or not. | ||||
|      * Some combinations are "invalid" or impossible and will never trigger reminders. Others do. | ||||
|      * | ||||
|      * The numbers below refer to a small list I made in a text-file (it no longer exists) which contained the eight | ||||
|      * binary combinations that can be made of three properties each piggy bank has (among others): | ||||
|      * | ||||
|      * - Whether or not it has a start date. | ||||
|      * - Whether or not it has an end date. | ||||
|      * - Whether or not the piggy bank repeats itself. | ||||
|      * | ||||
|      * @SuppressWarnings(PHPMD.ExcessiveMethodLength) | ||||
|      * @SuppressWarnings(PHPMD.NPathComplexity) | ||||
|      * @SuppressWarnings(PHPMD.CyclomaticComplexity) | ||||
|      * | ||||
|      * @param \PiggybankRepetition $repetition | ||||
|      * | ||||
|      * @return null | ||||
|      */ | ||||
|     public function createdRepetition(\PiggybankRepetition $repetition) | ||||
|     { | ||||
|         \Log::debug('TRIGGER on createdRepetition() for repetition #' . $repetition->id); | ||||
|  | ||||
|         $piggyBank = $repetition->piggybank; | ||||
|  | ||||
|         // first, exclude all combinations that will not generate (valid) reminders | ||||
|  | ||||
|         // no reminders needed (duh) | ||||
|         if (is_null(($piggyBank->reminder))) { | ||||
|             \Log::debug('No reminders because no reminder needed.'); | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         // no start, no target, no repeat (#1): | ||||
|         if (is_null($piggyBank->startdate) && is_null($piggyBank->targetdate) && $piggyBank->repeats == 0) { | ||||
|             \Log::debug('No reminders because no start, no target, no repeat (#1)'); | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         // no start, but repeats (#5): | ||||
|         if (is_null($piggyBank->startdate) && $piggyBank->repeats == 1) { | ||||
|             \Log::debug('No reminders because no start, but repeats (#5)'); | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         // no start, no end, but repeats (#6) | ||||
|         if (is_null($piggyBank->startdate) && is_null($piggyBank->targetdate) && $piggyBank->repeats == 1) { | ||||
|             \Log::debug('No reminders because no start, no end, but repeats (#6)'); | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         // no end, but repeats (#7) | ||||
|         if (is_null($piggyBank->targetdate) && $piggyBank->repeats == 1) { | ||||
|             \Log::debug('No reminders because no end, but repeats (#7)'); | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         \Log::debug('Will continue...'); | ||||
|         /* | ||||
|          * #2, #3, #4 and #8 are valid combo's. | ||||
|          * | ||||
|          * We add two years to the end when the repetition has no target date; we "pretend" there is a target date. | ||||
|          * | ||||
|          */ | ||||
|         if (is_null($repetition->targetdate)) { | ||||
|             $end = new Carbon; | ||||
|             $end->addYears(2); | ||||
|         } else { | ||||
|             $end = $repetition->targetdate; | ||||
|         } | ||||
|         /* | ||||
|          * If there is no start date, the start dat becomes right now. | ||||
|          */ | ||||
|         if (is_null($repetition->startdate)) { | ||||
|             $start = new Carbon; | ||||
|         } else { | ||||
|             $start = $repetition->startdate; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Firefly checks every period X between $start and $end and if necessary creates a reminder. Firefly | ||||
|          * only creates reminders if the $current date is after today. Piggy banks may have their start in the past. | ||||
|          * | ||||
|          * This loop will jump a month when the reminder is set monthly, a week when it's set weekly, etcetera. | ||||
|          */ | ||||
|         $current = $start; | ||||
|         $today   = new Carbon; | ||||
|         $today->startOfDay(); | ||||
|         while ($current <= $end) { | ||||
|             \Log::debug('Looping reminder dates; now at ' . $current); | ||||
|             /* | ||||
|              * Piggy bank reminders start X days before the actual date of the event. | ||||
|              */ | ||||
|             $reminderStart = clone $current; | ||||
|             switch ($piggyBank->reminder) { | ||||
|                 case 'day': | ||||
|                     $reminderStart->subDay(); | ||||
|                     break; | ||||
|                 case 'week': | ||||
|                     $reminderStart->subDays(4); | ||||
|                     break; | ||||
|                 case 'month': | ||||
|                     $reminderStart->subDays(21); | ||||
|                     break; | ||||
|                 case 'year': | ||||
|                     $reminderStart->subMonths(9); | ||||
|                     break; | ||||
|             } | ||||
|  | ||||
|             /* | ||||
|              * If the date is past today we create a reminder, otherwise we don't. The end date is the date | ||||
|              * the reminder is due; after that it is invalid. | ||||
|              */ | ||||
|             if ($current >= $today) { | ||||
|                 $reminder = new \PiggybankReminder; | ||||
|                 $reminder->piggybank()->associate($piggyBank); | ||||
|                 $reminder->user()->associate(\Auth::user()); | ||||
|                 $reminder->startdate = $reminderStart; | ||||
|                 $reminder->enddate   = $current; | ||||
|                 $reminder->active    = 1; | ||||
|                 \Log::debug('Will create a reminder. Is it valid?'); | ||||
|                 \Log::debug($reminder->validate()); | ||||
|                 try { | ||||
|  | ||||
|                     $reminder->save(); | ||||
|                 } catch (QueryException $e) { | ||||
|                     \Log::error('Could not save reminder: ' . $e->getMessage()); | ||||
|                 } | ||||
|             } else { | ||||
|                 \Log::debug('Current is before today, will not make a reminder.'); | ||||
|             } | ||||
|  | ||||
|             /* | ||||
|              * Here Firefly jumps ahead to the next reminder period. | ||||
|              */ | ||||
|             switch ($piggyBank->reminder) { | ||||
|                 case 'day': | ||||
|                     $current->addDays($piggyBank->reminder_skip); | ||||
|                     break; | ||||
|                 case 'week': | ||||
|                     $current->addWeeks($piggyBank->reminder_skip); | ||||
|                     break; | ||||
|                 case 'month': | ||||
|                     $current->addMonths($piggyBank->reminder_skip); | ||||
|                     break; | ||||
|                 case 'year': | ||||
|                     $current->addYears($piggyBank->reminder_skip); | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param \Piggybank $piggyBank | ||||
|      * | ||||
| @@ -267,13 +114,6 @@ class EloquentPiggybankTrigger | ||||
|      */ | ||||
|     public function destroy(\Piggybank $piggyBank) | ||||
|     { | ||||
|         $reminders = $piggyBank->piggybankreminders()->get(); | ||||
|         /** @var \PiggybankReminder $reminder */ | ||||
|         foreach ($reminders as $reminder) { | ||||
|             $reminder->delete(); | ||||
|  | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @@ -356,9 +196,6 @@ class EloquentPiggybankTrigger | ||||
|             'piggybanks.check', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@checkRepeatingPiggies' | ||||
|         ); | ||||
|  | ||||
|         $events->listen( | ||||
|             'piggybanks.repetition', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@createdRepetition' | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| namespace Firefly\Trigger\Recurring; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Firefly\Exception\FireflyException; | ||||
| use Illuminate\Events\Dispatcher; | ||||
|  | ||||
| /** | ||||
| @@ -18,14 +19,6 @@ class EloquentRecurringTrigger | ||||
|      */ | ||||
|     public function destroy(\RecurringTransaction $recurring) | ||||
|     { | ||||
|         $reminders = $recurring->recurringtransactionreminders()->get(); | ||||
|         /** @var \RecurringTransactionReminder $reminder */ | ||||
|         foreach ($reminders as $reminder) { | ||||
|             $reminder->delete(); | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -33,65 +26,68 @@ class EloquentRecurringTrigger | ||||
|      */ | ||||
|     public function store(\RecurringTransaction $recurring) | ||||
|     { | ||||
|         $this->createReminders(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public function createReminders() | ||||
|     /** | ||||
|      * @param \RecurringTransaction $recurring | ||||
|      * @param \TransactionJournal $journal | ||||
|      */ | ||||
|     public function rescan(\RecurringTransaction $recurring, \TransactionJournal $journal) | ||||
|     { | ||||
|         $entries = \Auth::user()->recurringtransactions()->where('active', 1)->get(); | ||||
|         /* | ||||
|          * Match words. | ||||
|          */ | ||||
|         $wordMatch   = false; | ||||
|         $matches     = explode(' ', $recurring->match); | ||||
|         $description = strtolower($journal->description); | ||||
|  | ||||
|         // for each entry, check for existing reminders during their period: | ||||
|         /** @var \RecurringTransaction $entry */ | ||||
|         foreach ($entries as $entry) { | ||||
|  | ||||
|             $start = clone $entry->date; | ||||
|             $end = clone $entry->date; | ||||
|             switch ($entry->repeat_freq) { | ||||
|                 case 'weekly': | ||||
|                     $start->startOfWeek(); | ||||
|                     $end->endOfWeek(); | ||||
|                     break; | ||||
|                 case 'monthly': | ||||
|                     $start->startOfMonth(); | ||||
|                     $end->endOfMonth(); | ||||
|                     break; | ||||
|                 case 'quarterly': | ||||
|                     $start->firstOfQuarter(); | ||||
|                     $end->lastOfQuarter(); | ||||
|                     break; | ||||
|                 case 'half-year': | ||||
|                     // start of half-year: | ||||
|                     if (intval($start->format('m')) >= 7) { | ||||
|                         $start->startOfYear(); | ||||
|                         $start->addMonths(6); | ||||
|                     } else { | ||||
|                         $start->startOfYear(); | ||||
|                     } | ||||
|                     $end = clone $start; | ||||
|                     $end->addMonths(6); | ||||
|                     break; | ||||
|                 case 'yearly': | ||||
|                     $start->startOfYear(); | ||||
|                     $end->endOfYear(); | ||||
|                     break; | ||||
|         /* | ||||
|          * Attach expense account to description for more narrow matching. | ||||
|          */ | ||||
|         $transactions = $journal->transactions()->get(); | ||||
|         /** @var \Transaction $transaction */ | ||||
|         foreach ($transactions as $transaction) { | ||||
|             /** @var \Account $account */ | ||||
|             $account = $transaction->account()->first(); | ||||
|             /** @var \AccountType $type */ | ||||
|             $type = $account->accountType()->first(); | ||||
|             if ($type->type == 'Expense account' || $type->type == 'Beneficiary account') { | ||||
|                 $description .= ' ' . strtolower($account->name); | ||||
|             } | ||||
|             // check if exists. | ||||
|             $count = $entry->reminders()->where('startdate', $start->format('Y-m-d'))->where( | ||||
|                 'enddate', $end->format('Y-m-d') | ||||
|             )->count(); | ||||
|             if ($count == 0) { | ||||
|                 // create reminder: | ||||
|                 $reminder = new \RecurringTransactionReminder; | ||||
|                 $reminder->recurringtransaction()->associate($entry); | ||||
|                 $reminder->startdate = $start; | ||||
|                 $reminder->enddate = $end; | ||||
|                 $reminder->active = 1; | ||||
|                 $reminder->user()->associate(\Auth::user()); | ||||
|                 $reminder->save(); | ||||
|         } | ||||
|  | ||||
|         $count = 0; | ||||
|         foreach ($matches as $word) { | ||||
|             if (!(strpos($description, strtolower($word)) === false)) { | ||||
|                 $count++; | ||||
|             } | ||||
|         } | ||||
|         if ($count >= count($matches)) { | ||||
|             $wordMatch = true; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * Match amount. | ||||
|          */ | ||||
|  | ||||
|         $amountMatch = false; | ||||
|         if (count($transactions) > 1) { | ||||
|  | ||||
|             $amount = max(floatval($transactions[0]->amount), floatval($transactions[1]->amount)); | ||||
|             $min    = floatval($recurring->amount_min); | ||||
|             $max    = floatval($recurring->amount_max); | ||||
|             if ($amount >= $min && $amount <= $max) { | ||||
|                 $amountMatch = true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * If both, update! | ||||
|          */ | ||||
|         if ($wordMatch && $amountMatch) { | ||||
|             $journal->recurringTransaction()->associate($recurring); | ||||
|             $journal->save(); | ||||
|         } | ||||
|  | ||||
|     } | ||||
| @@ -103,10 +99,7 @@ class EloquentRecurringTrigger | ||||
|      */ | ||||
|     public function subscribe(Dispatcher $events) | ||||
|     { | ||||
|         $events->listen('recurring.destroy', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@destroy'); | ||||
|         $events->listen('recurring.store', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@store'); | ||||
|         $events->listen('recurring.update', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@update'); | ||||
|         $events->listen('recurring.check', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@createReminders'); | ||||
|         $events->listen('recurring.rescan', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@rescan'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -114,14 +107,5 @@ class EloquentRecurringTrigger | ||||
|      */ | ||||
|     public function update(\RecurringTransaction $recurring) | ||||
|     { | ||||
|         // remove old active reminders | ||||
|         $reminders = $recurring->reminders()->validOnOrAfter(new Carbon)->get(); | ||||
|         foreach ($reminders as $r) { | ||||
|             $r->delete(); | ||||
|         } | ||||
|         $this->createReminders(); | ||||
|         // create new reminder for the current period. | ||||
|  | ||||
|         // and now create new one(s)! | ||||
|     } | ||||
| }  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user