mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-02 02:51:50 +00:00
Compare commits
220 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a45b25614 | ||
|
|
da3dc599f9 | ||
|
|
f013b435ab | ||
|
|
c5dee29e4b | ||
|
|
633ee02f13 | ||
|
|
6b750c909a | ||
|
|
5f8b6640a9 | ||
|
|
dd42d8437c | ||
|
|
67a178591d | ||
|
|
f5e5659c1f | ||
|
|
8b0f0fb615 | ||
|
|
209116e766 | ||
|
|
79392ab656 | ||
|
|
3ca1207231 | ||
|
|
cec1b147f2 | ||
|
|
46cfcfa3e7 | ||
|
|
b833e8dfa2 | ||
|
|
77b843efd8 | ||
|
|
db72ad7c60 | ||
|
|
eadc630fcb | ||
|
|
170c1793cc | ||
|
|
9f7c6c2d0c | ||
|
|
72d054c55c | ||
|
|
524edfe7c2 | ||
|
|
c25c5623d2 | ||
|
|
4f38b77ef6 | ||
|
|
5862803434 | ||
|
|
5b3beded39 | ||
|
|
c61fb7a598 | ||
|
|
33d9148029 | ||
|
|
63969f5a33 | ||
|
|
edde18aeef | ||
|
|
657116d361 | ||
|
|
e16269daa8 | ||
|
|
c07591ff5c | ||
|
|
75a478ad54 | ||
|
|
8dae8b1a7f | ||
|
|
15fd8cf486 | ||
|
|
55333156ac | ||
|
|
8cdcba3231 | ||
|
|
8bab9e84e2 | ||
|
|
2faae83912 | ||
|
|
5a61a11a61 | ||
|
|
a6d71988f2 | ||
|
|
7069e242ae | ||
|
|
56ee830558 | ||
|
|
6dd12729e6 | ||
|
|
14a48303cb | ||
|
|
72cf6c9c0f | ||
|
|
144ee6b8ca | ||
|
|
8967d86da6 | ||
|
|
18c6edbb5d | ||
|
|
53de3c4717 | ||
|
|
ad577e4e81 | ||
|
|
44811a3e7c | ||
|
|
1ab3f05b3a | ||
|
|
5e76488ae7 | ||
|
|
32771fe7e1 | ||
|
|
9b40cc6881 | ||
|
|
2e35260bbb | ||
|
|
a067704277 | ||
|
|
de281818ac | ||
|
|
c49bfad38d | ||
|
|
c1ba591b26 | ||
|
|
719af38a61 | ||
|
|
ac61dfae6b | ||
|
|
813fb679a7 | ||
|
|
e7562781f7 | ||
|
|
56d36b7f53 | ||
|
|
53b3f7f821 | ||
|
|
08a53156bd | ||
|
|
8985cd6309 | ||
|
|
3833da7410 | ||
|
|
4210cd10db | ||
|
|
a7bd1c6892 | ||
|
|
52b0111afa | ||
|
|
7921d128e4 | ||
|
|
d7e838701a | ||
|
|
289bcb22aa | ||
|
|
3fe57b7983 | ||
|
|
32e92c2a16 | ||
|
|
1b3d208540 | ||
|
|
6a8bf0aa62 | ||
|
|
56715556ed | ||
|
|
838330b909 | ||
|
|
69553b138b | ||
|
|
36d7a02994 | ||
|
|
301528e2d2 | ||
|
|
0303b45707 | ||
|
|
ba722e8ed5 | ||
|
|
289e5a5442 | ||
|
|
fdad96e2bc | ||
|
|
af994e4dae | ||
|
|
006d68e279 | ||
|
|
29dc122ad3 | ||
|
|
cf4a8c6204 | ||
|
|
3c73fe92bf | ||
|
|
6637590797 | ||
|
|
b8bab11acd | ||
|
|
a2f600feac | ||
|
|
80dd62ef0a | ||
|
|
827b1c9cd8 | ||
|
|
2e4fcf803d | ||
|
|
d00d95fc6f | ||
|
|
3e3ab9bd25 | ||
|
|
6eecc7722d | ||
|
|
ada4aaf69a | ||
|
|
93244c1f78 | ||
|
|
be056cea6b | ||
|
|
659ca8be14 | ||
|
|
ea9af8366d | ||
|
|
80edd47d36 | ||
|
|
d7746b3649 | ||
|
|
c4c4fbc34c | ||
|
|
59f57c96e9 | ||
|
|
a2f852fecf | ||
|
|
ad114ed329 | ||
|
|
c4c3d0f07f | ||
|
|
6cf8102de5 | ||
|
|
e7e4aa2218 | ||
|
|
6d84f4b6c1 | ||
|
|
ce3e9ffd11 | ||
|
|
3ada260e0e | ||
|
|
8fdd0cb795 | ||
|
|
913e05a2e6 | ||
|
|
fa1f703ef6 | ||
|
|
4004c53e1b | ||
|
|
4838670649 | ||
|
|
a985e09282 | ||
|
|
9bd1503cb4 | ||
|
|
a2ccbf7844 | ||
|
|
61bbe8a905 | ||
|
|
59bc5d22d1 | ||
|
|
1423d5b314 | ||
|
|
152d0eb1d0 | ||
|
|
6426d1df06 | ||
|
|
9284eb3fe9 | ||
|
|
afdae8bc1e | ||
|
|
2a7085e593 | ||
|
|
2408fb3ed4 | ||
|
|
8316afb176 | ||
|
|
e59fd098a3 | ||
|
|
e044199693 | ||
|
|
8f8e29fc22 | ||
|
|
8de5384158 | ||
|
|
216c659335 | ||
|
|
041ca8a5d3 | ||
|
|
fe4f1b306d | ||
|
|
a0972d99fb | ||
|
|
e332bfef7c | ||
|
|
cba5e226d8 | ||
|
|
5aff0c4943 | ||
|
|
cb49c00f4d | ||
|
|
e26d797d57 | ||
|
|
938581527e | ||
|
|
c38ae09735 | ||
|
|
28c3cfe084 | ||
|
|
4a2823bcba | ||
|
|
18eba02026 | ||
|
|
d4690ce580 | ||
|
|
a785c450b1 | ||
|
|
7480dc4a19 | ||
|
|
ad01891a67 | ||
|
|
67fe35d564 | ||
|
|
7f19b6957a | ||
|
|
0a54caf202 | ||
|
|
4b4c1c7f8f | ||
|
|
d071f3947e | ||
|
|
b3d99cd210 | ||
|
|
90e696f82c | ||
|
|
958fcd1cfa | ||
|
|
8f57c7dcb3 | ||
|
|
77262f52a4 | ||
|
|
16bfbc8a12 | ||
|
|
1fd375b875 | ||
|
|
46131ad39d | ||
|
|
0b5c5b2ae9 | ||
|
|
55be174037 | ||
|
|
a17b7025f1 | ||
|
|
170cf7fd77 | ||
|
|
23cdb4d326 | ||
|
|
cbbe529572 | ||
|
|
0b382426e9 | ||
|
|
1cbbf9baa4 | ||
|
|
8d41ff7b79 | ||
|
|
e3b6057bf8 | ||
|
|
66a4042cad | ||
|
|
56c08d8302 | ||
|
|
d4e759754d | ||
|
|
a96e171cbf | ||
|
|
bd4a8c8397 | ||
|
|
04f71b3b43 | ||
|
|
d124de51db | ||
|
|
d87d12a0f5 | ||
|
|
f2b08346d0 | ||
|
|
d3682a6727 | ||
|
|
371bbd9508 | ||
|
|
a8a28f442f | ||
|
|
65ddd8a736 | ||
|
|
8bb27de233 | ||
|
|
37e2f097ba | ||
|
|
1966d87ce6 | ||
|
|
7b8c86e1e3 | ||
|
|
de634da513 | ||
|
|
96836e2d6c | ||
|
|
8a9d576f61 | ||
|
|
791d12fbb4 | ||
|
|
d1329be2fa | ||
|
|
3ed6561702 | ||
|
|
7a0587f433 | ||
|
|
0fe682bfe6 | ||
|
|
0f685e8789 | ||
|
|
420771c233 | ||
|
|
5e3e9271ca | ||
|
|
1e603c0833 | ||
|
|
03e1673e92 | ||
|
|
9f992f003d | ||
|
|
f50244a41f | ||
|
|
baf9ebab15 | ||
|
|
fb2fa54480 |
13
.env.example
13
.env.example
@@ -2,6 +2,7 @@ APP_ENV=production
|
|||||||
APP_DEBUG=false
|
APP_DEBUG=false
|
||||||
APP_KEY=SomeRandomStringOf32CharsExactly
|
APP_KEY=SomeRandomStringOf32CharsExactly
|
||||||
|
|
||||||
|
|
||||||
DB_CONNECTION=mysql
|
DB_CONNECTION=mysql
|
||||||
DB_HOST=localhost
|
DB_HOST=localhost
|
||||||
DB_DATABASE=homestead
|
DB_DATABASE=homestead
|
||||||
@@ -11,14 +12,22 @@ DB_PASSWORD=secret
|
|||||||
CACHE_DRIVER=file
|
CACHE_DRIVER=file
|
||||||
SESSION_DRIVER=file
|
SESSION_DRIVER=file
|
||||||
|
|
||||||
|
DEFAULT_CURRENCY=EUR
|
||||||
|
DEFAULT_LANGUAGE=en_US
|
||||||
|
|
||||||
EMAIL_SMTP=
|
EMAIL_SMTP=
|
||||||
EMAIL_DRIVER=smtp
|
EMAIL_DRIVER=smtp
|
||||||
EMAIL_USERNAME=
|
EMAIL_USERNAME=
|
||||||
EMAIL_PASSWORD=
|
EMAIL_PASSWORD=
|
||||||
ANALYTICS_ID=
|
|
||||||
EMAIL_PRETEND=false
|
EMAIL_PRETEND=false
|
||||||
|
|
||||||
|
SHOW_INCOMPLETE_TRANSLATIONS=false
|
||||||
|
|
||||||
|
ANALYTICS_ID=
|
||||||
RUNCLEANUP=true
|
RUNCLEANUP=true
|
||||||
SITE_OWNER=mail@example.com
|
SITE_OWNER=mail@example.com
|
||||||
|
|
||||||
SENDGRID_USERNAME=
|
SENDGRID_USERNAME=
|
||||||
SENDGRID_PASSWORD=
|
SENDGRID_PASSWORD=
|
||||||
|
|
||||||
|
BLOCKED_DOMAINS=
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,7 +5,7 @@ Thumbs.db
|
|||||||
.idea/
|
.idea/
|
||||||
tests/_output/*
|
tests/_output/*
|
||||||
_ide_helper.php
|
_ide_helper.php
|
||||||
/build/logs/clover.xml
|
/build/logs
|
||||||
index.html*
|
index.html*
|
||||||
app/storage/firefly-export*
|
app/storage/firefly-export*
|
||||||
.vagrant
|
.vagrant
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ install:
|
|||||||
- composer update
|
- composer update
|
||||||
- php artisan env
|
- php artisan env
|
||||||
- mv -v .env.testing .env
|
- mv -v .env.testing .env
|
||||||
|
- touch storage/database/testing.db
|
||||||
|
- php artisan migrate --env=testing
|
||||||
|
- php artisan migrate --seed --env=testing
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- phpunit
|
- phpunit
|
||||||
|
|||||||
29
README.md
29
README.md
@@ -19,7 +19,6 @@ their current cashflow. There are tons of ways to save and earn money.
|
|||||||
|
|
||||||
Firefly works on the principle that if you know where you're money is going, you can stop it from going there.
|
Firefly works on the principle that if you know where you're money is going, you can stop it from going there.
|
||||||
|
|
||||||
|
|
||||||
To get to know Firefly, and to see if it fits you, check out these resources:
|
To get to know Firefly, and to see if it fits you, check out these resources:
|
||||||
|
|
||||||
- The screenshots below on this very page.
|
- The screenshots below on this very page.
|
||||||
@@ -61,19 +60,19 @@ Everything is organised:
|
|||||||
|
|
||||||
_Please note that everything in these screenshots is fictional and may not be realistic._
|
_Please note that everything in these screenshots is fictional and may not be realistic._
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Running and installing
|
## Running and installing
|
||||||
|
|
||||||
@@ -82,7 +81,19 @@ If you're still interested please read [the installation guide](https://github.c
|
|||||||
and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**.
|
and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**.
|
||||||
|
|
||||||
If you want to try out Firefly III, you can do so on [this dedicated website](https://geld.nder.be/).
|
If you want to try out Firefly III, you can do so on [this dedicated website](https://geld.nder.be/).
|
||||||
This site always runs the latest version of Firefly III. If you want to use it, please read the [privacy considerations](https://github.com/JC5/firefly-iii/wiki/Privacy-on-demo-site) for this demo-site. Accounts on the demo sites will stop working after one week.
|
This site always runs the latest version of Firefly III. If you want to use it, please read the [privacy considerations](https://github.com/JC5/firefly-iii/wiki/Privacy-on-demo-site) for this demo-site. Accounts on the demo sites will stop working after one month. It's a trial.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
You should always run Firefly III on a site with TLS enabled (https://). Please note that although some parts of the
|
||||||
|
database are encrypted (transaction descriptions, names, etc.) some parts are _not_ (amounts, dates, etc). If you need
|
||||||
|
more security, you must enable transparent database encryption or a comparable technology. Please remember that this
|
||||||
|
is open source software under active development, and it is in no way guaranteed to be safe or secure.
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
|
||||||
|
Firefly III is currently available in Dutch and English. Support for other languages is being worked on. I can use
|
||||||
|
your help. Checkout [Crowdin](https://crowdin.com/project/firefly-iii) for more information.
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
|
|||||||
@@ -14,15 +14,6 @@ use Illuminate\Support\Collection;
|
|||||||
interface AccountChartGenerator
|
interface AccountChartGenerator
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $accounts
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function all(Collection $accounts, Carbon $start, Carbon $end);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
|
|||||||
@@ -3,10 +3,8 @@
|
|||||||
namespace FireflyIII\Generator\Chart\Account;
|
namespace FireflyIII\Generator\Chart\Account;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Config;
|
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Preferences;
|
|
||||||
use Steam;
|
use Steam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,21 +15,6 @@ use Steam;
|
|||||||
class ChartJsAccountChartGenerator implements AccountChartGenerator
|
class ChartJsAccountChartGenerator implements AccountChartGenerator
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
*
|
|
||||||
* @param Collection $accounts
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function all(Collection $accounts, Carbon $start, Carbon $end)
|
|
||||||
{
|
|
||||||
return $this->frontpage($accounts, $start, $end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
@@ -42,10 +25,10 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
|
|||||||
public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end)
|
public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
'count' => 1,
|
'count' => 1,
|
||||||
'labels' => [], 'datasets' => [[
|
'labels' => [], 'datasets' => [[
|
||||||
'label' => trans('firefly.spent'),
|
'label' => trans('firefly.spent'),
|
||||||
'data' => []]]];
|
'data' => []]]];
|
||||||
|
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
$start->subDay();
|
$start->subDay();
|
||||||
@@ -105,21 +88,21 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
|
|||||||
public function frontpage(Collection $accounts, Carbon $start, Carbon $end)
|
public function frontpage(Collection $accounts, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
// language:
|
// language:
|
||||||
$language = Preferences::get('language', 'en')->data;
|
$format = trans('config.month_and_day');
|
||||||
$format = Config::get('firefly.monthAndDay.' . $language);
|
$data = [
|
||||||
$data = [
|
|
||||||
'count' => 0,
|
'count' => 0,
|
||||||
'labels' => [],
|
'labels' => [],
|
||||||
'datasets' => [],
|
'datasets' => [],
|
||||||
];
|
];
|
||||||
$current = clone $start;
|
$current = clone $start;
|
||||||
while ($current <= $end) {
|
while ($current <= $end) {
|
||||||
$data['labels'][] = $current->formatLocalized($format);
|
$data['labels'][] = $current->formatLocalized($format);
|
||||||
$current->addDay();
|
$current->addDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
$set = [
|
$set = [
|
||||||
'label' => $account->name,
|
'label' => $account->name,
|
||||||
'fillColor' => 'rgba(220,220,220,0.2)',
|
'fillColor' => 'rgba(220,220,220,0.2)',
|
||||||
'strokeColor' => 'rgba(220,220,220,1)',
|
'strokeColor' => 'rgba(220,220,220,1)',
|
||||||
@@ -129,9 +112,15 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
|
|||||||
'pointHighlightStroke' => 'rgba(220,220,220,1)',
|
'pointHighlightStroke' => 'rgba(220,220,220,1)',
|
||||||
'data' => [],
|
'data' => [],
|
||||||
];
|
];
|
||||||
$current = clone $start;
|
$current = clone $start;
|
||||||
|
$range = Steam::balanceInRange($account, $start, $end);
|
||||||
|
$previous = array_values($range)[0];
|
||||||
while ($current <= $end) {
|
while ($current <= $end) {
|
||||||
$set['data'][] = Steam::balance($account, $current);
|
$format = $current->format('Y-m-d');
|
||||||
|
$balance = isset($range[$format]) ? $range[$format] : $previous;
|
||||||
|
|
||||||
|
$set['data'][] = $balance;
|
||||||
|
$previous = $balance;
|
||||||
$current->addDay();
|
$current->addDay();
|
||||||
}
|
}
|
||||||
$data['datasets'][] = $set;
|
$data['datasets'][] = $set;
|
||||||
@@ -151,8 +140,7 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
|
|||||||
public function single(Account $account, Carbon $start, Carbon $end)
|
public function single(Account $account, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
// language:
|
// language:
|
||||||
$language = Preferences::get('language', 'en')->data;
|
$format = trans('config.month_and_day');
|
||||||
$format = Config::get('firefly.monthAndDay.' . $language);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'count' => 1,
|
'count' => 1,
|
||||||
|
|||||||
@@ -71,8 +71,7 @@ class ChartJsBillChartGenerator implements BillChartGenerator
|
|||||||
public function single(Bill $bill, Collection $entries)
|
public function single(Bill $bill, Collection $entries)
|
||||||
{
|
{
|
||||||
// language:
|
// language:
|
||||||
$language = Preferences::get('language', 'en')->data;
|
$format = trans('config.month');
|
||||||
$format = Config::get('firefly.month.' . $language);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'count' => 3,
|
'count' => 3,
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ interface BudgetChartGenerator
|
|||||||
*/
|
*/
|
||||||
public function frontpage(Collection $entries);
|
public function frontpage(Collection $entries);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYear(Collection $entries);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $budgets
|
* @param Collection $budgets
|
||||||
* @param Collection $entries
|
* @param Collection $entries
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
|
|||||||
public function budget(Collection $entries, $dateFormat = 'month')
|
public function budget(Collection $entries, $dateFormat = 'month')
|
||||||
{
|
{
|
||||||
// language:
|
// language:
|
||||||
$language = Preferences::get('language', 'en')->data;
|
$language = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US'))->data;
|
||||||
$format = Config::get('firefly.' . $dateFormat . '.' . $language);
|
$format = Config::get('firefly.' . $dateFormat . '.' . $language);
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
@@ -33,7 +33,7 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
|
|||||||
[
|
[
|
||||||
'label' => 'Amount',
|
'label' => 'Amount',
|
||||||
'data' => [],
|
'data' => [],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -115,8 +115,7 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
|
|||||||
public function year(Collection $budgets, Collection $entries)
|
public function year(Collection $budgets, Collection $entries)
|
||||||
{
|
{
|
||||||
// language:
|
// language:
|
||||||
$language = Preferences::get('language', 'en')->data;
|
$format = trans('config.month');
|
||||||
$format = Config::get('firefly.month.' . $language);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'labels' => [],
|
'labels' => [],
|
||||||
@@ -141,4 +140,37 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
|
|||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYear(Collection $entries)
|
||||||
|
{
|
||||||
|
// dataset:
|
||||||
|
$data = [
|
||||||
|
'count' => 0,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [],
|
||||||
|
];
|
||||||
|
// get labels from one of the budgets (assuming there's at least one):
|
||||||
|
$first = $entries->first();
|
||||||
|
foreach ($first['budgeted'] as $year => $noInterest) {
|
||||||
|
$data['labels'][] = strval($year);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then, loop all entries and create datasets:
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$name = $entry['name'];
|
||||||
|
$spent = $entry['spent'];
|
||||||
|
$budgeted = $entry['budgeted'];
|
||||||
|
$data['datasets'][] = ['label' => 'Spent on ' . $name, 'data' => array_values($spent)];
|
||||||
|
$data['datasets'][] = ['label' => 'Budgeted for ' . $name, 'data' => array_values($budgeted)];
|
||||||
|
}
|
||||||
|
$data['count'] = count($data['datasets']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ interface CategoryChartGenerator
|
|||||||
*/
|
*/
|
||||||
public function all(Collection $entries);
|
public function all(Collection $entries);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function earnedInPeriod(Collection $categories, Collection $entries);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $entries
|
* @param Collection $entries
|
||||||
*
|
*
|
||||||
@@ -31,8 +39,14 @@ interface CategoryChartGenerator
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function period(Collection $entries);
|
public function multiYear(Collection $entries);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function period(Collection $entries);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $categories
|
* @param Collection $categories
|
||||||
@@ -41,12 +55,4 @@ interface CategoryChartGenerator
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function spentInYear(Collection $categories, Collection $entries);
|
public function spentInYear(Collection $categories, Collection $entries);
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $categories
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function earnedInYear(Collection $categories, Collection $entries);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
namespace FireflyIII\Generator\Chart\Category;
|
namespace FireflyIII\Generator\Chart\Category;
|
||||||
|
|
||||||
use Config;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Preferences;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,8 +99,7 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
|
|||||||
{
|
{
|
||||||
|
|
||||||
// language:
|
// language:
|
||||||
$language = Preferences::get('language', 'en')->data;
|
$format = trans('config.month');
|
||||||
$format = Config::get('firefly.month.' . $language);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'count' => 0,
|
'count' => 0,
|
||||||
@@ -131,12 +128,11 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function earnedInYear(Collection $categories, Collection $entries)
|
public function earnedInPeriod(Collection $categories, Collection $entries)
|
||||||
{
|
{
|
||||||
|
|
||||||
// language:
|
// language:
|
||||||
$language = Preferences::get('language', 'en')->data;
|
$format = trans('config.month');
|
||||||
$format = Config::get('firefly.month.' . $language);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'count' => 0,
|
'count' => 0,
|
||||||
@@ -158,4 +154,74 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
|
|||||||
return $data;
|
return $data;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function spentInPeriod(Collection $categories, Collection $entries)
|
||||||
|
{
|
||||||
|
|
||||||
|
// language:
|
||||||
|
$format = trans('config.month');
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'count' => 0,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
$data['labels'][] = $category->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$date = $entry[0]->formatLocalized($format);
|
||||||
|
array_shift($entry);
|
||||||
|
$data['count']++;
|
||||||
|
$data['datasets'][] = ['label' => $date, 'data' => $entry];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYear(Collection $entries)
|
||||||
|
{
|
||||||
|
// dataset:
|
||||||
|
$data = [
|
||||||
|
'count' => 0,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [],
|
||||||
|
];
|
||||||
|
// get labels from one of the categories (assuming there's at least one):
|
||||||
|
$first = $entries->first();
|
||||||
|
foreach ($first['spent'] as $year => $noInterest) {
|
||||||
|
$data['labels'][] = strval($year);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then, loop all entries and create datasets:
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$name = $entry['name'];
|
||||||
|
$spent = $entry['spent'];
|
||||||
|
$earned = $entry['earned'];
|
||||||
|
if (array_sum(array_values($spent)) != 0) {
|
||||||
|
$data['datasets'][] = ['label' => 'Spent in category ' . $name, 'data' => array_values($spent)];
|
||||||
|
}
|
||||||
|
if (array_sum(array_values($earned)) != 0) {
|
||||||
|
$data['datasets'][] = ['label' => 'Earned in category ' . $name, 'data' => array_values($earned)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data['count'] = count($data['datasets']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ class ChartJsPiggyBankChartGenerator implements PiggyBankChartGenerator
|
|||||||
{
|
{
|
||||||
|
|
||||||
// language:
|
// language:
|
||||||
$language = Preferences::get('language', 'en')->data;
|
$format = trans('config.month_and_day');
|
||||||
$format = Config::get('firefly.monthAndDay.' . $language);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'count' => 1,
|
'count' => 1,
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ class ChartJsReportChartGenerator implements ReportChartGenerator
|
|||||||
public function yearInOut(Collection $entries)
|
public function yearInOut(Collection $entries)
|
||||||
{
|
{
|
||||||
// language:
|
// language:
|
||||||
$language = Preferences::get('language', 'en')->data;
|
$format = trans('config.month');
|
||||||
$format = Config::get('firefly.month.' . $language);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'count' => 2,
|
'count' => 2,
|
||||||
@@ -49,6 +48,39 @@ class ChartJsReportChartGenerator implements ReportChartGenerator
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as above but other translations.
|
||||||
|
*
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYearInOut(Collection $entries)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'count' => 2,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.income'),
|
||||||
|
'data' => []
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.expenses'),
|
||||||
|
'data' => []
|
||||||
|
]
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$data['labels'][] = $entry[0]->formatLocalized('%Y');
|
||||||
|
$data['datasets'][0]['data'][] = round($entry[1], 2);
|
||||||
|
$data['datasets'][1]['data'][] = round($entry[2], 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $income
|
* @param string $income
|
||||||
* @param string $expense
|
* @param string $expense
|
||||||
@@ -74,9 +106,40 @@ class ChartJsReportChartGenerator implements ReportChartGenerator
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
$data['datasets'][0]['data'][] = round($income, 2);
|
$data['datasets'][0]['data'][] = round($income, 2);
|
||||||
$data['datasets'][1]['data'][] = round( $expense, 2);
|
$data['datasets'][1]['data'][] = round($expense, 2);
|
||||||
$data['datasets'][0]['data'][] = round(($income / $count), 2);
|
$data['datasets'][0]['data'][] = round(($income / $count), 2);
|
||||||
$data['datasets'][1]['data'][] = round(( $expense / $count), 2);
|
$data['datasets'][1]['data'][] = round(($expense / $count), 2);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $income
|
||||||
|
* @param string $expense
|
||||||
|
* @param int $count
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYearInOutSummarized($income, $expense, $count)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'count' => 2,
|
||||||
|
'labels' => [trans('firefly.sum_of_years'), trans('firefly.average_of_years')],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.income'),
|
||||||
|
'data' => []
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.expenses'),
|
||||||
|
'data' => []
|
||||||
|
]
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$data['datasets'][0]['data'][] = round($income, 2);
|
||||||
|
$data['datasets'][1]['data'][] = round($expense, 2);
|
||||||
|
$data['datasets'][0]['data'][] = round(($income / $count), 2);
|
||||||
|
$data['datasets'][1]['data'][] = round(($expense / $count), 2);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,22 @@ use Illuminate\Support\Collection;
|
|||||||
interface ReportChartGenerator
|
interface ReportChartGenerator
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYearInOut(Collection $entries);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $income
|
||||||
|
* @param string $expense
|
||||||
|
* @param int $count
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYearInOutSummarized($income, $expense, $count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $entries
|
* @param Collection $entries
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -150,24 +150,4 @@ class BalanceLine
|
|||||||
{
|
{
|
||||||
$this->balanceEntries = $balanceEntries;
|
$this->balanceEntries = $balanceEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If the BalanceEntries for a BalanceLine have a "left" value, the amount
|
|
||||||
* of money left in the entire BalanceLine is returned here:
|
|
||||||
*
|
|
||||||
* @return float
|
|
||||||
*/
|
|
||||||
public function sumOfLeft()
|
|
||||||
{
|
|
||||||
$sum = '0';
|
|
||||||
bcscale(2);
|
|
||||||
/** @var BalanceEntry $balanceEntry */
|
|
||||||
foreach ($this->getBalanceEntries() as $balanceEntry) {
|
|
||||||
$sum = bcadd($sum, $balanceEntry->getLeft());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class Category
|
|||||||
// spent is minus zero for an expense report:
|
// spent is minus zero for an expense report:
|
||||||
if ($category->spent < 0) {
|
if ($category->spent < 0) {
|
||||||
$this->categories->push($category);
|
$this->categories->push($category);
|
||||||
|
$this->addTotal($category->spent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ class Category
|
|||||||
*/
|
*/
|
||||||
public function getCategories()
|
public function getCategories()
|
||||||
{
|
{
|
||||||
$set = $this->categories->sortByDesc(
|
$set = $this->categories->sortBy(
|
||||||
function (CategoryModel $category) {
|
function (CategoryModel $category) {
|
||||||
return $category->spent;
|
return $category->spent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,18 +33,24 @@ class Expense
|
|||||||
*/
|
*/
|
||||||
public function addOrCreateExpense(TransactionJournal $entry)
|
public function addOrCreateExpense(TransactionJournal $entry)
|
||||||
{
|
{
|
||||||
|
bcscale(2);
|
||||||
|
|
||||||
$accountId = $entry->account_id;
|
$accountId = $entry->account_id;
|
||||||
|
$amount = strval(round($entry->amount, 2));
|
||||||
|
if (bccomp('0', $amount) === -1) {
|
||||||
|
$amount = bcmul($amount, '-1');
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->expenses->has($accountId)) {
|
if (!$this->expenses->has($accountId)) {
|
||||||
$newObject = new stdClass;
|
$newObject = new stdClass;
|
||||||
$newObject->amount = strval(round($entry->amount_positive, 2));
|
$newObject->amount = $amount;
|
||||||
$newObject->name = $entry->name;
|
$newObject->name = $entry->name;
|
||||||
$newObject->count = 1;
|
$newObject->count = 1;
|
||||||
$newObject->id = $accountId;
|
$newObject->id = $accountId;
|
||||||
$this->expenses->put($accountId, $newObject);
|
$this->expenses->put($accountId, $newObject);
|
||||||
} else {
|
} else {
|
||||||
bcscale(2);
|
|
||||||
$existing = $this->expenses->get($accountId);
|
$existing = $this->expenses->get($accountId);
|
||||||
$existing->amount = bcadd($existing->amount, $entry->amount_positive);
|
$existing->amount = bcadd($existing->amount, $amount);
|
||||||
$existing->count++;
|
$existing->count++;
|
||||||
$this->expenses->put($accountId, $existing);
|
$this->expenses->put($accountId, $existing);
|
||||||
}
|
}
|
||||||
@@ -55,8 +61,18 @@ class Expense
|
|||||||
*/
|
*/
|
||||||
public function addToTotal($add)
|
public function addToTotal($add)
|
||||||
{
|
{
|
||||||
$add = strval(round($add, 2));
|
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
|
|
||||||
|
|
||||||
|
$add = strval(round($add, 2));
|
||||||
|
if (bccomp('0', $add) === -1) {
|
||||||
|
$add = bcmul($add, '-1');
|
||||||
|
}
|
||||||
|
|
||||||
|
// if amount is positive, the original transaction
|
||||||
|
// was a transfer. But since this is an expense report,
|
||||||
|
// that amount must be negative.
|
||||||
|
|
||||||
$this->total = bcadd($this->total, $add);
|
$this->total = bcadd($this->total, $add);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +81,7 @@ class Expense
|
|||||||
*/
|
*/
|
||||||
public function getExpenses()
|
public function getExpenses()
|
||||||
{
|
{
|
||||||
$set = $this->expenses->sortByDesc(
|
$set = $this->expenses->sortBy(
|
||||||
function (stdClass $object) {
|
function (stdClass $object) {
|
||||||
return $object->amount;
|
return $object->amount;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ class Importer
|
|||||||
|
|
||||||
// some debug info:
|
// some debug info:
|
||||||
$journalId = $journal->id;
|
$journalId = $journal->id;
|
||||||
$type = $journal->transactionType->type;
|
$type = $journal->getTransactionType();
|
||||||
/** @var Account $asset */
|
/** @var Account $asset */
|
||||||
$asset = $this->importData['asset-account-object'];
|
$asset = $this->importData['asset-account-object'];
|
||||||
/** @var Account $opposing */
|
/** @var Account $opposing */
|
||||||
@@ -314,13 +314,13 @@ class Importer
|
|||||||
*/
|
*/
|
||||||
protected function getTransactionType()
|
protected function getTransactionType()
|
||||||
{
|
{
|
||||||
$transactionType = TransactionType::where('type', 'Deposit')->first();
|
$transactionType = TransactionType::where('type', TransactionType::DEPOSIT)->first();
|
||||||
if ($this->importData['amount'] < 0) {
|
if ($this->importData['amount'] < 0) {
|
||||||
$transactionType = TransactionType::where('type', 'Withdrawal')->first();
|
$transactionType = TransactionType::where('type', TransactionType::WITHDRAWAL)->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array($this->importData['opposing-account-object']->accountType->type, ['Asset account', 'Default account'])) {
|
if (in_array($this->importData['opposing-account-object']->accountType->type, ['Asset account', 'Default account'])) {
|
||||||
$transactionType = TransactionType::where('type', 'Transfer')->first();
|
$transactionType = TransactionType::where('type', TransactionType::TRANSFER)->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $transactionType;
|
return $transactionType;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class Currency implements PostProcessorInterface
|
|||||||
|
|
||||||
// fix currency
|
// fix currency
|
||||||
if (is_null($this->data['currency'])) {
|
if (is_null($this->data['currency'])) {
|
||||||
$currencyPreference = Preferences::get('currencyPreference', 'EUR');
|
$currencyPreference = Preferences::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR'));
|
||||||
$this->data['currency'] = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
$this->data['currency'] = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ use FireflyIII\Models\Account;
|
|||||||
use FireflyIII\Models\Bill;
|
use FireflyIII\Models\Bill;
|
||||||
use FireflyIII\Models\Budget as BudgetModel;
|
use FireflyIII\Models\Budget as BudgetModel;
|
||||||
use FireflyIII\Models\LimitRepetition;
|
use FireflyIII\Models\LimitRepetition;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Steam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ReportHelper
|
* Class ReportHelper
|
||||||
@@ -43,48 +45,113 @@ class ReportHelper implements ReportHelperInterface
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return CategoryCollection
|
||||||
|
*/
|
||||||
|
public function getCategoryReport(Carbon $start, Carbon $end, Collection $accounts)
|
||||||
|
{
|
||||||
|
$object = new CategoryCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET CATEGORIES:
|
||||||
|
*/
|
||||||
|
/** @var \FireflyIII\Repositories\Category\CategoryRepositoryInterface $repository */
|
||||||
|
$repository = app('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||||
|
$set = $repository->getCategories();
|
||||||
|
foreach ($set as $category) {
|
||||||
|
$spent = $repository->balanceInPeriod($category, $start, $end, $accounts);
|
||||||
|
$category->spent = $spent;
|
||||||
|
$object->addCategory($category);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function listOfMonths(Carbon $date)
|
||||||
|
{
|
||||||
|
|
||||||
|
$start = clone $date;
|
||||||
|
$end = Carbon::now();
|
||||||
|
$months = [];
|
||||||
|
while ($start <= $end) {
|
||||||
|
$year = $start->year;
|
||||||
|
|
||||||
|
if (!isset($months[$year])) {
|
||||||
|
$months[$year] = [
|
||||||
|
'start' => Carbon::createFromDate($year, 1, 1)->format('Y-m-d'),
|
||||||
|
'end' => Carbon::createFromDate($year, 12, 31)->format('Y-m-d'),
|
||||||
|
'months' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentEnd = clone $start;
|
||||||
|
$currentEnd->endOfMonth();
|
||||||
|
$months[$year]['months'][] = [
|
||||||
|
'formatted' => $start->formatLocalized('%B %Y'),
|
||||||
|
'start' => $start->format('Y-m-d'),
|
||||||
|
'end' => $currentEnd->format('Y-m-d'),
|
||||||
|
'month' => $start->month,
|
||||||
|
'year' => $year,
|
||||||
|
];
|
||||||
|
$start->addMonth();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $months;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method generates a full report for the given period on all
|
* This method generates a full report for the given period on all
|
||||||
* the users asset and cash accounts.
|
* given accounts
|
||||||
*
|
*
|
||||||
* @param Carbon $date
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param $shared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return AccountCollection
|
* @return AccountCollection
|
||||||
*/
|
*/
|
||||||
public function getAccountReport(Carbon $date, Carbon $end, $shared)
|
public function getAccountReport(Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
|
$startAmount = '0';
|
||||||
|
$endAmount = '0';
|
||||||
$accounts = $this->query->getAllAccounts($date, $end, $shared);
|
$diff = '0';
|
||||||
$start = '0';
|
|
||||||
$end = '0';
|
|
||||||
$diff = '0';
|
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
|
|
||||||
// remove cash account, if any:
|
$accounts->each(
|
||||||
$accounts = $accounts->filter(
|
function (Account $account) use ($start, $end) {
|
||||||
function (Account $account) {
|
/**
|
||||||
if ($account->accountType->type != 'Cash account') {
|
* The balance for today always incorporates transactions
|
||||||
return $account;
|
* made on today. So to get todays "start" balance, we sub one
|
||||||
}
|
* day.
|
||||||
|
*/
|
||||||
|
$yesterday = clone $start;
|
||||||
|
$yesterday->subDay();
|
||||||
|
|
||||||
return null;
|
/** @noinspection PhpParamsInspection */
|
||||||
|
$account->startBalance = Steam::balance($account, $yesterday);
|
||||||
|
$account->endBalance = Steam::balance($account, $end);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// summarize:
|
// summarize:
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
$start = bcadd($start, $account->startBalance);
|
$startAmount = bcadd($startAmount, $account->startBalance);
|
||||||
$end = bcadd($end, $account->endBalance);
|
$endAmount = bcadd($endAmount, $account->endBalance);
|
||||||
$diff = bcadd($diff, bcsub($account->endBalance, $account->startBalance));
|
$diff = bcadd($diff, bcsub($account->endBalance, $account->startBalance));
|
||||||
}
|
}
|
||||||
|
|
||||||
$object = new AccountCollection;
|
$object = new AccountCollection;
|
||||||
$object->setStart($start);
|
$object->setStart($startAmount);
|
||||||
$object->setEnd($end);
|
$object->setEnd($endAmount);
|
||||||
$object->setDifference($diff);
|
$object->setDifference($diff);
|
||||||
$object->setAccounts($accounts);
|
$object->setAccounts($accounts);
|
||||||
|
|
||||||
@@ -92,37 +159,136 @@ class ReportHelper implements ReportHelperInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Get a full report on the users incomes during the period for the given accounts.
|
||||||
*
|
*
|
||||||
* The balance report contains a Balance object which in turn contains:
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* A BalanceHeader object which contains all relevant user asset accounts for the report.
|
* @return Income
|
||||||
|
*/
|
||||||
|
public function getIncomeReport($start, $end, Collection $accounts)
|
||||||
|
{
|
||||||
|
$object = new Income;
|
||||||
|
$set = $this->query->incomeInPeriod($start, $end, $accounts);
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$object->addToTotal($entry->amount_positive);
|
||||||
|
$object->addOrCreateIncome($entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a full report on the users expenses during the period for a list of accounts.
|
||||||
*
|
*
|
||||||
* A number of BalanceLine objects, which hold:
|
* @param Carbon $start
|
||||||
* - A budget
|
* @param Carbon $end
|
||||||
* - A number of BalanceEntry objects.
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* The BalanceEntry object holds:
|
* @return Expense
|
||||||
* - The same budget (again)
|
*/
|
||||||
* - A user asset account as mentioned in the BalanceHeader
|
public function getExpenseReport($start, $end, Collection $accounts)
|
||||||
* - The amount of money spent on the budget by the user asset account
|
{
|
||||||
|
$object = new Expense;
|
||||||
|
$set = $this->query->expenseInPeriod($start, $end, $accounts);
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$object->addToTotal($entry->amount); // can be positive, if it's a transfer
|
||||||
|
$object->addOrCreateExpense($entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @param Carbon $start
|
* @return BudgetCollection
|
||||||
* @param Carbon $end
|
*/
|
||||||
* @param boolean $shared
|
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts)
|
||||||
|
{
|
||||||
|
$object = new BudgetCollection;
|
||||||
|
/** @var \FireflyIII\Repositories\Budget\BudgetRepositoryInterface $repository */
|
||||||
|
$repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||||
|
$set = $repository->getBudgets();
|
||||||
|
|
||||||
|
bcscale(2);
|
||||||
|
|
||||||
|
foreach ($set as $budget) {
|
||||||
|
|
||||||
|
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
|
||||||
|
|
||||||
|
// no repetition(s) for this budget:
|
||||||
|
if ($repetitions->count() == 0) {
|
||||||
|
$spent = $repository->balanceInPeriod($budget, $start, $end, $accounts);
|
||||||
|
$budgetLine = new BudgetLine;
|
||||||
|
$budgetLine->setBudget($budget);
|
||||||
|
$budgetLine->setOverspent($spent);
|
||||||
|
$object->addOverspent($spent);
|
||||||
|
$object->addBudgetLine($budgetLine);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// one or more repetitions for budget:
|
||||||
|
/** @var LimitRepetition $repetition */
|
||||||
|
foreach ($repetitions as $repetition) {
|
||||||
|
$budgetLine = new BudgetLine;
|
||||||
|
$budgetLine->setBudget($budget);
|
||||||
|
$budgetLine->setRepetition($repetition);
|
||||||
|
$expenses = $repository->balanceInPeriod($budget, $start, $end, $accounts);
|
||||||
|
|
||||||
|
// 200 en -100 is 100, vergeleken met 0 === 1
|
||||||
|
// 200 en -200 is 0, vergeleken met 0 === 0
|
||||||
|
// 200 en -300 is -100, vergeleken met 0 === -1
|
||||||
|
|
||||||
|
$left = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? bcadd($repetition->amount, $expenses) : 0;
|
||||||
|
$spent = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? $expenses : '0';
|
||||||
|
$overspent = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? '0' : bcadd($expenses, $repetition->amount);
|
||||||
|
|
||||||
|
$budgetLine->setLeft($left);
|
||||||
|
$budgetLine->setSpent($spent);
|
||||||
|
$budgetLine->setOverspent($overspent);
|
||||||
|
$budgetLine->setBudgeted($repetition->amount);
|
||||||
|
|
||||||
|
$object->addBudgeted($repetition->amount);
|
||||||
|
$object->addSpent($spent);
|
||||||
|
$object->addLeft($left);
|
||||||
|
$object->addOverspent($overspent);
|
||||||
|
$object->addBudgetLine($budgetLine);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// stuff outside of budgets:
|
||||||
|
$noBudget = $repository->getWithoutBudgetSum($start, $end);
|
||||||
|
$budgetLine = new BudgetLine;
|
||||||
|
$budgetLine->setOverspent($noBudget);
|
||||||
|
$budgetLine->setSpent($noBudget);
|
||||||
|
$object->addOverspent($noBudget);
|
||||||
|
$object->addBudgetLine($budgetLine);
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return Balance
|
* @return Balance
|
||||||
*/
|
*/
|
||||||
public function getBalanceReport(Carbon $start, Carbon $end, $shared)
|
public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
$repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
$repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||||
$tagRepository = app('FireflyIII\Repositories\Tag\TagRepositoryInterface');
|
$tagRepository = app('FireflyIII\Repositories\Tag\TagRepositoryInterface');
|
||||||
$balance = new Balance;
|
$balance = new Balance;
|
||||||
|
|
||||||
// build a balance header:
|
// build a balance header:
|
||||||
$header = new BalanceHeader;
|
$header = new BalanceHeader;
|
||||||
|
$budgets = $repository->getBudgets();
|
||||||
$accounts = $this->query->getAllAccounts($start, $end, $shared);
|
|
||||||
$budgets = $repository->getBudgets();
|
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
$header->addAccount($account);
|
$header->addAccount($account);
|
||||||
}
|
}
|
||||||
@@ -134,6 +300,7 @@ class ReportHelper implements ReportHelperInterface
|
|||||||
|
|
||||||
// get budget amount for current period:
|
// get budget amount for current period:
|
||||||
$rep = $repository->getCurrentRepetition($budget, $start, $end);
|
$rep = $repository->getCurrentRepetition($budget, $start, $end);
|
||||||
|
// could be null?
|
||||||
$line->setRepetition($rep);
|
$line->setRepetition($rep);
|
||||||
|
|
||||||
// loop accounts:
|
// loop accounts:
|
||||||
@@ -142,7 +309,7 @@ class ReportHelper implements ReportHelperInterface
|
|||||||
$balanceEntry->setAccount($account);
|
$balanceEntry->setAccount($account);
|
||||||
|
|
||||||
// get spent:
|
// get spent:
|
||||||
$spent = $this->query->spentInBudgetCorrected($account, $budget, $start, $end); // I think shared is irrelevant.
|
$spent = $this->query->spentInBudget($account, $budget, $start, $end); // I think shared is irrelevant.
|
||||||
|
|
||||||
$balanceEntry->setSpent($spent);
|
$balanceEntry->setSpent($spent);
|
||||||
$line->addBalanceEntry($balanceEntry);
|
$line->addBalanceEntry($balanceEntry);
|
||||||
@@ -153,6 +320,7 @@ class ReportHelper implements ReportHelperInterface
|
|||||||
|
|
||||||
// then a new line for without budget.
|
// then a new line for without budget.
|
||||||
// and one for the tags:
|
// and one for the tags:
|
||||||
|
// and one for "left unbalanced".
|
||||||
$empty = new BalanceLine;
|
$empty = new BalanceLine;
|
||||||
$tags = new BalanceLine;
|
$tags = new BalanceLine;
|
||||||
$diffLine = new BalanceLine;
|
$diffLine = new BalanceLine;
|
||||||
@@ -164,7 +332,7 @@ class ReportHelper implements ReportHelperInterface
|
|||||||
$spent = $this->query->spentNoBudget($account, $start, $end);
|
$spent = $this->query->spentNoBudget($account, $start, $end);
|
||||||
$left = $tagRepository->coveredByBalancingActs($account, $start, $end);
|
$left = $tagRepository->coveredByBalancingActs($account, $start, $end);
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
$diff = bcsub($spent, $left);
|
$diff = bcadd($spent, $left);
|
||||||
|
|
||||||
// budget
|
// budget
|
||||||
$budgetEntry = new BalanceEntry;
|
$budgetEntry = new BalanceEntry;
|
||||||
@@ -199,16 +367,19 @@ class ReportHelper implements ReportHelperInterface
|
|||||||
* This method generates a full report for the given period on all
|
* This method generates a full report for the given period on all
|
||||||
* the users bills and their payments.
|
* the users bills and their payments.
|
||||||
*
|
*
|
||||||
* @param Carbon $start
|
* Excludes bills which have not had a payment on the mentioned accounts.
|
||||||
* @param Carbon $end
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return BillCollection
|
* @return BillCollection
|
||||||
*/
|
*/
|
||||||
public function getBillReport(Carbon $start, Carbon $end)
|
public function getBillReport(Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
|
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
|
||||||
$repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface');
|
$repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface');
|
||||||
$bills = $repository->getBills();
|
$bills = $repository->getBillsForAccounts($accounts);
|
||||||
$collection = new BillCollection;
|
$collection = new BillCollection;
|
||||||
|
|
||||||
/** @var Bill $bill */
|
/** @var Bill $bill */
|
||||||
@@ -238,168 +409,5 @@ class ReportHelper implements ReportHelperInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $collection;
|
return $collection;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
* @param boolean $shared
|
|
||||||
*
|
|
||||||
* @return BudgetCollection
|
|
||||||
*/
|
|
||||||
public function getBudgetReport(Carbon $start, Carbon $end, $shared)
|
|
||||||
{
|
|
||||||
$object = new BudgetCollection;
|
|
||||||
/** @var \FireflyIII\Repositories\Budget\BudgetRepositoryInterface $repository */
|
|
||||||
$repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
|
||||||
$set = $repository->getBudgets();
|
|
||||||
|
|
||||||
bcscale(2);
|
|
||||||
|
|
||||||
foreach ($set as $budget) {
|
|
||||||
|
|
||||||
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
|
|
||||||
|
|
||||||
// no repetition(s) for this budget:
|
|
||||||
if ($repetitions->count() == 0) {
|
|
||||||
$spent = $repository->balanceInPeriod($budget, $start, $end, $shared);
|
|
||||||
$budgetLine = new BudgetLine;
|
|
||||||
$budgetLine->setBudget($budget);
|
|
||||||
$budgetLine->setOverspent($spent);
|
|
||||||
$object->addOverspent($spent);
|
|
||||||
$object->addBudgetLine($budgetLine);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// one or more repetitions for budget:
|
|
||||||
/** @var LimitRepetition $repetition */
|
|
||||||
foreach ($repetitions as $repetition) {
|
|
||||||
$budgetLine = new BudgetLine;
|
|
||||||
$budgetLine->setBudget($budget);
|
|
||||||
$budgetLine->setRepetition($repetition);
|
|
||||||
$expenses = $repository->balanceInPeriod($budget, $repetition->startdate, $repetition->enddate, $shared);
|
|
||||||
$expenses = $expenses * -1;
|
|
||||||
$left = $expenses < $repetition->amount ? bcsub($repetition->amount, $expenses) : 0;
|
|
||||||
$spent = $expenses > $repetition->amount ? 0 : $expenses;
|
|
||||||
$overspent = $expenses > $repetition->amount ? bcsub($expenses, $repetition->amount) : 0;
|
|
||||||
|
|
||||||
$budgetLine->setLeft($left);
|
|
||||||
$budgetLine->setSpent($spent);
|
|
||||||
$budgetLine->setOverspent($overspent);
|
|
||||||
$budgetLine->setBudgeted($repetition->amount);
|
|
||||||
|
|
||||||
$object->addBudgeted($repetition->amount);
|
|
||||||
$object->addSpent($spent);
|
|
||||||
$object->addLeft($left);
|
|
||||||
$object->addOverspent($overspent);
|
|
||||||
$object->addBudgetLine($budgetLine);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// stuff outside of budgets:
|
|
||||||
$noBudget = $repository->getWithoutBudgetSum($start, $end);
|
|
||||||
$budgetLine = new BudgetLine;
|
|
||||||
$budgetLine->setOverspent($noBudget);
|
|
||||||
$object->addOverspent($noBudget);
|
|
||||||
$object->addBudgetLine($budgetLine);
|
|
||||||
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
* @param boolean $shared
|
|
||||||
*
|
|
||||||
* @return CategoryCollection
|
|
||||||
*/
|
|
||||||
public function getCategoryReport(Carbon $start, Carbon $end, $shared)
|
|
||||||
{
|
|
||||||
$object = new CategoryCollection;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET CATEGORIES:
|
|
||||||
*/
|
|
||||||
/** @var \FireflyIII\Repositories\Category\CategoryRepositoryInterface $repository */
|
|
||||||
$repository = app('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
|
||||||
$set = $repository->getCategories();
|
|
||||||
foreach ($set as $category) {
|
|
||||||
$spent = $repository->balanceInPeriod($category, $start, $end, $shared);
|
|
||||||
$category->spent = $spent;
|
|
||||||
$object->addCategory($category);
|
|
||||||
$object->addTotal($spent);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a full report on the users expenses during the period.
|
|
||||||
*
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
* @param boolean $shared
|
|
||||||
*
|
|
||||||
* @return Expense
|
|
||||||
*/
|
|
||||||
public function getExpenseReport($start, $end, $shared)
|
|
||||||
{
|
|
||||||
$object = new Expense;
|
|
||||||
$set = $this->query->expenseInPeriodCorrected($start, $end, $shared);
|
|
||||||
foreach ($set as $entry) {
|
|
||||||
$object->addToTotal($entry->amount_positive);
|
|
||||||
$object->addOrCreateExpense($entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a full report on the users incomes during the period.
|
|
||||||
*
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
* @param boolean $shared
|
|
||||||
*
|
|
||||||
* @return Income
|
|
||||||
*/
|
|
||||||
public function getIncomeReport($start, $end, $shared)
|
|
||||||
{
|
|
||||||
$object = new Income;
|
|
||||||
$set = $this->query->incomeInPeriodCorrected($start, $end, $shared);
|
|
||||||
foreach ($set as $entry) {
|
|
||||||
$object->addToTotal($entry->amount_positive);
|
|
||||||
$object->addOrCreateIncome($entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Carbon $date
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function listOfMonths(Carbon $date)
|
|
||||||
{
|
|
||||||
|
|
||||||
$start = clone $date;
|
|
||||||
$end = Carbon::now();
|
|
||||||
$months = [];
|
|
||||||
while ($start <= $end) {
|
|
||||||
$year = $start->year;
|
|
||||||
$months[$year][] = [
|
|
||||||
'formatted' => $start->formatLocalized('%B %Y'),
|
|
||||||
'month' => $start->month,
|
|
||||||
'year' => $year,
|
|
||||||
];
|
|
||||||
$start->addMonth();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $months;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
|
|||||||
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
|
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
|
||||||
use FireflyIII\Helpers\Collection\Expense;
|
use FireflyIII\Helpers\Collection\Expense;
|
||||||
use FireflyIII\Helpers\Collection\Income;
|
use FireflyIII\Helpers\Collection\Income;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface ReportHelperInterface
|
* Interface ReportHelperInterface
|
||||||
@@ -21,75 +22,78 @@ interface ReportHelperInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method generates a full report for the given period on all
|
* This method generates a full report for the given period on all
|
||||||
* the users asset and cash accounts.
|
* given accounts
|
||||||
*
|
*
|
||||||
* @param Carbon $date
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param boolean $shared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return AccountCollection
|
* @return AccountCollection
|
||||||
*/
|
*/
|
||||||
public function getAccountReport(Carbon $date, Carbon $end, $shared);
|
public function getAccountReport(Carbon $start, Carbon $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method generates a full report for the given period on all
|
* This method generates a full report for the given period on all
|
||||||
* the users bills and their payments.
|
* the users bills and their payments.
|
||||||
*
|
*
|
||||||
* @param Carbon $start
|
* Excludes bills which have not had a payment on the mentioned accounts.
|
||||||
* @param Carbon $end
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return BillCollection
|
* @return BillCollection
|
||||||
*/
|
*/
|
||||||
public function getBillReport(Carbon $start, Carbon $end);
|
public function getBillReport(Carbon $start, Carbon $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param boolean $shared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return Balance
|
* @return Balance
|
||||||
*/
|
*/
|
||||||
public function getBalanceReport(Carbon $start, Carbon $end, $shared);
|
public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param boolean $shared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return BudgetCollection
|
* @return BudgetCollection
|
||||||
*/
|
*/
|
||||||
public function getBudgetReport(Carbon $start, Carbon $end, $shared);
|
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param boolean $shared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return CategoryCollection
|
* @return CategoryCollection
|
||||||
*/
|
*/
|
||||||
public function getCategoryReport(Carbon $start, Carbon $end, $shared);
|
public function getCategoryReport(Carbon $start, Carbon $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a full report on the users expenses during the period.
|
* Get a full report on the users expenses during the period for a list of accounts.
|
||||||
*
|
*
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param boolean $shared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return Expense
|
* @return Expense
|
||||||
*/
|
*/
|
||||||
public function getExpenseReport($start, $end, $shared);
|
public function getExpenseReport($start, $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a full report on the users incomes during the period.
|
* Get a full report on the users incomes during the period for the given accounts.
|
||||||
*
|
*
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param boolean $shared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return Income
|
* @return Income
|
||||||
*/
|
*/
|
||||||
public function getIncomeReport($start, $end, $shared);
|
public function getIncomeReport($start, $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ use Crypt;
|
|||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Query\JoinClause;
|
use Illuminate\Database\Query\JoinClause;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Steam;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ReportQuery
|
* Class ReportQuery
|
||||||
@@ -20,178 +20,6 @@ use Steam;
|
|||||||
*/
|
*/
|
||||||
class ReportQuery implements ReportQueryInterface
|
class ReportQuery implements ReportQueryInterface
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* See ReportQueryInterface::incomeInPeriodCorrected.
|
|
||||||
*
|
|
||||||
* This method's length is caused mainly by the query build stuff. Therefor:
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
|
||||||
*
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
* @param bool $includeShared
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function expenseInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false)
|
|
||||||
{
|
|
||||||
$query = $this->queryJournalsWithTransactions($start, $end);
|
|
||||||
if ($includeShared === false) {
|
|
||||||
$query->where(
|
|
||||||
function (Builder $query) {
|
|
||||||
$query->where(
|
|
||||||
function (Builder $q) { // only get withdrawals not from a shared account
|
|
||||||
$q->where('transaction_types.type', 'Withdrawal');
|
|
||||||
$q->where('acm_from.data', '!=', '"sharedAsset"');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
$query->orWhere(
|
|
||||||
function (Builder $q) { // and transfers from a shared account.
|
|
||||||
$q->where('transaction_types.type', 'Transfer');
|
|
||||||
$q->where('acm_to.data', '=', '"sharedAsset"');
|
|
||||||
$q->where('acm_from.data', '!=', '"sharedAsset"');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$query->where('transaction_types.type', 'Withdrawal'); // any withdrawal is fine.
|
|
||||||
}
|
|
||||||
$query->orderBy('transaction_journals.date');
|
|
||||||
$data = $query->get( // get everything
|
|
||||||
['transaction_journals.*', 'transaction_types.type', 'ac_to.name as name', 'ac_to.id as account_id', 'ac_to.encrypted as account_encrypted']
|
|
||||||
);
|
|
||||||
|
|
||||||
$data->each(
|
|
||||||
function (TransactionJournal $journal) {
|
|
||||||
if (intval($journal->account_encrypted) == 1) {
|
|
||||||
$journal->name = Crypt::decrypt($journal->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a users accounts combined with various meta-data related to the start and end date.
|
|
||||||
*
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
* @param bool $includeShared
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function getAllAccounts(Carbon $start, Carbon $end, $includeShared = false)
|
|
||||||
{
|
|
||||||
$query = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')
|
|
||||||
->accountTypeIn(['Default account', 'Asset account', 'Cash account']);
|
|
||||||
if ($includeShared === false) {
|
|
||||||
$query->leftJoin(
|
|
||||||
'account_meta', function (JoinClause $join) {
|
|
||||||
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
|
|
||||||
}
|
|
||||||
)
|
|
||||||
->where(
|
|
||||||
function (Builder $query) {
|
|
||||||
|
|
||||||
$query->where('account_meta.data', '!=', '"sharedAsset"');
|
|
||||||
$query->orWhereNull('account_meta.data');
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$set = $query->get(['accounts.*']);
|
|
||||||
$set->each(
|
|
||||||
function (Account $account) use ($start, $end) {
|
|
||||||
/**
|
|
||||||
* The balance for today always incorporates transactions
|
|
||||||
* made on today. So to get todays "start" balance, we sub one
|
|
||||||
* day.
|
|
||||||
*/
|
|
||||||
$yesterday = clone $start;
|
|
||||||
$yesterday->subDay();
|
|
||||||
|
|
||||||
/** @noinspection PhpParamsInspection */
|
|
||||||
$account->startBalance = Steam::balance($account, $yesterday);
|
|
||||||
$account->endBalance = Steam::balance($account, $end);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return $set;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results
|
|
||||||
* will simply list the transaction journals only. This should allow any follow up counting to be accurate with
|
|
||||||
* regards to tags.
|
|
||||||
*
|
|
||||||
* This method returns all "income" journals in a certain period, which are both transfers from a shared account
|
|
||||||
* and "ordinary" deposits. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
|
|
||||||
* not group and returns different fields.
|
|
||||||
*
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
* @param bool $includeShared
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function incomeInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false)
|
|
||||||
{
|
|
||||||
$query = $this->queryJournalsWithTransactions($start, $end);
|
|
||||||
if ($includeShared === false) {
|
|
||||||
// only get deposits not to a shared account
|
|
||||||
// and transfers to a shared account.
|
|
||||||
$query->where(
|
|
||||||
function (Builder $query) {
|
|
||||||
$query->where(
|
|
||||||
function (Builder $q) {
|
|
||||||
$q->where('transaction_types.type', 'Deposit');
|
|
||||||
$q->where('acm_to.data', '!=', '"sharedAsset"');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
$query->orWhere(
|
|
||||||
function (Builder $q) {
|
|
||||||
$q->where('transaction_types.type', 'Transfer');
|
|
||||||
$q->where('acm_from.data', '=', '"sharedAsset"');
|
|
||||||
$q->where('acm_to.data','!=','"sharedAsset"');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// any deposit is fine.
|
|
||||||
$query->where('transaction_types.type', 'Deposit');
|
|
||||||
}
|
|
||||||
$query->orderBy('transaction_journals.date');
|
|
||||||
|
|
||||||
// get everything
|
|
||||||
$data = $query->get(
|
|
||||||
['transaction_journals.*', 'transaction_types.type', 'ac_from.name as name', 'ac_from.id as account_id', 'ac_from.encrypted as account_encrypted']
|
|
||||||
);
|
|
||||||
|
|
||||||
$data->each(
|
|
||||||
function (TransactionJournal $journal) {
|
|
||||||
if (intval($journal->account_encrypted) == 1) {
|
|
||||||
$journal->name = Crypt::decrypt($journal->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
$data = $data->filter(
|
|
||||||
function (TransactionJournal $journal) {
|
|
||||||
if ($journal->amount != 0) {
|
|
||||||
return $journal;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Covers tags
|
* Covers tags
|
||||||
*
|
*
|
||||||
@@ -202,22 +30,18 @@ class ReportQuery implements ReportQueryInterface
|
|||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
public function spentInBudgetCorrected(Account $account, Budget $budget, Carbon $start, Carbon $end)
|
public function spentInBudget(Account $account, Budget $budget, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
|
|
||||||
bcscale(2);
|
return Auth::user()->transactionjournals()
|
||||||
|
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
return bcmul(
|
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
Auth::user()->transactionjournals()
|
->transactionTypes([TransactionType::WITHDRAWAL])
|
||||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
->where('transactions.account_id', $account->id)
|
||||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
->before($end)
|
||||||
->transactionTypes(['Withdrawal'])
|
->after($start)
|
||||||
->where('transactions.account_id', $account->id)
|
->where('budget_transaction_journal.budget_id', $budget->id)
|
||||||
->before($end)
|
->get(['transaction_journals.*'])->sum('amount');
|
||||||
->after($start)
|
|
||||||
->where('budget_transaction_journal.budget_id', $budget->id)
|
|
||||||
->get(['transaction_journals.*'])->sum('amount'), -1
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -233,7 +57,7 @@ class ReportQuery implements ReportQueryInterface
|
|||||||
Auth::user()->transactionjournals()
|
Auth::user()->transactionjournals()
|
||||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
->transactionTypes(['Withdrawal'])
|
->transactionTypes([TransactionType::WITHDRAWAL])
|
||||||
->where('transactions.account_id', $account->id)
|
->where('transactions.account_id', $account->id)
|
||||||
->before($end)
|
->before($end)
|
||||||
->after($start)
|
->after($start)
|
||||||
@@ -276,4 +100,144 @@ class ReportQuery implements ReportQueryInterface
|
|||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results
|
||||||
|
* will simply list the transaction journals only. This should allow any follow up counting to be accurate with
|
||||||
|
* regards to tags. It will only get the incomes to the specified accounts.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function incomeInPeriod(Carbon $start, Carbon $end, Collection $accounts)
|
||||||
|
{
|
||||||
|
$query = $this->queryJournalsWithTransactions($start, $end);
|
||||||
|
|
||||||
|
$ids = [];
|
||||||
|
/** @var Account $account */
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$ids[] = $account->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OR is a deposit
|
||||||
|
// OR any transfer TO the accounts in $accounts, not FROM any of the accounts in $accounts.
|
||||||
|
$query->where(
|
||||||
|
function (Builder $query) use ($ids) {
|
||||||
|
$query->where(
|
||||||
|
function (Builder $q) {
|
||||||
|
$q->where('transaction_types.type', TransactionType::DEPOSIT);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$query->orWhere(
|
||||||
|
function (Builder $q) use ($ids) {
|
||||||
|
$q->where('transaction_types.type', TransactionType::TRANSFER);
|
||||||
|
$q->whereNotIn('ac_from.id', $ids);
|
||||||
|
$q->whereIn('ac_to.id', $ids);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// only include selected accounts.
|
||||||
|
$query->whereIn('ac_to.id', $ids);
|
||||||
|
$query->orderBy('transaction_journals.date');
|
||||||
|
|
||||||
|
// get everything
|
||||||
|
$data = $query->get(
|
||||||
|
['transaction_journals.*',
|
||||||
|
'transaction_types.type', 'ac_from.name as name',
|
||||||
|
't_from.amount as from_amount',
|
||||||
|
't_to.amount as to_amount',
|
||||||
|
'ac_from.id as account_id', 'ac_from.encrypted as account_encrypted']
|
||||||
|
);
|
||||||
|
|
||||||
|
$data->each(
|
||||||
|
function (TransactionJournal $journal) {
|
||||||
|
if (intval($journal->account_encrypted) == 1) {
|
||||||
|
$journal->name = Crypt::decrypt($journal->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// $data = $data->filter(
|
||||||
|
// function (TransactionJournal $journal) {
|
||||||
|
// if ($journal->amount != 0) {
|
||||||
|
// return $journal;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See ReportQueryInterface::incomeInPeriod
|
||||||
|
*
|
||||||
|
* This method returns all "expense" journals in a certain period, which are both transfers to a shared account
|
||||||
|
* and "ordinary" withdrawals. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
|
||||||
|
* not group and returns different fields.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function expenseInPeriod(Carbon $start, Carbon $end, Collection $accounts)
|
||||||
|
{
|
||||||
|
$ids = [];
|
||||||
|
|
||||||
|
/** @var Account $account */
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$ids[] = $account->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->queryJournalsWithTransactions($start, $end);
|
||||||
|
|
||||||
|
// withdrawals from any account are an expense.
|
||||||
|
// transfers away, from an account in the list, to an account not in the list, are an expense.
|
||||||
|
|
||||||
|
$query->where(
|
||||||
|
function (Builder $query) use ($ids) {
|
||||||
|
$query->where(
|
||||||
|
function (Builder $q) {
|
||||||
|
$q->where('transaction_types.type', TransactionType::WITHDRAWAL);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$query->orWhere(
|
||||||
|
function (Builder $q) use ($ids) {
|
||||||
|
$q->where('transaction_types.type', TransactionType::TRANSFER);
|
||||||
|
$q->whereIn('ac_from.id', $ids);
|
||||||
|
$q->whereNotIn('ac_to.id', $ids);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// expense goes from the selected accounts:
|
||||||
|
$query->whereIn('ac_from.id', $ids);
|
||||||
|
|
||||||
|
$query->orderBy('transaction_journals.date');
|
||||||
|
$data = $query->get( // get everything
|
||||||
|
['transaction_journals.*', 'transaction_types.type',
|
||||||
|
't_from.amount as from_amount',
|
||||||
|
't_to.amount as to_amount',
|
||||||
|
'ac_to.name as name', 'ac_to.id as account_id', 'ac_to.encrypted as account_encrypted']
|
||||||
|
);
|
||||||
|
|
||||||
|
$data->each(
|
||||||
|
function (TransactionJournal $journal) {
|
||||||
|
if (intval($journal->account_encrypted) == 1) {
|
||||||
|
$journal->name = Crypt::decrypt($journal->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,44 +16,33 @@ interface ReportQueryInterface
|
|||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See ReportQueryInterface::incomeInPeriodCorrected
|
* See ReportQueryInterface::incomeInPeriod
|
||||||
*
|
*
|
||||||
* This method returns all "expense" journals in a certain period, which are both transfers to a shared account
|
* This method returns all "expense" journals in a certain period, which are both transfers to a shared account
|
||||||
* and "ordinary" withdrawals. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
|
* and "ordinary" withdrawals. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
|
||||||
* not group and returns different fields.
|
* not group and returns different fields.
|
||||||
*
|
*
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param bool $includeShared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function expenseInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false);
|
public function expenseInPeriod(Carbon $start, Carbon $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a users accounts combined with various meta-data related to the start and end date.
|
|
||||||
*
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
* @param bool $includeShared
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function getAllAccounts(Carbon $start, Carbon $end, $includeShared = false);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results
|
* This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results
|
||||||
* will simply list the transaction journals only. This should allow any follow up counting to be accurate with
|
* will simply list the transaction journals only. This should allow any follow up counting to be accurate with
|
||||||
* regards to tags.
|
* regards to tags. It will only get the incomes to the specified accounts.
|
||||||
*
|
*
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param bool $includeShared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function incomeInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false);
|
public function incomeInPeriod(Carbon $start, Carbon $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Covers tags as well.
|
* Covers tags as well.
|
||||||
@@ -65,7 +54,7 @@ interface ReportQueryInterface
|
|||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
public function spentInBudgetCorrected(Account $account, Budget $budget, Carbon $start, Carbon $end);
|
public function spentInBudget(Account $account, Budget $budget, Carbon $start, Carbon $end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Account $account
|
* @param Account $account
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ class AccountController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create($what = 'asset')
|
public function create($what = 'asset')
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||||
$subTitle = trans('firefly.make_new_' . $what . '_account');
|
$subTitle = trans('firefly.make_new_' . $what . '_account');
|
||||||
|
|
||||||
@@ -211,13 +213,14 @@ class AccountController extends Controller
|
|||||||
'name' => $request->input('name'),
|
'name' => $request->input('name'),
|
||||||
'accountType' => $request->input('what'),
|
'accountType' => $request->input('what'),
|
||||||
'virtualBalance' => round($request->input('virtualBalance'), 2),
|
'virtualBalance' => round($request->input('virtualBalance'), 2),
|
||||||
|
'virtualBalanceCurrency' => intval($request->input('amount_currency_id_virtualBalance')),
|
||||||
'active' => true,
|
'active' => true,
|
||||||
'user' => Auth::user()->id,
|
'user' => Auth::user()->id,
|
||||||
'iban' => $request->input('iban'),
|
'iban' => $request->input('iban'),
|
||||||
'accountRole' => $request->input('accountRole'),
|
'accountRole' => $request->input('accountRole'),
|
||||||
'openingBalance' => round($request->input('openingBalance'), 2),
|
'openingBalance' => round($request->input('openingBalance'), 2),
|
||||||
'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')),
|
'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')),
|
||||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
'openingBalanceCurrency' => intval($request->input('amount_currency_id_openingBalance')),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?php namespace FireflyIII\Http\Controllers\Auth;
|
<?php namespace FireflyIII\Http\Controllers\Auth;
|
||||||
|
|
||||||
use Auth;
|
use Auth;
|
||||||
|
use Config;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\Role;
|
use FireflyIII\Models\Role;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
@@ -8,6 +9,7 @@ use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
|
|||||||
use Illuminate\Foundation\Auth\ThrottlesLogins;
|
use Illuminate\Foundation\Auth\ThrottlesLogins;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Mail\Message;
|
use Illuminate\Mail\Message;
|
||||||
|
use Log;
|
||||||
use Mail;
|
use Mail;
|
||||||
use Request as Rq;
|
use Request as Rq;
|
||||||
use Session;
|
use Session;
|
||||||
@@ -23,6 +25,18 @@ class AuthController extends Controller
|
|||||||
{
|
{
|
||||||
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
|
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the user out of the application.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function getLogout()
|
||||||
|
{
|
||||||
|
Auth::logout();
|
||||||
|
|
||||||
|
return redirect('/auth/login');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the application registration form.
|
* Show the application registration form.
|
||||||
*
|
*
|
||||||
@@ -74,7 +88,10 @@ class AuthController extends Controller
|
|||||||
$foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first();
|
$foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first();
|
||||||
if (!is_null($foundUser)) {
|
if (!is_null($foundUser)) {
|
||||||
// if it exists, show message:
|
// if it exists, show message:
|
||||||
$code = $foundUser->blocked_code;
|
$code = $foundUser->blocked_code;
|
||||||
|
if (strlen($code) == 0) {
|
||||||
|
$code = 'general_blocked';
|
||||||
|
}
|
||||||
$message = trans('firefly.' . $code . '_error', ['email' => $credentials['email']]);
|
$message = trans('firefly.' . $code . '_error', ['email' => $credentials['email']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,21 +160,35 @@ class AuthController extends Controller
|
|||||||
}
|
}
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
|
||||||
$data = $request->all();
|
$data = $request->all();
|
||||||
$data['password'] = bcrypt($data['password']);
|
$data['password'] = bcrypt($data['password']);
|
||||||
|
|
||||||
|
// is user email domain blocked?
|
||||||
|
if ($this->isBlockedDomain($data['email'])) {
|
||||||
|
$validator->getMessageBag()->add('email', trans('validation.invalid_domain'));
|
||||||
|
$this->throwValidationException(
|
||||||
|
$request, $validator
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Auth::login($this->create($data));
|
Auth::login($this->create($data));
|
||||||
|
|
||||||
// get the email address
|
// get the email address
|
||||||
if (Auth::user() instanceof User) {
|
if (Auth::user() instanceof User) {
|
||||||
$email = Auth::user()->email;
|
$email = Auth::user()->email;
|
||||||
$address = route('index');
|
$address = route('index');
|
||||||
|
$ipAddress = $request->ip();
|
||||||
// send email.
|
// send email.
|
||||||
Mail::send(
|
try {
|
||||||
['emails.registered-html', 'emails.registered'], ['address' => $address], function (Message $message) use ($email) {
|
Mail::send(
|
||||||
$message->to($email, $email)->subject('Welcome to Firefly III! ');
|
['emails.registered-html', 'emails.registered'], ['address' => $address, 'ip' => $ipAddress], function (Message $message) use ($email) {
|
||||||
|
$message->to($email, $email)->subject('Welcome to Firefly III! ');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (\Swift_TransportException $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
// set flash message
|
// set flash message
|
||||||
Session::flash('success', 'You have registered successfully!');
|
Session::flash('success', 'You have registered successfully!');
|
||||||
@@ -180,6 +211,35 @@ class AuthController extends Controller
|
|||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getBlockedDomains()
|
||||||
|
{
|
||||||
|
$set = Config::get('mail.blocked_domains');
|
||||||
|
$domains = [];
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$domain = trim($entry);
|
||||||
|
if (strlen($domain) > 0) {
|
||||||
|
$domains[] = $domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $domains;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isBlockedDomain($email)
|
||||||
|
{
|
||||||
|
$parts = explode('@', $email);
|
||||||
|
$blocked = $this->getBlockedDomains();
|
||||||
|
|
||||||
|
if (isset($parts[1]) && in_array($parts[1], $blocked)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a validator for an incoming registration request.
|
* Get a validator for an incoming registration request.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
<?php namespace FireflyIII\Http\Controllers\Auth;
|
<?php namespace FireflyIII\Http\Controllers\Auth;
|
||||||
|
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
|
use FireflyIII\User;
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Mail\Message;
|
||||||
|
use Illuminate\Support\Facades\Password;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class PasswordController
|
* Class PasswordController
|
||||||
@@ -41,4 +45,38 @@ class PasswordController extends Controller
|
|||||||
$this->middleware('guest');
|
$this->middleware('guest');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a reset link to the given user.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function postEmail(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, ['email' => 'required|email']);
|
||||||
|
|
||||||
|
$user = User::whereEmail($request->get('email'))->first();
|
||||||
|
|
||||||
|
if (!is_null($user) && intval($user->blocked) === 1) {
|
||||||
|
$response = 'passwords.blocked';
|
||||||
|
} else {
|
||||||
|
$response = Password::sendResetLink(
|
||||||
|
$request->only('email'), function (Message $message) {
|
||||||
|
$message->subject($this->getEmailSubject());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($response) {
|
||||||
|
case Password::RESET_LINK_SENT:
|
||||||
|
return redirect()->back()->with('status', trans($response));
|
||||||
|
|
||||||
|
case Password::INVALID_USER:
|
||||||
|
case 'passwords.blocked':
|
||||||
|
return redirect()->back()->withErrors(['email' => trans($response)]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use Carbon\Carbon;
|
|||||||
use FireflyIII\Http\Requests\BudgetFormRequest;
|
use FireflyIII\Http\Requests\BudgetFormRequest;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\LimitRepetition;
|
use FireflyIII\Models\LimitRepetition;
|
||||||
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use Input;
|
use Input;
|
||||||
use Navigation;
|
use Navigation;
|
||||||
@@ -135,7 +136,7 @@ class BudgetController extends Controller
|
|||||||
*
|
*
|
||||||
* @return \Illuminate\View\View
|
* @return \Illuminate\View\View
|
||||||
*/
|
*/
|
||||||
public function index(BudgetRepositoryInterface $repository)
|
public function index(BudgetRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||||
{
|
{
|
||||||
$budgets = $repository->getActiveBudgets();
|
$budgets = $repository->getActiveBudgets();
|
||||||
$inactive = $repository->getInactiveBudgets();
|
$inactive = $repository->getInactiveBudgets();
|
||||||
@@ -147,6 +148,8 @@ class BudgetController extends Controller
|
|||||||
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
|
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
|
||||||
$budgetIncomeTotal = Preferences::get($key, 1000)->data;
|
$budgetIncomeTotal = Preferences::get($key, 1000)->data;
|
||||||
$period = Navigation::periodShow($start, $range);
|
$period = Navigation::periodShow($start, $range);
|
||||||
|
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
|
||||||
|
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
/**
|
/**
|
||||||
* Do some cleanup:
|
* Do some cleanup:
|
||||||
@@ -156,7 +159,7 @@ class BudgetController extends Controller
|
|||||||
// loop the budgets:
|
// loop the budgets:
|
||||||
/** @var Budget $budget */
|
/** @var Budget $budget */
|
||||||
foreach ($budgets as $budget) {
|
foreach ($budgets as $budget) {
|
||||||
$budget->spent = $repository->balanceInPeriod($budget, $start, $end);
|
$budget->spent = $repository->balanceInPeriod($budget, $start, $end, $accounts);
|
||||||
$budget->currentRep = $repository->getCurrentRepetition($budget, $start, $end);
|
$budget->currentRep = $repository->getCurrentRepetition($budget, $start, $end);
|
||||||
if ($budget->currentRep) {
|
if ($budget->currentRep) {
|
||||||
$budgeted = bcadd($budgeted, $budget->currentRep->amount);
|
$budgeted = bcadd($budgeted, $budget->currentRep->amount);
|
||||||
@@ -170,7 +173,7 @@ class BudgetController extends Controller
|
|||||||
$defaultCurrency = Amount::getDefaultCurrency();
|
$defaultCurrency = Amount::getDefaultCurrency();
|
||||||
|
|
||||||
return view(
|
return view(
|
||||||
'budgets.index', compact('budgetMaximum','period', 'range', 'budgetIncomeTotal', 'defaultCurrency', 'inactive', 'budgets', 'spent', 'budgeted')
|
'budgets.index', compact('budgetMaximum', 'period', 'range', 'budgetIncomeTotal', 'defaultCurrency', 'inactive', 'budgets', 'spent', 'budgeted')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +282,7 @@ class BudgetController extends Controller
|
|||||||
{
|
{
|
||||||
$budgetData = [
|
$budgetData = [
|
||||||
'name' => $request->input('name'),
|
'name' => $request->input('name'),
|
||||||
'active' => intval($request->input('active')) == 1
|
'active' => intval($request->input('active')) == 1,
|
||||||
];
|
];
|
||||||
|
|
||||||
$repository->update($budget, $budgetData);
|
$repository->update($budget, $budgetData);
|
||||||
|
|||||||
@@ -35,45 +35,32 @@ class AccountController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the balances for all the user's accounts.
|
* Shows the balances for a given set of dates and accounts.
|
||||||
|
*
|
||||||
|
* TODO fix parameters.
|
||||||
*
|
*
|
||||||
* @param AccountRepositoryInterface $repository
|
* @param AccountRepositoryInterface $repository
|
||||||
*
|
*
|
||||||
* @param $year
|
* @param $url
|
||||||
* @param $month
|
|
||||||
* @param bool $shared
|
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
*/
|
*/
|
||||||
public function all(AccountRepositoryInterface $repository, $year, $month, $shared = false)
|
public function report($report_type, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
$start = new Carbon($year . '-' . $month . '-01');
|
|
||||||
$end = clone $start;
|
|
||||||
$end->endOfMonth();
|
|
||||||
|
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('all');
|
$cache->addProperty('all');
|
||||||
$cache->addProperty('accounts');
|
$cache->addProperty('accounts');
|
||||||
|
$cache->addProperty('default');
|
||||||
|
$cache->addProperty($accounts);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var Collection $accounts */
|
|
||||||
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
|
|
||||||
if ($shared === false) {
|
|
||||||
/** @var Account $account */
|
|
||||||
foreach ($accounts as $index => $account) {
|
|
||||||
if ($account->getMeta('accountRole') == 'sharedAsset') {
|
|
||||||
$accounts->forget($index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make chart:
|
// make chart:
|
||||||
$data = $this->generator->all($accounts, $start, $end);
|
$data = $this->generator->frontpage($accounts, $start, $end);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use Carbon\Carbon;
|
|||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\LimitRepetition;
|
use FireflyIII\Models\LimitRepetition;
|
||||||
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -35,13 +36,86 @@ class BudgetController extends Controller
|
|||||||
$this->generator = app('FireflyIII\Generator\Chart\Budget\BudgetChartGenerator');
|
$this->generator = app('FireflyIII\Generator\Chart\Budget\BudgetChartGenerator');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BudgetRepositoryInterface $repository
|
||||||
|
* @param $report_type
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $budgets
|
||||||
|
*/
|
||||||
|
public function multiYear(BudgetRepositoryInterface $repository, $report_type, Carbon $start, Carbon $end, Collection $accounts, Collection $budgets)
|
||||||
|
{
|
||||||
|
// chart properties for cache:
|
||||||
|
$cache = new CacheProperties();
|
||||||
|
$cache->addProperty($report_type);
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($budgets);
|
||||||
|
$cache->addProperty('multiYearBudget');
|
||||||
|
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* budget
|
||||||
|
* year:
|
||||||
|
* spent: x
|
||||||
|
* budgeted: x
|
||||||
|
* year
|
||||||
|
* spent: x
|
||||||
|
* budgeted: x
|
||||||
|
*/
|
||||||
|
$entries = new Collection;
|
||||||
|
// go by budget, not by year.
|
||||||
|
foreach ($budgets as $budget) {
|
||||||
|
$entry = ['name' => '', 'spent' => [], 'budgeted' => []];
|
||||||
|
|
||||||
|
$currentStart = clone $start;
|
||||||
|
while ($currentStart < $end) {
|
||||||
|
// fix the date:
|
||||||
|
$currentEnd = clone $currentStart;
|
||||||
|
$currentEnd->endOfYear();
|
||||||
|
|
||||||
|
// get data:
|
||||||
|
if (is_null($budget->id)) {
|
||||||
|
$name = trans('firefly.noBudget');
|
||||||
|
$sum = $repository->getWithoutBudgetSum($currentStart, $currentEnd);
|
||||||
|
$budgeted = 0;
|
||||||
|
} else {
|
||||||
|
$name = $budget->name;
|
||||||
|
$sum = $repository->balanceInPeriod($budget, $currentStart, $currentEnd, $accounts);
|
||||||
|
$budgeted = $repository->getBudgetLimitRepetitions($budget, $currentStart, $currentEnd)->sum('amount');
|
||||||
|
}
|
||||||
|
|
||||||
|
// save to array:
|
||||||
|
$year = $currentStart->year;
|
||||||
|
$entry['name'] = $name;
|
||||||
|
$entry['spent'][$year] = ($sum * -1);
|
||||||
|
$entry['budgeted'][$year] = $budgeted;
|
||||||
|
|
||||||
|
// jump to next year.
|
||||||
|
$currentStart = clone $currentEnd;
|
||||||
|
$currentStart->addDay();
|
||||||
|
}
|
||||||
|
$entries->push($entry);
|
||||||
|
}
|
||||||
|
// generate chart with data:
|
||||||
|
$data = $this->generator->multiYear($entries);
|
||||||
|
|
||||||
|
return Response::json($data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param BudgetRepositoryInterface $repository
|
* @param BudgetRepositoryInterface $repository
|
||||||
* @param Budget $budget
|
* @param Budget $budget
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
*/
|
*/
|
||||||
public function budget(BudgetRepositoryInterface $repository, Budget $budget)
|
public function budget(BudgetRepositoryInterface $repository, AccountRepositoryInterface $accountRepository, Budget $budget)
|
||||||
{
|
{
|
||||||
|
|
||||||
// dates and times
|
// dates and times
|
||||||
@@ -50,7 +124,9 @@ class BudgetController extends Controller
|
|||||||
$last = Session::get('end', new Carbon);
|
$last = Session::get('end', new Carbon);
|
||||||
$final = clone $last;
|
$final = clone $last;
|
||||||
$final->addYears(2);
|
$final->addYears(2);
|
||||||
$last = Navigation::endOfX($last, $range, $final);
|
$last = Navigation::endOfX($last, $range, $final);
|
||||||
|
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
|
||||||
|
|
||||||
|
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
@@ -68,7 +144,7 @@ class BudgetController extends Controller
|
|||||||
$end->subDay();
|
$end->subDay();
|
||||||
$chartDate = clone $end;
|
$chartDate = clone $end;
|
||||||
$chartDate->startOfMonth();
|
$chartDate->startOfMonth();
|
||||||
$spent = $repository->balanceInPeriod($budget, $first, $end) * -1;
|
$spent = $repository->balanceInPeriod($budget, $first, $end, $accounts) * -1;
|
||||||
$entries->push([$chartDate, $spent]);
|
$entries->push([$chartDate, $spent]);
|
||||||
$first = Navigation::addPeriod($first, $range, 0);
|
$first = Navigation::addPeriod($first, $range, 0);
|
||||||
}
|
}
|
||||||
@@ -113,7 +189,7 @@ class BudgetController extends Controller
|
|||||||
/*
|
/*
|
||||||
* Sum of expenses on this day:
|
* Sum of expenses on this day:
|
||||||
*/
|
*/
|
||||||
$sum = $repository->expensesOnDayCorrected($budget, $start);
|
$sum = $repository->expensesOnDay($budget, $start);
|
||||||
$amount = bcadd($amount, $sum);
|
$amount = bcadd($amount, $sum);
|
||||||
$entries->push([clone $start, $amount]);
|
$entries->push([clone $start, $amount]);
|
||||||
$start->addDay();
|
$start->addDay();
|
||||||
@@ -133,12 +209,13 @@ class BudgetController extends Controller
|
|||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
*/
|
*/
|
||||||
public function frontpage(BudgetRepositoryInterface $repository)
|
public function frontpage(BudgetRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||||
{
|
{
|
||||||
$budgets = $repository->getBudgets();
|
$budgets = $repository->getBudgets();
|
||||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||||
$allEntries = new Collection;
|
$allEntries = new Collection;
|
||||||
|
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
|
||||||
|
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
@@ -156,13 +233,13 @@ class BudgetController extends Controller
|
|||||||
foreach ($budgets as $budget) {
|
foreach ($budgets as $budget) {
|
||||||
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
|
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
|
||||||
if ($repetitions->count() == 0) {
|
if ($repetitions->count() == 0) {
|
||||||
$expenses = $repository->balanceInPeriod($budget, $start, $end, true) * -1;
|
$expenses = $repository->balanceInPeriod($budget, $start, $end, $accounts) * -1;
|
||||||
$allEntries->push([$budget->name, 0, 0, $expenses, 0, 0]);
|
$allEntries->push([$budget->name, 0, 0, $expenses, 0, 0]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/** @var LimitRepetition $repetition */
|
/** @var LimitRepetition $repetition */
|
||||||
foreach ($repetitions as $repetition) {
|
foreach ($repetitions as $repetition) {
|
||||||
$expenses = $repository->balanceInPeriod($budget, $repetition->startdate, $repetition->enddate, true) * -1;
|
$expenses = $repository->balanceInPeriod($budget, $repetition->startdate, $repetition->enddate, $accounts) * -1;
|
||||||
// $left can be less than zero.
|
// $left can be less than zero.
|
||||||
// $overspent can be more than zero ( = overspending)
|
// $overspent can be more than zero ( = overspending)
|
||||||
|
|
||||||
@@ -197,11 +274,8 @@ class BudgetController extends Controller
|
|||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
*/
|
*/
|
||||||
public function year(BudgetRepositoryInterface $repository, $year, $shared = false)
|
public function year(BudgetRepositoryInterface $repository, $report_type, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
$start = new Carbon($year . '-01-01');
|
|
||||||
$end = new Carbon($year . '-12-31');
|
|
||||||
$shared = $shared == 'shared' ? true : false;
|
|
||||||
$allBudgets = $repository->getBudgets();
|
$allBudgets = $repository->getBudgets();
|
||||||
$budgets = new Collection;
|
$budgets = new Collection;
|
||||||
|
|
||||||
@@ -209,16 +283,17 @@ class BudgetController extends Controller
|
|||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($report_type);
|
||||||
|
$cache->addProperty($accounts);
|
||||||
$cache->addProperty('budget');
|
$cache->addProperty('budget');
|
||||||
$cache->addProperty('year');
|
$cache->addProperty('year');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter empty budgets:
|
// filter empty budgets:
|
||||||
|
|
||||||
foreach ($allBudgets as $budget) {
|
foreach ($allBudgets as $budget) {
|
||||||
$spent = $repository->balanceInPeriod($budget, $start, $end, $shared);
|
$spent = $repository->balanceInPeriod($budget, $start, $end, $accounts);
|
||||||
if ($spent != 0) {
|
if ($spent != 0) {
|
||||||
$budgets->push($budget);
|
$budgets->push($budget);
|
||||||
}
|
}
|
||||||
@@ -234,14 +309,14 @@ class BudgetController extends Controller
|
|||||||
|
|
||||||
// each budget, fill the row:
|
// each budget, fill the row:
|
||||||
foreach ($budgets as $budget) {
|
foreach ($budgets as $budget) {
|
||||||
$spent = $repository->balanceInPeriod($budget, $start, $month, $shared);
|
$spent = $repository->balanceInPeriod($budget, $start, $month, $accounts);
|
||||||
$row[] = $spent * -1;
|
$row[] = $spent * -1;
|
||||||
}
|
}
|
||||||
$entries->push($row);
|
$entries->push($row);
|
||||||
$start->endOfMonth()->addDay();
|
$start->endOfMonth()->addDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->year($allBudgets, $entries);
|
$data = $this->generator->year($budgets, $entries);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ class CategoryController extends Controller
|
|||||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$array = $repository->getCategoriesAndExpensesCorrected($start, $end);
|
$array = $repository->getCategoriesAndExpenses($start, $end);
|
||||||
// sort by callback:
|
// sort by callback:
|
||||||
uasort(
|
uasort(
|
||||||
$array,
|
$array,
|
||||||
@@ -121,6 +121,84 @@ class CategoryController extends Controller
|
|||||||
);
|
);
|
||||||
$set = new Collection($array);
|
$set = new Collection($array);
|
||||||
$data = $this->generator->frontpage($set);
|
$data = $this->generator->frontpage($set);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
|
|
||||||
|
return Response::json($data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param CategoryRepositoryInterface $repository
|
||||||
|
* @param $report_type
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $categories
|
||||||
|
*/
|
||||||
|
public function multiYear(CategoryRepositoryInterface $repository, $report_type, Carbon $start, Carbon $end, Collection $accounts, Collection $categories)
|
||||||
|
{
|
||||||
|
// chart properties for cache:
|
||||||
|
$cache = new CacheProperties();
|
||||||
|
$cache->addProperty($report_type);
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($categories);
|
||||||
|
$cache->addProperty('multiYearCategory');
|
||||||
|
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* category
|
||||||
|
* year:
|
||||||
|
* spent: x
|
||||||
|
* earned: x
|
||||||
|
* year
|
||||||
|
* spent: x
|
||||||
|
* earned: x
|
||||||
|
*/
|
||||||
|
$entries = new Collection;
|
||||||
|
// go by budget, not by year.
|
||||||
|
/** @var Category $category */
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
$entry = ['name' => '', 'spent' => [], 'earned' => []];
|
||||||
|
|
||||||
|
$currentStart = clone $start;
|
||||||
|
while ($currentStart < $end) {
|
||||||
|
// fix the date:
|
||||||
|
$currentEnd = clone $currentStart;
|
||||||
|
$currentEnd->endOfYear();
|
||||||
|
|
||||||
|
// get data:
|
||||||
|
if (is_null($category->id)) {
|
||||||
|
$name = trans('firefly.noCategory');
|
||||||
|
$spent = $repository->spentNoCategoryForAccounts($accounts, $currentStart, $currentEnd);
|
||||||
|
$earned = $repository->earnedNoCategoryForAccounts($accounts, $currentStart, $currentEnd);
|
||||||
|
} else {
|
||||||
|
$name = $category->name;
|
||||||
|
$spent = $repository->spentInPeriodForAccounts($category, $accounts, $currentStart, $currentEnd);
|
||||||
|
$earned = $repository->earnedInPeriodForAccounts($category, $accounts, $currentStart, $currentEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save to array:
|
||||||
|
$year = $currentStart->year;
|
||||||
|
$entry['name'] = $name;
|
||||||
|
$entry['spent'][$year] = ($spent * -1);
|
||||||
|
$entry['earned'][$year] = $earned;
|
||||||
|
|
||||||
|
// jump to next year.
|
||||||
|
$currentStart = clone $currentEnd;
|
||||||
|
$currentStart->addDay();
|
||||||
|
}
|
||||||
|
$entries->push($entry);
|
||||||
|
}
|
||||||
|
// generate chart with data:
|
||||||
|
$data = $this->generator->multiYear($entries);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|
||||||
@@ -151,8 +229,8 @@ class CategoryController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
while ($start <= $end) {
|
while ($start <= $end) {
|
||||||
$spent = $repository->spentOnDaySumCorrected($category, $start);
|
$spent = $repository->spentOnDaySum($category, $start);
|
||||||
$earned = $repository->earnedOnDaySumCorrected($category, $start);
|
$earned = $repository->earnedOnDaySum($category, $start);
|
||||||
$date = Navigation::periodShow($start, '1D');
|
$date = Navigation::periodShow($start, '1D');
|
||||||
$entries->push([clone $start, $date, $spent, $earned]);
|
$entries->push([clone $start, $date, $spent, $earned]);
|
||||||
$start->addDay();
|
$start->addDay();
|
||||||
@@ -194,8 +272,8 @@ class CategoryController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
while ($start <= $end) {
|
while ($start <= $end) {
|
||||||
$spent = $repository->spentOnDaySumCorrected($category, $start);
|
$spent = $repository->spentOnDaySum($category, $start);
|
||||||
$earned = $repository->earnedOnDaySumCorrected($category, $start);
|
$earned = $repository->earnedOnDaySum($category, $start);
|
||||||
$theDate = Navigation::periodShow($start, '1D');
|
$theDate = Navigation::periodShow($start, '1D');
|
||||||
$entries->push([clone $start, $theDate, $spent, $earned]);
|
$entries->push([clone $start, $theDate, $spent, $earned]);
|
||||||
$start->addDay();
|
$start->addDay();
|
||||||
@@ -213,31 +291,32 @@ class CategoryController extends Controller
|
|||||||
* This chart will only show expenses.
|
* This chart will only show expenses.
|
||||||
*
|
*
|
||||||
* @param CategoryRepositoryInterface $repository
|
* @param CategoryRepositoryInterface $repository
|
||||||
* @param $year
|
* @param $report_type
|
||||||
* @param bool $shared
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function spentInYear(CategoryRepositoryInterface $repository, $year, $shared = false)
|
public function spentInYear(CategoryRepositoryInterface $repository, $report_type, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
$start = new Carbon($year . '-01-01');
|
|
||||||
$end = new Carbon($year . '-12-31');
|
|
||||||
|
|
||||||
$cache = new CacheProperties; // chart properties for cache:
|
$cache = new CacheProperties; // chart properties for cache:
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($report_type);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($accounts);
|
||||||
$cache->addProperty('category');
|
$cache->addProperty('category');
|
||||||
$cache->addProperty('spent-in-year');
|
$cache->addProperty('spent-in-year');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$shared = $shared == 'shared' ? true : false;
|
|
||||||
$allCategories = $repository->getCategories();
|
$allCategories = $repository->getCategories();
|
||||||
$entries = new Collection;
|
$entries = new Collection;
|
||||||
$categories = $allCategories->filter(
|
$categories = $allCategories->filter(
|
||||||
function (Category $category) use ($repository, $start, $end, $shared) {
|
function (Category $category) use ($repository, $start, $end, $accounts) {
|
||||||
$spent = $repository->balanceInPeriod($category, $start, $end, $shared);
|
$spent = $repository->balanceInPeriod($category, $start, $end, $accounts);
|
||||||
if ($spent < 0) {
|
if ($spent < 0) {
|
||||||
return $category;
|
return $category;
|
||||||
}
|
}
|
||||||
@@ -252,7 +331,7 @@ class CategoryController extends Controller
|
|||||||
$row = [clone $start]; // make a row:
|
$row = [clone $start]; // make a row:
|
||||||
|
|
||||||
foreach ($categories as $category) { // each budget, fill the row
|
foreach ($categories as $category) { // each budget, fill the row
|
||||||
$spent = $repository->balanceInPeriod($category, $start, $month, $shared);
|
$spent = $repository->balanceInPeriod($category, $start, $month, $accounts);
|
||||||
if ($spent < 0) {
|
if ($spent < 0) {
|
||||||
$row[] = $spent * -1;
|
$row[] = $spent * -1;
|
||||||
} else {
|
} else {
|
||||||
@@ -269,61 +348,194 @@ class CategoryController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This chart will only show income.
|
* Returns a chart of what has been earned in this period in each category
|
||||||
|
* grouped by month.
|
||||||
*
|
*
|
||||||
* @param CategoryRepositoryInterface $repository
|
* @param CategoryRepositoryInterface $repository
|
||||||
* @param $year
|
* @param $report_type
|
||||||
* @param bool $shared
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function earnedInYear(CategoryRepositoryInterface $repository, $year, $shared = false)
|
public function earnedInPeriod(CategoryRepositoryInterface $repository, $report_type, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
$start = new Carbon($year . '-01-01');
|
$original = clone $start;
|
||||||
$end = new Carbon($year . '-12-31');
|
$cache = new CacheProperties; // chart properties for cache:
|
||||||
|
|
||||||
$cache = new CacheProperties; // chart properties for cache:
|
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($report_type);
|
||||||
|
$cache->addProperty($accounts);
|
||||||
$cache->addProperty('category');
|
$cache->addProperty('category');
|
||||||
$cache->addProperty('earned-in-year');
|
$cache->addProperty('earned-in-period');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
$categories = new Collection;
|
||||||
|
$sets = new Collection;
|
||||||
|
$entries = new Collection;
|
||||||
|
|
||||||
$shared = $shared == 'shared' ? true : false;
|
// run a very special query each month:
|
||||||
$allCategories = $repository->getCategories();
|
$start = clone $original;
|
||||||
$allEntries = new Collection;
|
while ($start < $end) {
|
||||||
$categories = $allCategories->filter(
|
$currentEnd = clone $start;
|
||||||
function (Category $category) use ($repository, $start, $end, $shared) {
|
$currentStart = clone $start;
|
||||||
$spent = $repository->balanceInPeriod($category, $start, $end, $shared);
|
$currentStart->startOfMonth();
|
||||||
if ($spent > 0) {
|
$currentEnd->endOfMonth();
|
||||||
return $category;
|
// get a list of categories, and what the user has earned for that category
|
||||||
}
|
// (if the user has earned anything)
|
||||||
|
$set = $repository->earnedForAccounts($accounts, $currentStart, $currentEnd);
|
||||||
return null;
|
$categories = $categories->merge($set);
|
||||||
|
// save the set combined with the data that is in it:
|
||||||
|
// for example:
|
||||||
|
// [december 2015, salary:1000, bonus:200]
|
||||||
|
$sets->push([$currentStart, $set]);
|
||||||
|
$start->addMonth();
|
||||||
|
}
|
||||||
|
// filter categories into a single bunch. Useful later on.
|
||||||
|
// $categories contains all the categories the user has earned money
|
||||||
|
// in in this period.
|
||||||
|
$categories = $categories->unique('id');
|
||||||
|
$categories = $categories->sortBy(
|
||||||
|
function (Category $category) {
|
||||||
|
return $category->name;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// start looping the time again, this time processing the
|
||||||
|
// data for each month.
|
||||||
|
$start = clone $original;
|
||||||
while ($start < $end) {
|
while ($start < $end) {
|
||||||
$month = clone $start; // month is the current end of the period
|
$currentEnd = clone $start;
|
||||||
$month->endOfMonth();
|
$currentStart = clone $start;
|
||||||
$row = [clone $start]; // make a row:
|
$currentStart->startOfMonth();
|
||||||
|
$currentEnd->endOfMonth();
|
||||||
|
|
||||||
foreach ($categories as $category) { // each budget, fill the row
|
// in $sets we have saved all the sets of data for each month
|
||||||
$spent = $repository->balanceInPeriod($category, $start, $month, $shared);
|
// so now we need to retrieve the corrent one.
|
||||||
if ($spent > 0) {
|
// match is on date of course.
|
||||||
$row[] = $spent;
|
$currentSet = $sets->first(
|
||||||
|
function ($key, $value) use ($currentStart) {
|
||||||
|
// set for this date.
|
||||||
|
return ($value[0] == $currentStart);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// create a row used later on.
|
||||||
|
$row = [clone $currentStart];
|
||||||
|
|
||||||
|
// loop all categories:
|
||||||
|
/** @var Category $category */
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
// if entry is not null, we've earned money in this period for this category.
|
||||||
|
$entry = $currentSet[1]->first(
|
||||||
|
function ($key, $value) use ($category) {
|
||||||
|
return $value->id == $category->id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// save amount
|
||||||
|
if (!is_null($entry)) {
|
||||||
|
$row[] = $entry->earned;
|
||||||
} else {
|
} else {
|
||||||
$row[] = 0;
|
$row[] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$allEntries->push($row);
|
$entries->push($row);
|
||||||
$start->addMonth();
|
$start->addMonth();
|
||||||
}
|
}
|
||||||
$data = $this->generator->earnedInYear($categories, $allEntries);
|
|
||||||
|
$data = $this->generator->earnedInPeriod($categories, $entries);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return $data;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a chart of what has been spent in this period in each category
|
||||||
|
* grouped by month.
|
||||||
|
*
|
||||||
|
* @param CategoryRepositoryInterface $repository
|
||||||
|
* @param $report_type
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function spentInPeriod(CategoryRepositoryInterface $repository, $report_type, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
|
{
|
||||||
|
$original = clone $start;
|
||||||
|
$cache = new CacheProperties; // chart properties for cache:
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($report_type);
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty('category');
|
||||||
|
$cache->addProperty('spent-in-period');
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
$categories = new Collection;
|
||||||
|
$sets = new Collection;
|
||||||
|
$entries = new Collection;
|
||||||
|
|
||||||
|
// run a very special query each month:
|
||||||
|
$start = clone $original;
|
||||||
|
while ($start < $end) {
|
||||||
|
$currentEnd = clone $start;
|
||||||
|
$currentStart = clone $start;
|
||||||
|
$currentStart->startOfMonth();
|
||||||
|
$currentEnd->endOfMonth();
|
||||||
|
$set = $repository->spentForAccounts($accounts, $currentStart, $currentEnd);
|
||||||
|
$categories = $categories->merge($set);
|
||||||
|
$sets->push([$currentStart, $set]);
|
||||||
|
$start->addMonth();
|
||||||
|
}
|
||||||
|
$categories = $categories->unique('id');
|
||||||
|
$categories = $categories->sortBy(
|
||||||
|
function (Category $category) {
|
||||||
|
return $category->name;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$start = clone $original;
|
||||||
|
while ($start < $end) {
|
||||||
|
$currentEnd = clone $start;
|
||||||
|
$currentStart = clone $start;
|
||||||
|
$currentStart->startOfMonth();
|
||||||
|
$currentEnd->endOfMonth();
|
||||||
|
$currentSet = $sets->first(
|
||||||
|
function ($key, $value) use ($currentStart) {
|
||||||
|
// set for this date.
|
||||||
|
return ($value[0] == $currentStart);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$row = [clone $currentStart];
|
||||||
|
|
||||||
|
/** @var Category $category */
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
/** @var Category $entry */
|
||||||
|
$entry = $currentSet[1]->first(
|
||||||
|
function ($key, $value) use ($category) {
|
||||||
|
return $value->id == $category->id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!is_null($entry)) {
|
||||||
|
$row[] = $entry->spent;
|
||||||
|
} else {
|
||||||
|
$row[] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$entries->push($row);
|
||||||
|
$start->addMonth();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->spentInPeriod($categories, $entries);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ use FireflyIII\Http\Controllers\Controller;
|
|||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Response;
|
use Response;
|
||||||
use Log;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ReportController
|
* Class ReportController
|
||||||
@@ -37,41 +36,66 @@ class ReportController extends Controller
|
|||||||
* Summarizes all income and expenses, per month, for a given year.
|
* Summarizes all income and expenses, per month, for a given year.
|
||||||
*
|
*
|
||||||
* @param ReportQueryInterface $query
|
* @param ReportQueryInterface $query
|
||||||
* @param $year
|
* @param $report_type
|
||||||
* @param bool $shared
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function yearInOut(ReportQueryInterface $query, $year, $shared = false)
|
public function yearInOut(ReportQueryInterface $query, $report_type, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
// get start and end of year
|
|
||||||
$start = new Carbon($year . '-01-01');
|
|
||||||
$end = new Carbon($year . '-12-31');
|
|
||||||
$shared = $shared == 'shared' ? true : false;
|
|
||||||
|
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty('yearInOut');
|
$cache->addProperty('yearInOut');
|
||||||
$cache->addProperty($year);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($shared);
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($end);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$entries = new Collection;
|
|
||||||
while ($start < $end) {
|
|
||||||
$month = clone $start;
|
|
||||||
$month->endOfMonth();
|
|
||||||
// total income and total expenses:
|
|
||||||
$incomeSum = $query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
|
|
||||||
$expenseSum = $query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
|
|
||||||
|
|
||||||
$entries->push([clone $start, $incomeSum, $expenseSum]);
|
// per year?
|
||||||
$start->addMonth();
|
if ($start->diffInMonths($end) > 12) {
|
||||||
|
|
||||||
|
$entries = new Collection;
|
||||||
|
while ($start < $end) {
|
||||||
|
$startOfYear = clone $start;
|
||||||
|
$startOfYear->startOfYear();
|
||||||
|
$endOfYear = clone $startOfYear;
|
||||||
|
$endOfYear->endOfYear();
|
||||||
|
|
||||||
|
// total income and total expenses:
|
||||||
|
$incomeSum = $query->incomeInPeriod($startOfYear, $endOfYear, $accounts)->sum('amount_positive');
|
||||||
|
$expenseSum = $query->expenseInPeriod($startOfYear, $endOfYear, $accounts)->sum('amount_positive');
|
||||||
|
|
||||||
|
$entries->push([clone $start, $incomeSum, $expenseSum]);
|
||||||
|
$start->addYear();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->multiYearInOut($entries);
|
||||||
|
$cache->store($data);
|
||||||
|
} else {
|
||||||
|
// per month:
|
||||||
|
|
||||||
|
$entries = new Collection;
|
||||||
|
while ($start < $end) {
|
||||||
|
$month = clone $start;
|
||||||
|
$month->endOfMonth();
|
||||||
|
// total income and total expenses:
|
||||||
|
$incomeSum = $query->incomeInPeriod($start, $month, $accounts)->sum('amount_positive');
|
||||||
|
$expenseSum = $query->expenseInPeriod($start, $month, $accounts)->sum('amount_positive');
|
||||||
|
|
||||||
|
|
||||||
|
$entries->push([clone $start, $incomeSum, $expenseSum]);
|
||||||
|
$start->addMonth();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->yearInOut($entries);
|
||||||
|
$cache->store($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->yearInOut($entries);
|
|
||||||
$cache->store($data);
|
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|
||||||
@@ -81,54 +105,71 @@ class ReportController extends Controller
|
|||||||
* Summarizes all income and expenses for a given year. Gives a total and an average.
|
* Summarizes all income and expenses for a given year. Gives a total and an average.
|
||||||
*
|
*
|
||||||
* @param ReportQueryInterface $query
|
* @param ReportQueryInterface $query
|
||||||
* @param $year
|
* @param $report_type
|
||||||
* @param bool $shared
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function yearInOutSummarized(ReportQueryInterface $query, $year, $shared = false)
|
public function yearInOutSummarized(ReportQueryInterface $query, $report_type, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
|
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty('yearInOutSummarized');
|
$cache->addProperty('yearInOutSummarized');
|
||||||
$cache->addProperty($year);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($shared);
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($accounts);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$start = new Carbon($year . '-01-01');
|
|
||||||
$end = new Carbon($year . '-12-31');
|
|
||||||
$shared = $shared == 'shared' ? true : false;
|
|
||||||
$income = '0';
|
$income = '0';
|
||||||
$expense = '0';
|
$expense = '0';
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
|
|
||||||
while ($start < $end) {
|
if ($start->diffInMonths($end) > 12) {
|
||||||
$month = clone $start;
|
// per year
|
||||||
$month->endOfMonth();
|
while ($start < $end) {
|
||||||
// total income and total expenses:
|
$startOfYear = clone $start;
|
||||||
$currentIncome = $query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
|
$startOfYear->startOfYear();
|
||||||
$currentExpense = $query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
|
$endOfYear = clone $startOfYear;
|
||||||
|
$endOfYear->endOfYear();
|
||||||
Log::debug('Date ['.$month->format('M Y').']: income = ['.$income.' + '.$currentIncome.'], out = ['.$expense.' + '.$currentExpense.']');
|
|
||||||
|
// total income and total expenses:
|
||||||
$income = bcadd($income, $currentIncome);
|
$currentIncome = $query->incomeInPeriod($startOfYear, $endOfYear, $accounts)->sum('amount_positive');
|
||||||
$expense = bcadd($expense, $currentExpense);
|
$currentExpense = $query->expenseInPeriod($startOfYear, $endOfYear, $accounts)->sum('amount_positive');
|
||||||
|
$income = bcadd($income, $currentIncome);
|
||||||
|
$expense = bcadd($expense, $currentExpense);
|
||||||
|
|
||||||
|
$count++;
|
||||||
|
$start->addYear();
|
||||||
$count++;
|
}
|
||||||
$start->addMonth();
|
|
||||||
|
$data = $this->generator->multiYearInOutSummarized($income, $expense, $count);
|
||||||
|
$cache->store($data);
|
||||||
|
} else {
|
||||||
|
// per month!
|
||||||
|
while ($start < $end) {
|
||||||
|
$month = clone $start;
|
||||||
|
$month->endOfMonth();
|
||||||
|
// total income and total expenses:
|
||||||
|
$currentIncome = $query->incomeInPeriod($start, $month, $accounts)->sum('amount_positive');
|
||||||
|
$currentExpense = $query->expenseInPeriod($start, $month, $accounts)->sum('amount_positive');
|
||||||
|
$income = bcadd($income, $currentIncome);
|
||||||
|
$expense = bcadd($expense, $currentExpense);
|
||||||
|
|
||||||
|
$count++;
|
||||||
|
$start->addMonth();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->yearInOutSummarized($income, $expense, $count);
|
||||||
|
$cache->store($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->yearInOutSummarized($income, $expense, $count);
|
|
||||||
$cache->store($data);
|
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|
||||||
|
|||||||
@@ -34,14 +34,15 @@ abstract class Controller extends BaseController
|
|||||||
View::share('hideTags', false);
|
View::share('hideTags', false);
|
||||||
|
|
||||||
if (Auth::check()) {
|
if (Auth::check()) {
|
||||||
$pref = Preferences::get('language', 'en');
|
$pref = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US'));
|
||||||
$lang = $pref->data;
|
$lang = $pref->data;
|
||||||
$this->monthFormat = Config::get('firefly.month.' . $lang);
|
$this->monthFormat = trans('config.month');
|
||||||
$this->monthAndDayFormat = Config::get('firefly.monthAndDay.' . $lang);
|
$this->monthAndDayFormat = trans('config.month_and_day');
|
||||||
|
|
||||||
View::share('monthFormat', $this->monthFormat);
|
View::share('monthFormat', $this->monthFormat);
|
||||||
View::share('monthAndDayFormat', $this->monthAndDayFormat);
|
View::share('monthAndDayFormat', $this->monthAndDayFormat);
|
||||||
View::share('language', $lang);
|
View::share('language', $lang);
|
||||||
|
View::share('localeconv', localeconv());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ class CurrencyController extends Controller
|
|||||||
public function index(CurrencyRepositoryInterface $repository)
|
public function index(CurrencyRepositoryInterface $repository)
|
||||||
{
|
{
|
||||||
$currencies = $repository->get();
|
$currencies = $repository->get();
|
||||||
$defaultCurrency = $repository->getCurrencyByPreference(Preferences::get('currencyPreference', 'EUR'));
|
$defaultCurrency = $repository->getCurrencyByPreference(Preferences::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR')));
|
||||||
|
|
||||||
|
|
||||||
if (!Auth::user()->hasRole('owner')) {
|
if (!Auth::user()->hasRole('owner')) {
|
||||||
|
|||||||
@@ -120,33 +120,4 @@ class HomeController extends Controller
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
* @return \Illuminate\Http\RedirectResponse|string
|
|
||||||
*/
|
|
||||||
public function routes()
|
|
||||||
{
|
|
||||||
if (!Auth::user()->hasRole('owner')) {
|
|
||||||
Session::flash('warning', 'This page is broken.');
|
|
||||||
|
|
||||||
return redirect(route('index'));
|
|
||||||
}
|
|
||||||
Log::debug('Make log.');
|
|
||||||
|
|
||||||
// get all routes:
|
|
||||||
$routeCollection = Route::getRoutes();
|
|
||||||
/** @var \Illuminate\Routing\Route $value */
|
|
||||||
foreach ($routeCollection as $value) {
|
|
||||||
$name = $value->getName();
|
|
||||||
$methods = $value->getMethods();
|
|
||||||
$isPost = in_array('POST', $methods);
|
|
||||||
$index = str_replace('.', '-', $name);
|
|
||||||
|
|
||||||
if (strlen($name) > 0 && !$isPost) {
|
|
||||||
echo "'" . $index . "' => '" . $name . "',<br />";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ' ';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ use Illuminate\Support\Collection;
|
|||||||
use Preferences;
|
use Preferences;
|
||||||
use Response;
|
use Response;
|
||||||
use Session;
|
use Session;
|
||||||
use Steam;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class JsonController
|
* Class JsonController
|
||||||
@@ -72,9 +71,8 @@ class JsonController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function boxBillsPaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
public function boxBillsPaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||||
{
|
{
|
||||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||||
$amount = 0;
|
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
|
|
||||||
// works for json too!
|
// works for json too!
|
||||||
@@ -85,21 +83,14 @@ class JsonController extends Controller
|
|||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
$bills = $repository->getActiveBills(); // these two functions are the same as the chart
|
// get amount from bills
|
||||||
|
$amount = $repository->billsPaidInRange($start, $end)->sum('paid');
|
||||||
|
|
||||||
/** @var Bill $bill */
|
// add credit card bill.
|
||||||
foreach ($bills as $bill) {
|
$creditCards = $accountRepository->getCreditCards($end); // Find credit card accounts and possibly unpaid credit card bills.
|
||||||
$amount = bcadd($amount, $repository->billPaymentsInRange($bill, $start, $end));
|
|
||||||
}
|
|
||||||
unset($bill, $bills);
|
|
||||||
|
|
||||||
$amount = $amount * -1; // make the amount positive again.
|
|
||||||
|
|
||||||
$creditCards = $accountRepository->getCreditCards(); // Find credit card accounts and possibly unpaid credit card bills.
|
|
||||||
/** @var Account $creditCard */
|
/** @var Account $creditCard */
|
||||||
foreach ($creditCards as $creditCard) {
|
foreach ($creditCards as $creditCard) {
|
||||||
$balance = Steam::balance($creditCard, $end, true); // if the balance is not zero, the monthly payment is still underway.
|
if ($creditCard->balance == 0) {
|
||||||
if ($balance == 0) {
|
|
||||||
// find a transfer TO the credit card which should account for
|
// find a transfer TO the credit card which should account for
|
||||||
// anything paid. If not, the CC is not yet used.
|
// anything paid. If not, the CC is not yet used.
|
||||||
$amount = bcadd($amount, $accountRepository->getTransfersInRange($creditCard, $start, $end)->sum('amount'));
|
$amount = bcadd($amount, $accountRepository->getTransfersInRange($creditCard, $start, $end)->sum('amount'));
|
||||||
@@ -149,14 +140,15 @@ class JsonController extends Controller
|
|||||||
}
|
}
|
||||||
unset($bill, $bills, $range, $ranges);
|
unset($bill, $bills, $range, $ranges);
|
||||||
|
|
||||||
$creditCards = $accountRepository->getCreditCards();
|
$creditCards = $accountRepository->getCreditCards($end);
|
||||||
|
|
||||||
|
/** @var Account $creditCard */
|
||||||
foreach ($creditCards as $creditCard) {
|
foreach ($creditCards as $creditCard) {
|
||||||
$balance = Steam::balance($creditCard, $end, true);
|
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
if ($creditCard->balance < 0) {
|
||||||
if ($balance < 0) {
|
|
||||||
// unpaid! create a fake bill that matches the amount.
|
// unpaid! create a fake bill that matches the amount.
|
||||||
$description = $creditCard->name;
|
$description = $creditCard->name;
|
||||||
$fakeAmount = $balance * -1;
|
$fakeAmount = $creditCard->balance * -1;
|
||||||
$fakeBill = $repository->createFakeBill($description, $date, $fakeAmount);
|
$fakeBill = $repository->createFakeBill($description, $date, $fakeAmount);
|
||||||
$unpaid->push([$fakeBill, $date]);
|
$unpaid->push([$fakeBill, $date]);
|
||||||
}
|
}
|
||||||
@@ -178,7 +170,7 @@ class JsonController extends Controller
|
|||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
*/
|
*/
|
||||||
public function boxIn(ReportQueryInterface $reportQuery)
|
public function boxIn(ReportQueryInterface $reportQuery, AccountRepositoryInterface $accountRepository)
|
||||||
{
|
{
|
||||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||||
@@ -191,8 +183,8 @@ class JsonController extends Controller
|
|||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
|
||||||
$amount = $reportQuery->incomeInPeriodCorrected($start, $end, true)->sum('amount');
|
$amount = $reportQuery->incomeInPeriod($start, $end, $accounts)->sum('to_amount');
|
||||||
|
|
||||||
$data = ['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
|
$data = ['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
@@ -205,11 +197,12 @@ class JsonController extends Controller
|
|||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
*/
|
*/
|
||||||
public function boxOut(ReportQueryInterface $reportQuery)
|
public function boxOut(ReportQueryInterface $reportQuery, AccountRepositoryInterface $accountRepository)
|
||||||
{
|
{
|
||||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||||
|
|
||||||
|
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
|
||||||
|
|
||||||
// works for json too!
|
// works for json too!
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
@@ -220,8 +213,7 @@ class JsonController extends Controller
|
|||||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$amount = $reportQuery->expenseInPeriodCorrected($start, $end, true)->sum('amount');
|
$amount = $reportQuery->expenseInPeriod($start, $end, $accounts)->sum('to_amount');
|
||||||
$amount = $amount * -1;
|
|
||||||
|
|
||||||
$data = ['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
|
$data = ['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
@@ -243,7 +235,6 @@ class JsonController extends Controller
|
|||||||
foreach ($list as $entry) {
|
foreach ($list as $entry) {
|
||||||
$return[] = $entry->name;
|
$return[] = $entry->name;
|
||||||
}
|
}
|
||||||
sort($return);
|
|
||||||
|
|
||||||
return Response::json($return);
|
return Response::json($return);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ class NewUserController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function submit(NewUserFormRequest $request, AccountRepositoryInterface $repository)
|
public function submit(NewUserFormRequest $request, AccountRepositoryInterface $repository)
|
||||||
{
|
{
|
||||||
|
|
||||||
// create normal asset account:
|
// create normal asset account:
|
||||||
$assetAccount = [
|
$assetAccount = [
|
||||||
'name' => $request->get('bank_name'),
|
'name' => $request->get('bank_name'),
|
||||||
@@ -61,7 +60,7 @@ class NewUserController extends Controller
|
|||||||
'accountRole' => 'defaultAsset',
|
'accountRole' => 'defaultAsset',
|
||||||
'openingBalance' => round($request->input('bank_balance'), 2),
|
'openingBalance' => round($request->input('bank_balance'), 2),
|
||||||
'openingBalanceDate' => new Carbon,
|
'openingBalanceDate' => new Carbon,
|
||||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
'openingBalanceCurrency' => intval($request->input('amount_currency_id_bank_balance')),
|
||||||
];
|
];
|
||||||
|
|
||||||
$repository->store($assetAccount);
|
$repository->store($assetAccount);
|
||||||
@@ -78,7 +77,7 @@ class NewUserController extends Controller
|
|||||||
'accountRole' => 'savingAsset',
|
'accountRole' => 'savingAsset',
|
||||||
'openingBalance' => round($request->input('savings_balance'), 2),
|
'openingBalance' => round($request->input('savings_balance'), 2),
|
||||||
'openingBalanceDate' => new Carbon,
|
'openingBalanceDate' => new Carbon,
|
||||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
'openingBalanceCurrency' => intval($request->input('amount_currency_id_savings_balance')),
|
||||||
];
|
];
|
||||||
$repository->store($savingsAccount);
|
$repository->store($savingsAccount);
|
||||||
}
|
}
|
||||||
@@ -96,7 +95,7 @@ class NewUserController extends Controller
|
|||||||
'accountRole' => 'ccAsset',
|
'accountRole' => 'ccAsset',
|
||||||
'openingBalance' => null,
|
'openingBalance' => null,
|
||||||
'openingBalanceDate' => null,
|
'openingBalanceDate' => null,
|
||||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
'openingBalanceCurrency' => intval($request->input('amount_currency_id_credit_card_limit')),
|
||||||
];
|
];
|
||||||
$creditCard = $repository->store($creditAccount);
|
$creditCard = $repository->store($creditAccount);
|
||||||
|
|
||||||
|
|||||||
@@ -37,10 +37,12 @@ class PreferencesController extends Controller
|
|||||||
$viewRange = $viewRangePref->data;
|
$viewRange = $viewRangePref->data;
|
||||||
$frontPageAccounts = Preferences::get('frontPageAccounts', []);
|
$frontPageAccounts = Preferences::get('frontPageAccounts', []);
|
||||||
$budgetMax = Preferences::get('budgetMaximum', 1000);
|
$budgetMax = Preferences::get('budgetMaximum', 1000);
|
||||||
$language = Preferences::get('language', 'en')->data;
|
$language = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US'))->data;
|
||||||
$budgetMaximum = $budgetMax->data;
|
$budgetMaximum = $budgetMax->data;
|
||||||
|
|
||||||
return view('preferences.index', compact('budgetMaximum', 'language', 'accounts', 'frontPageAccounts', 'viewRange'));
|
$showIncomplete = env('SHOW_INCOMPLETE_TRANSLATIONS', 'false') == 'true';
|
||||||
|
|
||||||
|
return view('preferences.index', compact('budgetMaximum', 'language', 'accounts', 'frontPageAccounts', 'viewRange', 'showIncomplete'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,7 +72,7 @@ class PreferencesController extends Controller
|
|||||||
|
|
||||||
// language:
|
// language:
|
||||||
$lang = Input::get('language');
|
$lang = Input::get('language');
|
||||||
if (in_array($lang, array_keys(Config::get('firefly.lang')))) {
|
if (in_array($lang, array_keys(Config::get('firefly.languages')))) {
|
||||||
Preferences::set('language', $lang);
|
Preferences::set('language', $lang);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class ProfileController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update the user with the new password.
|
// update the user with the new password.
|
||||||
Auth::user()->password = $request->get('new_password');
|
Auth::user()->password = bcrypt($request->get('new_password'));
|
||||||
Auth::user()->save();
|
Auth::user()->save();
|
||||||
|
|
||||||
Session::flash('success', trans('firefly.password_changed'));
|
Session::flash('success', trans('firefly.password_changed'));
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use Carbon\Carbon;
|
|||||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Session;
|
use Session;
|
||||||
use View;
|
use View;
|
||||||
|
|
||||||
@@ -41,111 +42,190 @@ class ReportController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index(AccountRepositoryInterface $repository)
|
public function index(AccountRepositoryInterface $repository)
|
||||||
{
|
{
|
||||||
$start = Session::get('first');
|
$start = Session::get('first');
|
||||||
$months = $this->helper->listOfMonths($start);
|
$months = $this->helper->listOfMonths($start);
|
||||||
|
$startOfMonth = clone Session::get('start');
|
||||||
|
$endOfMonth = clone Session::get('start');
|
||||||
|
$startOfYear = clone Session::get('start');
|
||||||
|
$endOfYear = clone Session::get('start');
|
||||||
|
$startOfMonth->startOfMonth();
|
||||||
|
$endOfMonth->endOfMonth();
|
||||||
|
$startOfYear->startOfYear();
|
||||||
|
$endOfYear->endOfYear();
|
||||||
|
|
||||||
// does the user have shared accounts?
|
// does the user have shared accounts?
|
||||||
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
|
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
|
||||||
$hasShared = false;
|
// get id's for quick links:
|
||||||
|
$accountIds = [];
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
if ($account->getMeta('accountRole') == 'sharedAsset') {
|
$accountIds [] = $account->id;
|
||||||
$hasShared = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
$accountList = join(',', $accountIds);
|
||||||
|
|
||||||
|
|
||||||
return view('reports.index', compact('months', 'hasShared'));
|
return view('reports.index', compact('months', 'accounts', 'start', 'accountList',
|
||||||
|
'startOfMonth', 'endOfMonth', 'startOfYear', 'endOfYear'
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $year
|
* @param $report_type
|
||||||
* @param string $month
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @param bool $shared
|
* @return View
|
||||||
*
|
|
||||||
* @return \Illuminate\View\View
|
|
||||||
*/
|
*/
|
||||||
public function month($year = '2014', $month = '1', $shared = false)
|
public function defaultYear($report_type, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
$start = new Carbon($year . '-' . $month . '-01');
|
|
||||||
$subTitle = trans('firefly.reportForMonth', ['month' => $start->formatLocalized($this->monthFormat)]);
|
|
||||||
$subTitleIcon = 'fa-calendar';
|
|
||||||
$end = clone $start;
|
|
||||||
$incomeTopLength = 8;
|
|
||||||
$expenseTopLength = 8;
|
|
||||||
if ($shared == 'shared') {
|
|
||||||
$shared = true;
|
|
||||||
$subTitle = trans('firefly.reportForMonthShared', ['month' => $start->formatLocalized($this->monthFormat)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$end->endOfMonth();
|
|
||||||
|
|
||||||
$accounts = $this->helper->getAccountReport($start, $end, $shared);
|
|
||||||
$incomes = $this->helper->getIncomeReport($start, $end, $shared);
|
|
||||||
$expenses = $this->helper->getExpenseReport($start, $end, $shared);
|
|
||||||
$budgets = $this->helper->getBudgetReport($start, $end, $shared);
|
|
||||||
$categories = $this->helper->getCategoryReport($start, $end, $shared);
|
|
||||||
$balance = $this->helper->getBalanceReport($start, $end, $shared);
|
|
||||||
$bills = $this->helper->getBillReport($start, $end);
|
|
||||||
|
|
||||||
Session::flash('gaEventCategory', 'report');
|
|
||||||
Session::flash('gaEventAction', 'month');
|
|
||||||
Session::flash('gaEventLabel', $start->format('F Y'));
|
|
||||||
|
|
||||||
|
|
||||||
return view(
|
|
||||||
'reports.month',
|
|
||||||
compact(
|
|
||||||
'start', 'shared',
|
|
||||||
'subTitle', 'subTitleIcon',
|
|
||||||
'accounts',
|
|
||||||
'incomes', 'incomeTopLength',
|
|
||||||
'expenses', 'expenseTopLength',
|
|
||||||
'budgets', 'balance',
|
|
||||||
'categories',
|
|
||||||
'bills'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $year
|
|
||||||
*
|
|
||||||
* @param bool $shared
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function year($year, $shared = false)
|
|
||||||
{
|
|
||||||
$start = new Carbon('01-01-' . $year);
|
|
||||||
$end = clone $start;
|
|
||||||
$subTitle = trans('firefly.reportForYear', ['year' => $year]);
|
|
||||||
$subTitleIcon = 'fa-bar-chart';
|
|
||||||
$incomeTopLength = 8;
|
$incomeTopLength = 8;
|
||||||
$expenseTopLength = 8;
|
$expenseTopLength = 8;
|
||||||
|
|
||||||
if ($shared == 'shared') {
|
$accountReport = $this->helper->getAccountReport($start, $end, $accounts);
|
||||||
$shared = true;
|
$incomes = $this->helper->getIncomeReport($start, $end, $accounts);
|
||||||
$subTitle = trans('firefly.reportForYearShared', ['year' => $year]);
|
$expenses = $this->helper->getExpenseReport($start, $end, $accounts);
|
||||||
}
|
|
||||||
$end->endOfYear();
|
|
||||||
|
|
||||||
$accounts = $this->helper->getAccountReport($start, $end, $shared);
|
|
||||||
$incomes = $this->helper->getIncomeReport($start, $end, $shared);
|
|
||||||
$expenses = $this->helper->getExpenseReport($start, $end, $shared);
|
|
||||||
|
|
||||||
Session::flash('gaEventCategory', 'report');
|
Session::flash('gaEventCategory', 'report');
|
||||||
Session::flash('gaEventAction', 'year');
|
Session::flash('gaEventAction', 'year');
|
||||||
Session::flash('gaEventLabel', $start->format('Y'));
|
Session::flash('gaEventLabel', $start->format('Y'));
|
||||||
|
|
||||||
|
// and some id's, joined:
|
||||||
|
$accountIds = [];
|
||||||
|
/** @var Account $account */
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$accountIds[] = $account->id;
|
||||||
|
}
|
||||||
|
$accountIds = join(',', $accountIds);
|
||||||
|
|
||||||
return view(
|
return view(
|
||||||
'reports.year',
|
'reports.default.year',
|
||||||
compact('start', 'shared', 'accounts', 'incomes', 'expenses', 'subTitle', 'subTitleIcon', 'incomeTopLength', 'expenseTopLength')
|
compact(
|
||||||
|
'start', 'accountReport', 'incomes', 'report_type', 'accountIds', 'end',
|
||||||
|
'expenses', 'incomeTopLength', 'expenseTopLength'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $report_type
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return View
|
||||||
|
*/
|
||||||
|
public function defaultMonth($report_type, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
|
{
|
||||||
|
$incomeTopLength = 8;
|
||||||
|
$expenseTopLength = 8;
|
||||||
|
|
||||||
|
// get report stuff!
|
||||||
|
$accountReport = $this->helper->getAccountReport($start, $end, $accounts);
|
||||||
|
$incomes = $this->helper->getIncomeReport($start, $end, $accounts);
|
||||||
|
$expenses = $this->helper->getExpenseReport($start, $end, $accounts);
|
||||||
|
$budgets = $this->helper->getBudgetReport($start, $end, $accounts);
|
||||||
|
$categories = $this->helper->getCategoryReport($start, $end, $accounts);
|
||||||
|
$balance = $this->helper->getBalanceReport($start, $end, $accounts);
|
||||||
|
$bills = $this->helper->getBillReport($start, $end, $accounts);
|
||||||
|
|
||||||
|
// and some id's, joined:
|
||||||
|
$accountIds = [];
|
||||||
|
/** @var Account $account */
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$accountIds[] = $account->id;
|
||||||
|
}
|
||||||
|
$accountIds = join(',', $accountIds);
|
||||||
|
|
||||||
|
// continue!
|
||||||
|
return view(
|
||||||
|
'reports.default.month',
|
||||||
|
compact(
|
||||||
|
'start', 'end', 'report_type',
|
||||||
|
'accountReport',
|
||||||
|
'incomes', 'incomeTopLength',
|
||||||
|
'expenses', 'expenseTopLength',
|
||||||
|
'budgets', 'balance',
|
||||||
|
'categories',
|
||||||
|
'bills',
|
||||||
|
'accountIds', 'report_type'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defaultMultiYear($report_type, $start, $end, $accounts)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// list of users stuff:
|
||||||
|
$budgets = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface')->getActiveBudgets();
|
||||||
|
$categories = app('FireflyIII\Repositories\Category\CategoryRepositoryInterface')->getCategories();
|
||||||
|
|
||||||
|
// and some id's, joined:
|
||||||
|
$accountIds = [];
|
||||||
|
/** @var Account $account */
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$accountIds[] = $account->id;
|
||||||
|
}
|
||||||
|
$accountIds = join(',', $accountIds);
|
||||||
|
|
||||||
|
return view(
|
||||||
|
'reports.default.multi-year', compact('budgets', 'accounts', 'categories', 'start', 'end', 'accountIds', 'report_type')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $report_type
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return View
|
||||||
|
*/
|
||||||
|
public function report($report_type, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
|
{
|
||||||
|
// throw an error if necessary.
|
||||||
|
if ($end < $start) {
|
||||||
|
return view('error')->with('message', 'End date cannot be before start date, silly!');
|
||||||
|
}
|
||||||
|
|
||||||
|
// lower threshold
|
||||||
|
if ($start < Session::get('first')) {
|
||||||
|
$start = Session::get('first');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($report_type) {
|
||||||
|
default:
|
||||||
|
case 'default':
|
||||||
|
|
||||||
|
View::share(
|
||||||
|
'subTitle', trans(
|
||||||
|
'firefly.report_default',
|
||||||
|
[
|
||||||
|
'start' => $start->formatLocalized($this->monthFormat),
|
||||||
|
'end' => $end->formatLocalized($this->monthFormat),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
View::share('subTitleIcon', 'fa-calendar');
|
||||||
|
|
||||||
|
// more than one year date difference means year report.
|
||||||
|
if ($start->diffInMonths($end) > 12) {
|
||||||
|
// return view('error')->with('message', 'No report yet for this time period.');
|
||||||
|
return $this->defaultMultiYear($report_type, $start, $end, $accounts);
|
||||||
|
}
|
||||||
|
// more than two months date difference means year report.
|
||||||
|
if ($start->diffInMonths($end) > 1) {
|
||||||
|
return $this->defaultYear($report_type, $start, $end, $accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->defaultMonth($report_type, $start, $end, $accounts);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use FireflyIII\Http\Requests\JournalFormRequest;
|
|||||||
use FireflyIII\Models\PiggyBank;
|
use FireflyIII\Models\PiggyBank;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||||
use Input;
|
use Input;
|
||||||
@@ -45,8 +46,9 @@ class TransactionController extends Controller
|
|||||||
*
|
*
|
||||||
* @return \Illuminate\View\View
|
* @return \Illuminate\View\View
|
||||||
*/
|
*/
|
||||||
public function create(AccountRepositoryInterface $repository, $what = 'deposit')
|
public function create(AccountRepositoryInterface $repository, $what = TransactionType::DEPOSIT)
|
||||||
{
|
{
|
||||||
|
$what = strtolower($what);
|
||||||
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
|
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
|
||||||
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
|
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
|
||||||
$uploadSize = min($maxFileSize, $maxPostSize);
|
$uploadSize = min($maxFileSize, $maxPostSize);
|
||||||
@@ -95,7 +97,7 @@ class TransactionController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function delete(TransactionJournal $journal)
|
public function delete(TransactionJournal $journal)
|
||||||
{
|
{
|
||||||
$what = strtolower($journal->transactionType->type);
|
$what = strtolower($journal->getTransactionType());
|
||||||
$subTitle = trans('firefly.delete_' . $what, ['description' => $journal->description]);
|
$subTitle = trans('firefly.delete_' . $what, ['description' => $journal->description]);
|
||||||
|
|
||||||
// put previous url in session
|
// put previous url in session
|
||||||
@@ -137,7 +139,7 @@ class TransactionController extends Controller
|
|||||||
public function edit(AccountRepositoryInterface $repository, TransactionJournal $journal)
|
public function edit(AccountRepositoryInterface $repository, TransactionJournal $journal)
|
||||||
{
|
{
|
||||||
// cannot edit opening balance
|
// cannot edit opening balance
|
||||||
if ($journal->transactionType->type == 'Opening balance') {
|
if ($journal->isOpeningBalance()) {
|
||||||
return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!');
|
return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +147,7 @@ class TransactionController extends Controller
|
|||||||
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
|
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
|
||||||
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
|
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
|
||||||
$uploadSize = min($maxFileSize, $maxPostSize);
|
$uploadSize = min($maxFileSize, $maxPostSize);
|
||||||
$what = strtolower($journal->transactionType->type);
|
$what = strtolower($journal->getTransactionType());
|
||||||
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
||||||
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
|
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
|
||||||
$budgets[0] = trans('form.noBudget');
|
$budgets[0] = trans('form.noBudget');
|
||||||
@@ -181,7 +183,7 @@ class TransactionController extends Controller
|
|||||||
|
|
||||||
$preFilled['amount'] = $journal->amount_positive;
|
$preFilled['amount'] = $journal->amount_positive;
|
||||||
|
|
||||||
if ($journal->transactionType->type == 'Withdrawal') {
|
if ($journal->isWithdrawal()) {
|
||||||
$preFilled['account_id'] = $journal->source_account->id;
|
$preFilled['account_id'] = $journal->source_account->id;
|
||||||
$preFilled['expense_account'] = $journal->destination_account->name_for_editform;
|
$preFilled['expense_account'] = $journal->destination_account->name_for_editform;
|
||||||
} else {
|
} else {
|
||||||
@@ -269,8 +271,8 @@ class TransactionController extends Controller
|
|||||||
$t->after = bcadd($t->before, $t->amount);
|
$t->after = bcadd($t->before, $t->amount);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
$what = strtolower($journal->transactionType->type);
|
$what = strtolower($journal->getTransactionType());
|
||||||
$subTitle = trans('firefly.' . $journal->transactionType->type) . ' "' . e($journal->description) . '"';
|
$subTitle = trans('firefly.' . $journal->getTransactionType()) . ' "' . e($journal->description) . '"';
|
||||||
|
|
||||||
return view('transactions.show', compact('journal', 'subTitle', 'what'));
|
return view('transactions.show', compact('journal', 'subTitle', 'what'));
|
||||||
}
|
}
|
||||||
@@ -287,7 +289,7 @@ class TransactionController extends Controller
|
|||||||
$journalData = $request->getJournalData();
|
$journalData = $request->getJournalData();
|
||||||
|
|
||||||
// if not withdrawal, unset budgetid.
|
// if not withdrawal, unset budgetid.
|
||||||
if ($journalData['what'] != 'withdrawal') {
|
if ($journalData['what'] != strtolower(TransactionType::WITHDRAWAL)) {
|
||||||
$journalData['budget_id'] = 0;
|
$journalData['budget_id'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,7 +310,7 @@ class TransactionController extends Controller
|
|||||||
// rescan journal, UpdateJournalConnection
|
// rescan journal, UpdateJournalConnection
|
||||||
event(new JournalSaved($journal));
|
event(new JournalSaved($journal));
|
||||||
|
|
||||||
if ($journal->transactionType->type == 'Transfer' && intval($request->get('piggy_bank_id')) > 0) {
|
if ($journal->isTransfer() && intval($request->get('piggy_bank_id')) > 0) {
|
||||||
event(new JournalCreated($journal, intval($request->get('piggy_bank_id'))));
|
event(new JournalCreated($journal, intval($request->get('piggy_bank_id'))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +342,7 @@ class TransactionController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
// cannot edit opening balance
|
// cannot edit opening balance
|
||||||
if ($journal->transactionType->type == 'Opening balance') {
|
if ($journal->isOpeningBalance()) {
|
||||||
return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!');
|
return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?php namespace FireflyIII\Http\Middleware;
|
<?php namespace FireflyIII\Http\Middleware;
|
||||||
|
|
||||||
use App;
|
use App;
|
||||||
|
use Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Closure;
|
use Closure;
|
||||||
use Config;
|
use Config;
|
||||||
@@ -54,15 +55,20 @@ class Authenticate
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (intval($this->auth->user()->blocked) == 1) {
|
if (intval($this->auth->user()->blocked) == 1) {
|
||||||
return redirect()->route('logout');
|
Auth::logout();
|
||||||
|
|
||||||
|
return redirect()->route('index');
|
||||||
}
|
}
|
||||||
|
|
||||||
// if logged in, set user language:
|
// if logged in, set user language:
|
||||||
$pref = Preferences::get('language', 'en');
|
$pref = Preferences::get('language', env('DEFAULT_LANGUAGE','en_US'));
|
||||||
App::setLocale($pref->data);
|
App::setLocale($pref->data);
|
||||||
Carbon::setLocale($pref->data);
|
Carbon::setLocale(substr($pref->data,0,2));
|
||||||
|
$locale = explode(',', trans('config.locale'));
|
||||||
|
$locale = array_map('trim', $locale);
|
||||||
|
|
||||||
setlocale(LC_TIME, Config::get('firefly.locales.' . $pref->data));
|
setlocale(LC_TIME, $locale);
|
||||||
|
setlocale(LC_MONETARY, $locale);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,18 +41,19 @@ class AccountFormRequest extends Request
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $idRule,
|
'id' => $idRule,
|
||||||
'name' => $nameRule,
|
'name' => $nameRule,
|
||||||
'openingBalance' => 'numeric',
|
'openingBalance' => 'numeric',
|
||||||
'iban' => 'iban',
|
'iban' => 'iban',
|
||||||
'virtualBalance' => 'numeric',
|
'virtualBalance' => 'numeric',
|
||||||
'openingBalanceDate' => 'date',
|
'openingBalanceDate' => 'date',
|
||||||
'accountRole' => 'in:' . $accountRoles,
|
'accountRole' => 'in:' . $accountRoles,
|
||||||
'active' => 'boolean',
|
'active' => 'boolean',
|
||||||
'ccType' => 'in:' . $ccPaymentTypes,
|
'ccType' => 'in:' . $ccPaymentTypes,
|
||||||
'ccMonthlyPaymentDate' => 'date',
|
'ccMonthlyPaymentDate' => 'date',
|
||||||
'balance_currency_id' => 'exists:transaction_currencies,id',
|
'amount_currency_id_openingBalance' => 'exists:transaction_currencies,id',
|
||||||
'what' => 'in:' . $types
|
'amount_currency_id_virtualBalance' => 'exists:transaction_currencies,id',
|
||||||
|
'what' => 'in:' . $types
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,17 +29,18 @@ class BillFormRequest extends Request
|
|||||||
public function getBillData()
|
public function getBillData()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => $this->get('name'),
|
'name' => $this->get('name'),
|
||||||
'match' => $this->get('match'),
|
'match' => $this->get('match'),
|
||||||
'amount_min' => round($this->get('amount_min'), 2),
|
'amount_min' => round($this->get('amount_min'), 2),
|
||||||
'amount_currency_id' => round($this->get('amount_currency_id'), 2),
|
'amount_currency_id_amount_min' => intval($this->get('amount_currency_id_amount_min')),
|
||||||
'amount_max' => round($this->get('amount_max'), 2),
|
'amount_currency_id_amount_max' => intval($this->get('amount_currency_id_amount_max')),
|
||||||
'date' => new Carbon($this->get('date')),
|
'amount_max' => round($this->get('amount_max'), 2),
|
||||||
'user' => Auth::user()->id,
|
'date' => new Carbon($this->get('date')),
|
||||||
'repeat_freq' => $this->get('repeat_freq'),
|
'user' => Auth::user()->id,
|
||||||
'skip' => intval($this->get('skip')),
|
'repeat_freq' => $this->get('repeat_freq'),
|
||||||
'automatch' => intval($this->get('automatch')) === 1,
|
'skip' => intval($this->get('skip')),
|
||||||
'active' => intval($this->get('active')) === 1,
|
'automatch' => intval($this->get('automatch')) === 1,
|
||||||
|
'active' => intval($this->get('active')) === 1,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,16 +57,17 @@ class BillFormRequest extends Request
|
|||||||
}
|
}
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
'name' => $nameRule,
|
'name' => $nameRule,
|
||||||
'match' => $matchRule,
|
'match' => $matchRule,
|
||||||
'amount_min' => 'required|numeric|min:0.01',
|
'amount_min' => 'required|numeric|min:0.01',
|
||||||
'amount_max' => 'required|numeric|min:0.01',
|
'amount_max' => 'required|numeric|min:0.01',
|
||||||
'amount_currency_id' => 'required|exists:transaction_currencies,id',
|
'amount_currency_id_amount_min' => 'required|exists:transaction_currencies,id',
|
||||||
'date' => 'required|date',
|
'amount_currency_id_amount_max' => 'required|exists:transaction_currencies,id',
|
||||||
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
|
'date' => 'required|date',
|
||||||
'skip' => 'required|between:0,31',
|
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
|
||||||
'automatch' => 'in:1',
|
'skip' => 'required|between:0,31',
|
||||||
'active' => 'in:1',
|
'automatch' => 'in:1',
|
||||||
|
'active' => 'in:1',
|
||||||
];
|
];
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace FireflyIII\Http\Requests;
|
|||||||
use Auth;
|
use Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
use Input;
|
use Input;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,20 +31,20 @@ class JournalFormRequest extends Request
|
|||||||
public function getJournalData()
|
public function getJournalData()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'what' => $this->get('what'),
|
'what' => $this->get('what'),
|
||||||
'description' => $this->get('description'),
|
'description' => $this->get('description'),
|
||||||
'account_id' => intval($this->get('account_id')),
|
'account_id' => intval($this->get('account_id')),
|
||||||
'account_from_id' => intval($this->get('account_from_id')),
|
'account_from_id' => intval($this->get('account_from_id')),
|
||||||
'account_to_id' => intval($this->get('account_to_id')),
|
'account_to_id' => intval($this->get('account_to_id')),
|
||||||
'expense_account' => $this->get('expense_account'),
|
'expense_account' => $this->get('expense_account'),
|
||||||
'revenue_account' => $this->get('revenue_account'),
|
'revenue_account' => $this->get('revenue_account'),
|
||||||
'amount' => round($this->get('amount'), 2),
|
'amount' => round($this->get('amount'), 2),
|
||||||
'user' => Auth::user()->id,
|
'user' => Auth::user()->id,
|
||||||
'amount_currency_id' => intval($this->get('amount_currency_id')),
|
'amount_currency_id_amount' => intval($this->get('amount_currency_id_amount')),
|
||||||
'date' => new Carbon($this->get('date')),
|
'date' => new Carbon($this->get('date')),
|
||||||
'budget_id' => intval($this->get('budget_id')),
|
'budget_id' => intval($this->get('budget_id')),
|
||||||
'category' => $this->get('category'),
|
'category' => $this->get('category'),
|
||||||
'tags' => explode(',', $this->get('tags')),
|
'tags' => explode(',', $this->get('tags')),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,16 +57,16 @@ class JournalFormRequest extends Request
|
|||||||
{
|
{
|
||||||
$what = Input::get('what');
|
$what = Input::get('what');
|
||||||
$rules = [
|
$rules = [
|
||||||
'description' => 'required|min:1,max:255',
|
'description' => 'required|min:1,max:255',
|
||||||
'what' => 'required|in:withdrawal,deposit,transfer',
|
'what' => 'required|in:withdrawal,deposit,transfer',
|
||||||
'amount' => 'numeric|required|min:0.01',
|
'amount' => 'numeric|required|min:0.01',
|
||||||
'date' => 'required|date',
|
'date' => 'required|date',
|
||||||
'amount_currency_id' => 'required|exists:transaction_currencies,id',
|
'amount_currency_id_amount' => 'required|exists:transaction_currencies,id',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
switch ($what) {
|
switch ($what) {
|
||||||
case 'withdrawal':
|
case strtolower(TransactionType::WITHDRAWAL):
|
||||||
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
|
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
|
||||||
$rules['expense_account'] = 'between:1,255';
|
$rules['expense_account'] = 'between:1,255';
|
||||||
$rules['category'] = 'between:1,255';
|
$rules['category'] = 'between:1,255';
|
||||||
@@ -73,12 +74,12 @@ class JournalFormRequest extends Request
|
|||||||
$rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets';
|
$rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'deposit':
|
case strtolower(TransactionType::DEPOSIT):
|
||||||
$rules['category'] = 'between:1,255';
|
$rules['category'] = 'between:1,255';
|
||||||
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
|
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
|
||||||
$rules['revenue_account'] = 'between:1,255';
|
$rules['revenue_account'] = 'between:1,255';
|
||||||
break;
|
break;
|
||||||
case 'transfer':
|
case strtolower(TransactionType::TRANSFER):
|
||||||
$rules['account_from_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_to_id';
|
$rules['account_from_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_to_id';
|
||||||
$rules['account_to_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_from_id';
|
$rules['account_to_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_from_id';
|
||||||
$rules['category'] = 'between:1,255';
|
$rules['category'] = 'between:1,255';
|
||||||
|
|||||||
@@ -27,11 +27,13 @@ class NewUserFormRequest extends Request
|
|||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'bank_name' => 'required|between:1,200',
|
'bank_name' => 'required|between:1,200',
|
||||||
'bank_balance' => 'required|numeric',
|
'bank_balance' => 'required|numeric',
|
||||||
'savings_balance' => 'numeric',
|
'savings_balance' => 'numeric',
|
||||||
'credit_card_limit' => 'numeric',
|
'credit_card_limit' => 'numeric',
|
||||||
'balance_currency_id' => 'exists:transaction_currencies,id',
|
'amount_currency_id_bank_balance' => 'exists:transaction_currencies,id',
|
||||||
|
'amount_currency_id_savings_balance' => 'exists:transaction_currencies,id',
|
||||||
|
'amount_currency_id_credit_card_limit' => 'exists:transaction_currencies,id',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,13 +36,13 @@ class PiggyBankFormRequest extends Request
|
|||||||
|
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
'name' => $nameRule,
|
'name' => $nameRule,
|
||||||
'account_id' => 'required|belongsToUser:accounts',
|
'account_id' => 'required|belongsToUser:accounts',
|
||||||
'targetamount' => 'required|min:0.01',
|
'targetamount' => 'required|min:0.01',
|
||||||
'amount_currency_id' => 'exists:transaction_currencies,id',
|
'amount_currency_id_targetamount' => 'exists:transaction_currencies,id',
|
||||||
'startdate' => 'date',
|
'startdate' => 'date',
|
||||||
'targetdate' => $targetDateRule,
|
'targetdate' => $targetDateRule,
|
||||||
'order' => 'integer|min:1',
|
'order' => 'integer|min:1',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -351,30 +351,13 @@ Breadcrumbs::register(
|
|||||||
);
|
);
|
||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'reports.year', function (Generator $breadcrumbs, Carbon $date, $shared) {
|
'reports.report', function (Generator $breadcrumbs, Carbon $start, Carbon $end, $reportType, $accountIds) {
|
||||||
$breadcrumbs->parent('reports.index');
|
$breadcrumbs->parent('reports.index');
|
||||||
if ($shared) {
|
|
||||||
$title = trans('breadcrumbs.yearly_report_shared', ['date' => $date->year]);
|
|
||||||
} else {
|
|
||||||
$title = trans('breadcrumbs.yearly_report', ['date' => $date->year]);
|
|
||||||
}
|
|
||||||
$breadcrumbs->push($title, route('reports.year', [$date->year]));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Breadcrumbs::register(
|
$monthFormat = trans('config.month_and_day');
|
||||||
'reports.month', function (Generator $breadcrumbs, Carbon $date, $shared) {
|
$title = trans('firefly.report_default', ['start' => $start->formatLocalized($monthFormat), 'end' => $end->formatLocalized($monthFormat)]);
|
||||||
$breadcrumbs->parent('reports.year', $date, $shared);
|
|
||||||
$language = Preferences::get('language', 'en')->data;
|
|
||||||
$format = Config::get('firefly.month.' . $language);
|
|
||||||
|
|
||||||
if ($shared) {
|
$breadcrumbs->push($title, route('reports.report', ['url' => 'abcde']));
|
||||||
$title = trans('breadcrumbs.monthly_report_shared', ['date' => $date->formatLocalized($format)]);
|
|
||||||
} else {
|
|
||||||
$title = trans('breadcrumbs.monthly_report', ['date' => $date->formatLocalized($format)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$breadcrumbs->push($title, route('reports.month', [$date->year, $date->month]));
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -416,7 +399,7 @@ Breadcrumbs::register(
|
|||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'transactions.show', function (Generator $breadcrumbs, TransactionJournal $journal) {
|
'transactions.show', function (Generator $breadcrumbs, TransactionJournal $journal) {
|
||||||
|
|
||||||
$breadcrumbs->parent('transactions.index', strtolower($journal->transactionType->type));
|
$breadcrumbs->parent('transactions.index', strtolower($journal->getTransactionType()));
|
||||||
$breadcrumbs->push($journal->description, route('transactions.show', [$journal->id]));
|
$breadcrumbs->push($journal->description, route('transactions.show', [$journal->id]));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\Attachment;
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\Bill;
|
use FireflyIII\Models\Bill;
|
||||||
@@ -29,6 +30,111 @@ Route::bind(
|
|||||||
throw new NotFoundHttpException;
|
throw new NotFoundHttpException;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
// account list! Yay!
|
||||||
|
Route::bind(
|
||||||
|
'accountList',
|
||||||
|
function ($value) {
|
||||||
|
if (Auth::check()) {
|
||||||
|
$ids = explode(',', $value);
|
||||||
|
/** @var \Illuminate\Support\Collection $object */
|
||||||
|
$object = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
||||||
|
->where('account_types.editable', 1)
|
||||||
|
->whereIn('accounts.id', $ids)
|
||||||
|
->where('user_id', Auth::user()->id)
|
||||||
|
->get(['accounts.*']);
|
||||||
|
if ($object->count() > 0) {
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// budget list
|
||||||
|
Route::bind(
|
||||||
|
'budgetList',
|
||||||
|
function ($value) {
|
||||||
|
if (Auth::check()) {
|
||||||
|
$ids = explode(',', $value);
|
||||||
|
/** @var \Illuminate\Support\Collection $object */
|
||||||
|
$object = Budget::where('active', 1)
|
||||||
|
->whereIn('id', $ids)
|
||||||
|
->where('user_id', Auth::user()->id)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// add empty budget if applicable.
|
||||||
|
if (in_array('0', $ids)) {
|
||||||
|
$object->push(new Budget);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($object->count() > 0) {
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// category list
|
||||||
|
Route::bind(
|
||||||
|
'categoryList',
|
||||||
|
function ($value) {
|
||||||
|
if (Auth::check()) {
|
||||||
|
$ids = explode(',', $value);
|
||||||
|
/** @var \Illuminate\Support\Collection $object */
|
||||||
|
$object = Category::whereIn('id', $ids)
|
||||||
|
->where('user_id', Auth::user()->id)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// add empty budget if applicable.
|
||||||
|
if (in_array('0', $ids)) {
|
||||||
|
$object->push(new Category);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($object->count() > 0) {
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Date
|
||||||
|
Route::bind(
|
||||||
|
'start_date',
|
||||||
|
function ($value) {
|
||||||
|
if (Auth::check()) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
$date = new Carbon($value);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error('Could not parse date "' . $value . '" for user #' . Auth::user()->id);
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Date
|
||||||
|
Route::bind(
|
||||||
|
'end_date',
|
||||||
|
function ($value) {
|
||||||
|
if (Auth::check()) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
$date = new Carbon($value);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error('Could not parse date "' . $value . '" for user #' . Auth::user()->id);
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
Route::bind(
|
Route::bind(
|
||||||
'tj', function ($value) {
|
'tj', function ($value) {
|
||||||
@@ -162,7 +268,7 @@ Route::get('/cron/sendgrid', ['uses' => 'CronController@sendgrid']);
|
|||||||
|
|
||||||
Route::controllers(
|
Route::controllers(
|
||||||
[
|
[
|
||||||
'auth' => 'Auth\AuthController',
|
'auth' => 'Auth\AuthController',
|
||||||
'password' => 'Auth\PasswordController',
|
'password' => 'Auth\PasswordController',
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -178,7 +284,6 @@ Route::group(
|
|||||||
Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']);
|
Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']);
|
||||||
Route::post('/daterange', ['uses' => 'HomeController@dateRange', 'as' => 'daterange']);
|
Route::post('/daterange', ['uses' => 'HomeController@dateRange', 'as' => 'daterange']);
|
||||||
Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']);
|
Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']);
|
||||||
Route::get('/routes', ['uses' => 'HomeController@routes']);
|
|
||||||
/**
|
/**
|
||||||
* Account Controller
|
* Account Controller
|
||||||
*/
|
*/
|
||||||
@@ -284,9 +389,7 @@ Route::group(
|
|||||||
// accounts:
|
// accounts:
|
||||||
Route::get('/chart/account/frontpage', ['uses' => 'Chart\AccountController@frontpage']);
|
Route::get('/chart/account/frontpage', ['uses' => 'Chart\AccountController@frontpage']);
|
||||||
Route::get('/chart/account/expense', ['uses' => 'Chart\AccountController@expenseAccounts']);
|
Route::get('/chart/account/expense', ['uses' => 'Chart\AccountController@expenseAccounts']);
|
||||||
Route::get('/chart/account/month/{year}/{month}/{shared?}', ['uses' => 'Chart\AccountController@all'])->where(
|
Route::get('/chart/account/report/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\AccountController@report']);
|
||||||
['year' => '[0-9]{4}', 'month' => '[0-9]{1,2}', 'shared' => 'shared']
|
|
||||||
);
|
|
||||||
Route::get('/chart/account/{account}', ['uses' => 'Chart\AccountController@single']);
|
Route::get('/chart/account/{account}', ['uses' => 'Chart\AccountController@single']);
|
||||||
|
|
||||||
|
|
||||||
@@ -296,18 +399,24 @@ Route::group(
|
|||||||
|
|
||||||
// budgets:
|
// budgets:
|
||||||
Route::get('/chart/budget/frontpage', ['uses' => 'Chart\BudgetController@frontpage']);
|
Route::get('/chart/budget/frontpage', ['uses' => 'Chart\BudgetController@frontpage']);
|
||||||
Route::get('/chart/budget/year/{year}/{shared?}', ['uses' => 'Chart\BudgetController@year'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']);
|
|
||||||
|
// this chart is used in reports:
|
||||||
|
Route::get('/chart/budget/year/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\BudgetController@year']);
|
||||||
|
Route::get('/chart/budget/multi-year/{report_type}/{start_date}/{end_date}/{accountList}/{budgetList}', ['uses' => 'Chart\BudgetController@multiYear']);
|
||||||
|
|
||||||
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'Chart\BudgetController@budgetLimit']);
|
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'Chart\BudgetController@budgetLimit']);
|
||||||
Route::get('/chart/budget/{budget}', ['uses' => 'Chart\BudgetController@budget']);
|
Route::get('/chart/budget/{budget}', ['uses' => 'Chart\BudgetController@budget']);
|
||||||
|
|
||||||
// categories:
|
// categories:
|
||||||
Route::get('/chart/category/frontpage', ['uses' => 'Chart\CategoryController@frontpage']);
|
Route::get('/chart/category/frontpage', ['uses' => 'Chart\CategoryController@frontpage']);
|
||||||
Route::get('/chart/category/spent-in-year/{year}/{shared?}', ['uses' => 'Chart\CategoryController@spentInYear'])->where(
|
|
||||||
['year' => '[0-9]{4}', 'shared' => 'shared']
|
// these three charts are for reports:
|
||||||
);
|
Route::get('/chart/category/earned-in-period/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\CategoryController@earnedInPeriod']);
|
||||||
Route::get('/chart/category/earned-in-year/{year}/{shared?}', ['uses' => 'Chart\CategoryController@earnedInYear'])->where(
|
Route::get('/chart/category/spent-in-period/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\CategoryController@spentInPeriod']);
|
||||||
['year' => '[0-9]{4}', 'shared' => 'shared']
|
Route::get(
|
||||||
|
'/chart/category/multi-year/{report_type}/{start_date}/{end_date}/{accountList}/{categoryList}', ['uses' => 'Chart\CategoryController@multiYear']
|
||||||
);
|
);
|
||||||
|
|
||||||
Route::get('/chart/category/{category}/period', ['uses' => 'Chart\CategoryController@currentPeriod']);
|
Route::get('/chart/category/{category}/period', ['uses' => 'Chart\CategoryController@currentPeriod']);
|
||||||
Route::get('/chart/category/{category}/period/{date}', ['uses' => 'Chart\CategoryController@specificPeriod']);
|
Route::get('/chart/category/{category}/period/{date}', ['uses' => 'Chart\CategoryController@specificPeriod']);
|
||||||
Route::get('/chart/category/{category}/all', ['uses' => 'Chart\CategoryController@all']);
|
Route::get('/chart/category/{category}/all', ['uses' => 'Chart\CategoryController@all']);
|
||||||
@@ -316,10 +425,8 @@ Route::group(
|
|||||||
Route::get('/chart/piggyBank/{piggyBank}', ['uses' => 'Chart\PiggyBankController@history']);
|
Route::get('/chart/piggyBank/{piggyBank}', ['uses' => 'Chart\PiggyBankController@history']);
|
||||||
|
|
||||||
// reports:
|
// reports:
|
||||||
Route::get('/chart/report/in-out/{year}/{shared?}', ['uses' => 'Chart\ReportController@yearInOut'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']);
|
Route::get('/chart/report/in-out/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\ReportController@yearInOut']);
|
||||||
Route::get('/chart/report/in-out-sum/{year}/{shared?}', ['uses' => 'Chart\ReportController@yearInOutSummarized'])->where(
|
Route::get('/chart/report/in-out-sum/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\ReportController@yearInOutSummarized']);
|
||||||
['year' => '[0-9]{4}', 'shared' => 'shared']
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -385,12 +492,7 @@ Route::group(
|
|||||||
* Report Controller
|
* Report Controller
|
||||||
*/
|
*/
|
||||||
Route::get('/reports', ['uses' => 'ReportController@index', 'as' => 'reports.index']);
|
Route::get('/reports', ['uses' => 'ReportController@index', 'as' => 'reports.index']);
|
||||||
Route::get('/reports/{year}/{shared?}', ['uses' => 'ReportController@year', 'as' => 'reports.year'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']);
|
Route::get('/reports/report/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'ReportController@report', 'as' => 'reports.report']);
|
||||||
Route::get('/reports/{year}/{month}/{shared?}', ['uses' => 'ReportController@month', 'as' => 'reports.month'])->where(
|
|
||||||
['year' => '[0-9]{4}', 'month' => '[0-9]{1,2}', 'shared' => 'shared']
|
|
||||||
);
|
|
||||||
|
|
||||||
// pop ups for budget report:
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search Controller
|
* Search Controller
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereSkip($value)
|
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereSkip($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereNameEncrypted($value)
|
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereNameEncrypted($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereMatchEncrypted($value)
|
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereMatchEncrypted($value)
|
||||||
* @property \Carbon\Carbon $nextExpectedMatch
|
* @property \Carbon\Carbon $nextExpectedMatch
|
||||||
* @property \Carbon\Carbon $lastFoundMatch
|
* @property \Carbon\Carbon $lastFoundMatch
|
||||||
*/
|
*/
|
||||||
class Bill extends Model
|
class Bill extends Model
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||||||
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereUserId($value)
|
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereUserId($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereEncrypted($value)
|
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereEncrypted($value)
|
||||||
* @property-read float $spent
|
* @property-read float $spent
|
||||||
* @property \Carbon\Carbon $lastActivity
|
* @property \Carbon\Carbon $lastActivity
|
||||||
*/
|
*/
|
||||||
class Category extends Model
|
class Category extends Model
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ use Watson\Validating\ValidatingTrait;
|
|||||||
* @property-read int $account_id
|
* @property-read int $account_id
|
||||||
* @property string $name
|
* @property string $name
|
||||||
* @property-read string $symbol
|
* @property-read string $symbol
|
||||||
|
* @property-read string $type
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Attachment[] $attachments
|
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Attachment[] $attachments
|
||||||
* @property-read mixed $amount_positive
|
* @property-read mixed $amount_positive
|
||||||
*/
|
*/
|
||||||
@@ -147,10 +148,9 @@ class TransactionJournal extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
$type = $this->transactionType->type;
|
|
||||||
$transaction = $this->transactions->sortByDesc('amount')->first();
|
$transaction = $this->transactions->sortByDesc('amount')->first();
|
||||||
$amount = $transaction->amount;
|
$amount = $transaction->amount;
|
||||||
if ($type == 'Withdrawal') {
|
if ($this->isWithdrawal()) {
|
||||||
$amount = $amount * -1;
|
$amount = $amount * -1;
|
||||||
}
|
}
|
||||||
$cache->store($amount);
|
$cache->store($amount);
|
||||||
@@ -167,15 +167,15 @@ class TransactionJournal extends Model
|
|||||||
*/
|
*/
|
||||||
protected function amountByTagAdvancePayment(Tag $tag, $amount)
|
protected function amountByTagAdvancePayment(Tag $tag, $amount)
|
||||||
{
|
{
|
||||||
if ($this->transactionType->type == 'Withdrawal') {
|
if ($this->isWithdrawal()) {
|
||||||
$others = $tag->transactionJournals()->transactionTypes(['Deposit'])->get();
|
$others = $tag->transactionJournals()->transactionTypes([TransactionType::DEPOSIT])->get();
|
||||||
foreach ($others as $other) {
|
foreach ($others as $other) {
|
||||||
$amount = bcsub($amount, $other->amount_positive);
|
$amount = bcsub($amount, $other->amount_positive);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $amount;
|
return $amount;
|
||||||
}
|
}
|
||||||
if ($this->transactionType->type == 'Deposit') {
|
if ($this->isDeposit()) {
|
||||||
return '0';
|
return '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,8 +190,8 @@ class TransactionJournal extends Model
|
|||||||
*/
|
*/
|
||||||
protected function amountByTagBalancingAct($tag, $amount)
|
protected function amountByTagBalancingAct($tag, $amount)
|
||||||
{
|
{
|
||||||
if ($this->transactionType->type == 'Withdrawal') {
|
if ($this->isWithdrawal()) {
|
||||||
$transfer = $tag->transactionJournals()->transactionTypes(['Transfer'])->first();
|
$transfer = $tag->transactionJournals()->transactionTypes([TransactionType::TRANSFER])->first();
|
||||||
if ($transfer) {
|
if ($transfer) {
|
||||||
$amount = bcsub($amount, $transfer->amount_positive);
|
$amount = bcsub($amount, $transfer->amount_positive);
|
||||||
|
|
||||||
@@ -491,4 +491,59 @@ class TransactionJournal extends Model
|
|||||||
return $this->belongsTo('FireflyIII\User');
|
return $this->belongsTo('FireflyIII\User');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTransactionType()
|
||||||
|
{
|
||||||
|
return $this->transactionType->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isWithdrawal()
|
||||||
|
{
|
||||||
|
if (!is_null($this->type)) {
|
||||||
|
return $this->type == TransactionType::WITHDRAWAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->transactionType->isWithdrawal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDeposit()
|
||||||
|
{
|
||||||
|
if (!is_null($this->type)) {
|
||||||
|
return $this->type == TransactionType::DEPOSIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->transactionType->isDeposit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isTransfer()
|
||||||
|
{
|
||||||
|
if (!is_null($this->type)) {
|
||||||
|
return $this->type == TransactionType::TRANSFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->transactionType->isTransfer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isOpeningBalance()
|
||||||
|
{
|
||||||
|
if (!is_null($this->type)) {
|
||||||
|
return $this->type == TransactionType::OPENING_BALANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->transactionType->isOpeningBalance();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ class TransactionType extends Model
|
|||||||
{
|
{
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
|
|
||||||
|
const WITHDRAWAL = 'Withdrawal';
|
||||||
|
const DEPOSIT = 'Deposit';
|
||||||
|
const TRANSFER = 'Transfer';
|
||||||
|
const OPENING_BALANCE = 'Opening balance';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
@@ -31,6 +36,38 @@ class TransactionType extends Model
|
|||||||
return ['created_at', 'updated_at', 'deleted_at'];
|
return ['created_at', 'updated_at', 'deleted_at'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDeposit()
|
||||||
|
{
|
||||||
|
return $this->type === TransactionType::DEPOSIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isOpeningBalance()
|
||||||
|
{
|
||||||
|
return $this->type === TransactionType::OPENING_BALANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isTransfer()
|
||||||
|
{
|
||||||
|
return $this->type === TransactionType::TRANSFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isWithdrawal()
|
||||||
|
{
|
||||||
|
return $this->type === TransactionType::WITHDRAWAL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -41,7 +41,16 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function countAccounts(array $types)
|
public function countAccounts(array $types)
|
||||||
{
|
{
|
||||||
return Auth::user()->accounts()->accountTypeIn($types)->count();
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('user-count-accounts');
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = Auth::user()->accounts()->accountTypeIn($types)->count();
|
||||||
|
$cache->store($count);
|
||||||
|
|
||||||
|
return $count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,6 +78,14 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function getAccounts(array $types)
|
public function getAccounts(array $types)
|
||||||
{
|
{
|
||||||
|
$cache = new CacheProperties();
|
||||||
|
$cache->addProperty('get-accounts');
|
||||||
|
$cache->addProperty($types);
|
||||||
|
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get();
|
||||||
|
}
|
||||||
|
|
||||||
/** @var Collection $result */
|
/** @var Collection $result */
|
||||||
$result = Auth::user()->accounts()->with(
|
$result = Auth::user()->accounts()->with(
|
||||||
['accountmeta' => function (HasMany $query) {
|
['accountmeta' => function (HasMany $query) {
|
||||||
@@ -82,23 +99,39 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$cache->store($result);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This method returns the users credit cards, along with some basic information about the
|
||||||
|
* balance they have on their CC. To be used in the JSON boxes on the front page that say
|
||||||
|
* how many bills there are still left to pay. The balance will be saved in field "balance".
|
||||||
|
*
|
||||||
|
* To get the balance, the field "date" is necessary.
|
||||||
|
*
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function getCreditCards()
|
public function getCreditCards(Carbon $date)
|
||||||
{
|
{
|
||||||
return Auth::user()->accounts()
|
return Auth::user()->accounts()
|
||||||
->hasMetaValue('accountRole', 'ccAsset')
|
->hasMetaValue('accountRole', 'ccAsset')
|
||||||
->hasMetaValue('ccType', 'monthlyFull')
|
->hasMetaValue('ccType', 'monthlyFull')
|
||||||
|
->leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
|
||||||
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
|
->whereNull('transactions.deleted_at')
|
||||||
|
->where('transaction_journals.date', '<=', $date->format('Y-m-d'))
|
||||||
|
->groupBy('accounts.id')
|
||||||
->get(
|
->get(
|
||||||
[
|
[
|
||||||
'accounts.*',
|
'accounts.*',
|
||||||
'ccType.data as ccType',
|
'ccType.data as ccType',
|
||||||
'accountRole.data as accountRole'
|
'accountRole.data as accountRole',
|
||||||
|
DB::Raw('SUM(`transactions`.`amount`) AS `balance`')
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -111,8 +144,18 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function getFirstTransaction(TransactionJournal $journal, Account $account)
|
public function getFirstTransaction(TransactionJournal $journal, Account $account)
|
||||||
{
|
{
|
||||||
|
$cache = new CacheProperties();
|
||||||
|
$cache->addProperty('first-transaction');
|
||||||
|
$cache->addProperty($journal->id);
|
||||||
|
$cache->addProperty($account->id);
|
||||||
|
|
||||||
return $journal->transactions()->where('account_id', $account->id)->first();
|
if ($cache->has()) {
|
||||||
|
return $cache->get();
|
||||||
|
}
|
||||||
|
$transaction = $journal->transactions()->where('account_id', $account->id)->first();
|
||||||
|
$cache->store($transaction);
|
||||||
|
|
||||||
|
return $transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,8 +166,7 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
public function getFrontpageAccounts(Preference $preference)
|
public function getFrontpageAccounts(Preference $preference)
|
||||||
{
|
{
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($preference->data);
|
$cache->addProperty('user-frontpage-accounts');
|
||||||
$cache->addProperty('frontPageaccounts');
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return $cache->get(); // @codeCoverageIgnore
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
@@ -158,6 +200,7 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
$cache->addProperty($account->id);
|
$cache->addProperty($account->id);
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty('frontpage-transactions');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return $cache->get(); // @codeCoverageIgnore
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
@@ -172,6 +215,7 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
->before($end)
|
->before($end)
|
||||||
->after($start)
|
->after($start)
|
||||||
->orderBy('transaction_journals.date', 'DESC')
|
->orderBy('transaction_journals.date', 'DESC')
|
||||||
|
->orderBy('transaction_journals.order', 'ASC')
|
||||||
->orderBy('transaction_journals.id', 'DESC')
|
->orderBy('transaction_journals.id', 'DESC')
|
||||||
->take(10)
|
->take(10)
|
||||||
->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']);
|
->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']);
|
||||||
@@ -227,14 +271,14 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
|
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty($ids);
|
$cache->addProperty($ids);
|
||||||
$cache->addProperty('piggyAccounts');
|
$cache->addProperty('user-piggy-bank-accounts');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return $cache->get(); // @codeCoverageIgnore
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$ids = array_unique($ids);
|
$ids = array_unique($ids);
|
||||||
if (count($ids) > 0) {
|
if (count($ids) > 0) {
|
||||||
$accounts = Auth::user()->accounts()->whereIn('id', $ids)->get();
|
$accounts = Auth::user()->accounts()->whereIn('id', $ids)->where('accounts.active', 1)->get();
|
||||||
}
|
}
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
|
|
||||||
@@ -273,6 +317,7 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')
|
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')
|
||||||
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
|
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
|
||||||
->where('account_meta.name', 'accountRole')
|
->where('account_meta.name', 'accountRole')
|
||||||
|
->where('accounts.active', 1)
|
||||||
->where('account_meta.data', '"savingAsset"')
|
->where('account_meta.data', '"savingAsset"')
|
||||||
->get(['accounts.*']);
|
->get(['accounts.*']);
|
||||||
$start = clone Session::get('start', new Carbon);
|
$start = clone Session::get('start', new Carbon);
|
||||||
@@ -319,31 +364,23 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function getTransfersInRange(Account $account, Carbon $start, Carbon $end)
|
public function getTransfersInRange(Account $account, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
$set = TransactionJournal::whereIn(
|
$set = TransactionJournal::whereIn(
|
||||||
'id', function (Builder $q) use ($account, $start, $end) {
|
'id', function (Builder $q) use ($account, $start, $end) {
|
||||||
$q->select('transaction_journals.id')
|
$q->select('transaction_journals.id')
|
||||||
->from('transactions')
|
->from('transactions')
|
||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||||
->where('transactions.account_id', $account->id)
|
->where('transactions.account_id', $account->id)
|
||||||
|
->where('transactions.amount', '>', 0)// this makes the filter unnecessary.
|
||||||
->where('transaction_journals.user_id', Auth::user()->id)
|
->where('transaction_journals.user_id', Auth::user()->id)
|
||||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||||
->where('transaction_types.type', 'Transfer');
|
->where('transaction_types.type', TransactionType::TRANSFER);
|
||||||
|
|
||||||
}
|
}
|
||||||
)->get();
|
)->get();
|
||||||
$filtered = $set->filter(
|
|
||||||
function (TransactionJournal $journal) use ($account) {
|
|
||||||
if ($journal->destination_account->id == $account->id) {
|
|
||||||
return $journal;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return $set;
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return $filtered;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -372,12 +409,23 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function openingBalanceTransaction(Account $account)
|
public function openingBalanceTransaction(Account $account)
|
||||||
{
|
{
|
||||||
return TransactionJournal
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($account->id);
|
||||||
|
$cache->addProperty('opening-balance-journal');
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$journal = TransactionJournal
|
||||||
::orderBy('transaction_journals.date', 'ASC')
|
::orderBy('transaction_journals.date', 'ASC')
|
||||||
->accountIs($account)
|
->accountIs($account)
|
||||||
->transactionTypes(['Opening balance'])
|
->transactionTypes([TransactionType::OPENING_BALANCE])
|
||||||
->orderBy('created_at', 'ASC')
|
->orderBy('created_at', 'ASC')
|
||||||
->first(['transaction_journals.*']);
|
->first(['transaction_journals.*']);
|
||||||
|
$cache->store($journal);
|
||||||
|
|
||||||
|
return $journal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -548,7 +596,7 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
protected function storeInitialBalance(Account $account, Account $opposing, array $data)
|
protected function storeInitialBalance(Account $account, Account $opposing, array $data)
|
||||||
{
|
{
|
||||||
$transactionType = TransactionType::whereType('Opening balance')->first();
|
$transactionType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
|
||||||
$journal = TransactionJournal::create(
|
$journal = TransactionJournal::create(
|
||||||
[
|
[
|
||||||
'user_id' => $data['user'],
|
'user_id' => $data['user'],
|
||||||
@@ -642,4 +690,16 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
|
|
||||||
return $journal;
|
return $journal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*
|
||||||
|
* @param $accountId
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function find($accountId)
|
||||||
|
{
|
||||||
|
return Auth::user()->accounts()->findOrNew($accountId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,15 @@ interface AccountRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function countAccounts(array $types);
|
public function countAccounts(array $types);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $accountId
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function find($accountId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Account $account
|
* @param Account $account
|
||||||
* @param Account $moveTo
|
* @param Account $moveTo
|
||||||
@@ -48,9 +57,17 @@ interface AccountRepositoryInterface
|
|||||||
public function getFirstTransaction(TransactionJournal $journal, Account $account);
|
public function getFirstTransaction(TransactionJournal $journal, Account $account);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This method returns the users credit cards, along with some basic information about the
|
||||||
|
* balance they have on their CC. To be used in the JSON boxes on the front page that say
|
||||||
|
* how many bills there are still left to pay. The balance will be saved in field "balance".
|
||||||
|
*
|
||||||
|
* To get the balance, the field "date" is necessary.
|
||||||
|
*
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function getCreditCards();
|
public function getCreditCards(Carbon $date);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the accounts of a user that have piggy banks connected to them.
|
* Get the accounts of a user that have piggy banks connected to them.
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ namespace FireflyIII\Repositories\Bill;
|
|||||||
use Auth;
|
use Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use DB;
|
use DB;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\Bill;
|
use FireflyIII\Models\Bill;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use Illuminate\Database\Query\JoinClause;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Log;
|
use Log;
|
||||||
use Navigation;
|
use Navigation;
|
||||||
@@ -21,6 +23,7 @@ use Steam;
|
|||||||
class BillRepository implements BillRepositoryInterface
|
class BillRepository implements BillRepositoryInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* Returns the sum of all payments connected to this bill between the dates.
|
* Returns the sum of all payments connected to this bill between the dates.
|
||||||
*
|
*
|
||||||
* @param Bill $bill
|
* @param Bill $bill
|
||||||
@@ -83,7 +86,7 @@ class BillRepository implements BillRepositoryInterface
|
|||||||
public function getActiveBills()
|
public function getActiveBills()
|
||||||
{
|
{
|
||||||
/** @var Collection $set */
|
/** @var Collection $set */
|
||||||
$set = Auth::user()->bills()->orderBy('name', 'ASC')->where('active', 1)->get()->sortBy('name');
|
$set = Auth::user()->bills()->where('active', 1)->get()->sortBy('name');
|
||||||
|
|
||||||
return $set;
|
return $set;
|
||||||
}
|
}
|
||||||
@@ -108,6 +111,46 @@ class BillRepository implements BillRepositoryInterface
|
|||||||
return $set;
|
return $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getBillsForAccounts(Collection $accounts)
|
||||||
|
{
|
||||||
|
/** @var Collection $set */
|
||||||
|
$set = Auth::user()->bills()->orderBy('name', 'ASC')->get();
|
||||||
|
|
||||||
|
$ids = [];
|
||||||
|
/** @var Account $account */
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$ids[] = $account->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$set = $set->filter(
|
||||||
|
function (Bill $bill) use ($ids) {
|
||||||
|
// get transaction journals from or to any of the mentioned accounts.
|
||||||
|
// if zero, return null.
|
||||||
|
$journals = $bill->transactionjournals()->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->whereIn('transactions.account_id', $ids)->count();
|
||||||
|
|
||||||
|
return ($journals > 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$set = $set->sortBy(
|
||||||
|
function (Bill $bill) {
|
||||||
|
|
||||||
|
$int = $bill->active == 1 ? 0 : 1;
|
||||||
|
|
||||||
|
return $int . strtolower($bill->name);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Bill $bill
|
* @param Bill $bill
|
||||||
*
|
*
|
||||||
@@ -154,7 +197,7 @@ class BillRepository implements BillRepositoryInterface
|
|||||||
}
|
}
|
||||||
$journals = new Collection;
|
$journals = new Collection;
|
||||||
if (count($ids) > 0) {
|
if (count($ids) > 0) {
|
||||||
$journals = Auth::user()->transactionjournals()->transactionTypes(['Withdrawal'])->whereIn('transaction_journals.id', $ids)->get(
|
$journals = Auth::user()->transactionjournals()->transactionTypes([TransactionType::WITHDRAWAL])->whereIn('transaction_journals.id', $ids)->get(
|
||||||
['transaction_journals.*']
|
['transaction_journals.*']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -276,12 +319,21 @@ class BillRepository implements BillRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function scan(Bill $bill, TransactionJournal $journal)
|
public function scan(Bill $bill, TransactionJournal $journal)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Can only support withdrawals.
|
||||||
|
*/
|
||||||
|
if (false === $journal->isWithdrawal()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$matches = explode(',', $bill->match);
|
$matches = explode(',', $bill->match);
|
||||||
$description = strtolower($journal->description) . ' ' . strtolower($journal->destination_account->name);
|
$description = strtolower($journal->description) . ' ' . strtolower($journal->destination_account->name);
|
||||||
$wordMatch = $this->doWordMatch($matches, $description);
|
$wordMatch = $this->doWordMatch($matches, $description);
|
||||||
$amountMatch = $this->doAmountMatch($journal->amount_positive, $bill->amount_min, $bill->amount_max);
|
$amountMatch = $this->doAmountMatch($journal->amount_positive, $bill->amount_min, $bill->amount_max);
|
||||||
Log::debug('Journal #' . $journal->id . ' has description "' . $description . '"');
|
Log::debug('Journal #' . $journal->id . ' has description "' . $description . '"');
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If both, update!
|
* If both, update!
|
||||||
*/
|
*/
|
||||||
@@ -446,22 +498,21 @@ class BillRepository implements BillRepositoryInterface
|
|||||||
{
|
{
|
||||||
|
|
||||||
$accounts = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
$accounts = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||||
$creditCards = $accounts->getCreditCards();
|
$creditCards = $accounts->getCreditCards($end);
|
||||||
$paid = $set->get('paid');
|
$paid = $set->get('paid');
|
||||||
$unpaid = $set->get('unpaid');
|
$unpaid = $set->get('unpaid');
|
||||||
|
|
||||||
foreach ($creditCards as $creditCard) {
|
foreach ($creditCards as $creditCard) {
|
||||||
$balance = Steam::balance($creditCard, $end, true);
|
|
||||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||||
if ($balance < 0) {
|
if ($creditCard->balance < 0) {
|
||||||
// unpaid! create a fake bill that matches the amount.
|
// unpaid! create a fake bill that matches the amount.
|
||||||
$description = $creditCard->name;
|
$description = $creditCard->name;
|
||||||
$amount = $balance * -1;
|
$amount = $creditCard->balance * -1;
|
||||||
$fakeBill = $this->createFakeBill($description, $date, $amount);
|
$fakeBill = $this->createFakeBill($description, $date, $amount);
|
||||||
unset($description, $amount);
|
unset($description, $amount);
|
||||||
$unpaid->push([$fakeBill, $date]);
|
$unpaid->push([$fakeBill, $date]);
|
||||||
}
|
}
|
||||||
if ($balance == 0) {
|
if ($creditCard->balance == 0) {
|
||||||
// find transfer(s) TO the credit card which should account for
|
// find transfer(s) TO the credit card which should account for
|
||||||
// anything paid. If not, the CC is not yet used.
|
// anything paid. If not, the CC is not yet used.
|
||||||
$journals = $accounts->getTransfersInRange($creditCard, $start, $end);
|
$journals = $accounts->getTransfersInRange($creditCard, $start, $end);
|
||||||
@@ -474,4 +525,32 @@ class BillRepository implements BillRepositoryInterface
|
|||||||
|
|
||||||
return $set;
|
return $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns all active bills which have been paid for in the given range,
|
||||||
|
* with the field "paid" indicating how much the bill was for.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function billsPaidInRange(Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
$set = Auth::user()->bills()
|
||||||
|
->leftJoin('transaction_journals', 'transaction_journals.bill_id', '=', 'bills.id')
|
||||||
|
->leftJoin(
|
||||||
|
'transactions', function (JoinClause $join) {
|
||||||
|
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '>', 0);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||||
|
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||||
|
->where('bills.active', 1)
|
||||||
|
->groupBy('bills.id')->get(
|
||||||
|
['bills.*', DB::Raw('SUM(`transactions`.`amount`) as `paid`')]
|
||||||
|
);
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ interface BillRepositoryInterface
|
|||||||
public function getBillsForChart(Carbon $start, Carbon $end);
|
public function getBillsForChart(Carbon $start, Carbon $end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* Returns the sum of all payments connected to this bill between the dates.
|
* Returns the sum of all payments connected to this bill between the dates.
|
||||||
*
|
*
|
||||||
* @param Bill $bill
|
* @param Bill $bill
|
||||||
@@ -49,6 +50,17 @@ interface BillRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function billPaymentsInRange(Bill $bill, Carbon $start, Carbon $end);
|
public function billPaymentsInRange(Bill $bill, Carbon $start, Carbon $end);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns all active bills which have been paid for in the given range,
|
||||||
|
* with the field "paid" indicating how much the bill was for.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function billsPaidInRange(Carbon $start, Carbon $end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a fake bill to help the chart controller.
|
* Create a fake bill to help the chart controller.
|
||||||
*
|
*
|
||||||
@@ -77,6 +89,15 @@ interface BillRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function getBills();
|
public function getBills();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the bills which have some kind of relevance to the accounts mentioned.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getBillsForAccounts(Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Bill $bill
|
* @param Bill $bill
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use Carbon\Carbon;
|
|||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
use FireflyIII\Models\LimitRepetition;
|
use FireflyIII\Models\LimitRepetition;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\Repositories\Shared\ComponentRepository;
|
use FireflyIII\Repositories\Shared\ComponentRepository;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||||
@@ -50,10 +51,10 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
|
|||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
public function expensesOnDayCorrected(Budget $budget, Carbon $date)
|
public function expensesOnDay(Budget $budget, Carbon $date)
|
||||||
{
|
{
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
$sum = $budget->transactionjournals()->transactionTypes(['Withdrawal'])->onDate($date)->get(['transaction_journals.*'])->sum('amount');
|
$sum = $budget->transactionjournals()->transactionTypes([TransactionType::WITHDRAWAL])->onDate($date)->get(['transaction_journals.*'])->sum('amount');
|
||||||
|
|
||||||
return $sum;
|
return $sum;
|
||||||
}
|
}
|
||||||
@@ -139,9 +140,11 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
|
|||||||
return $cache->get(); // @codeCoverageIgnore
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
$data = $budget->limitrepetitions()
|
$data = $budget->limitrepetitions()
|
||||||
->where('limit_repetitions.startdate', $start)
|
->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00'))
|
||||||
->where('limit_repetitions.enddate', $end)
|
->where('limit_repetitions.enddate', $end->format('Y-m-d 00:00:00'))
|
||||||
->first(['limit_repetitions.*']);
|
->first(['limit_repetitions.*']);
|
||||||
|
//Log::debug('Looking for limit reps for budget #' . $budget->id . ' start [' . $start . '] and end [' . $end . '].');
|
||||||
|
//Log::debug(DB::getQueryLog())
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
@@ -226,6 +229,8 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*
|
||||||
* @param Budget $budget
|
* @param Budget $budget
|
||||||
*
|
*
|
||||||
* @return Carbon
|
* @return Carbon
|
||||||
@@ -241,6 +246,7 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* @param Budget $budget
|
* @param Budget $budget
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
*
|
*
|
||||||
@@ -303,25 +309,23 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
|
|||||||
)
|
)
|
||||||
->after($start)
|
->after($start)
|
||||||
->before($end)
|
->before($end)
|
||||||
->transactionTypes(['Withdrawal'])
|
->transactionTypes([TransactionType::WITHDRAWAL])
|
||||||
->get(['transaction_journals.*'])->sum('amount');
|
->get(['transaction_journals.*'])->sum('amount');
|
||||||
|
|
||||||
bcscale(2);
|
return $noBudgetSet;
|
||||||
|
|
||||||
return bcmul($noBudgetSet, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Budget $budget
|
* @param Budget $budget
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param bool $shared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, $shared = true)
|
public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
return $this->commonBalanceInPeriod($budget, $start, $end, $shared);
|
return $this->commonBalanceInPeriod($budget, $start, $end, $accounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ interface BudgetRepositoryInterface
|
|||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
public function expensesOnDayCorrected(Budget $budget, Carbon $date);
|
public function expensesOnDay(Budget $budget, Carbon $date);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection
|
* @return Collection
|
||||||
@@ -96,6 +96,7 @@ interface BudgetRepositoryInterface
|
|||||||
public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50);
|
public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* @param Budget $budget
|
* @param Budget $budget
|
||||||
*
|
*
|
||||||
* @return Carbon
|
* @return Carbon
|
||||||
@@ -103,6 +104,7 @@ interface BudgetRepositoryInterface
|
|||||||
public function getLastBudgetLimitDate(Budget $budget);
|
public function getLastBudgetLimitDate(Budget $budget);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* @param Budget $budget
|
* @param Budget $budget
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
*
|
*
|
||||||
@@ -128,16 +130,16 @@ interface BudgetRepositoryInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Same as ::spentInPeriod but corrects journals for their amount (tags).
|
* Same as ::spentInPeriod but corrects journals for a set of accounts
|
||||||
*
|
*
|
||||||
* @param Budget $budget
|
* @param Budget $budget
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param boolean $shared
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, $shared = true);
|
public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
|||||||
@@ -5,10 +5,13 @@ namespace FireflyIII\Repositories\Category;
|
|||||||
use Auth;
|
use Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Crypt;
|
use Crypt;
|
||||||
|
use DB;
|
||||||
use FireflyIII\Models\Category;
|
use FireflyIII\Models\Category;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\Repositories\Shared\ComponentRepository;
|
use FireflyIII\Repositories\Shared\ComponentRepository;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
|
use Illuminate\Database\Query\JoinClause;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,6 +50,13 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
|||||||
*/
|
*/
|
||||||
public function getCategories()
|
public function getCategories()
|
||||||
{
|
{
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('category-list');
|
||||||
|
|
||||||
|
if($cache->has()) {
|
||||||
|
return $cache->get();
|
||||||
|
}
|
||||||
|
|
||||||
/** @var Collection $set */
|
/** @var Collection $set */
|
||||||
$set = Auth::user()->categories()->orderBy('name', 'ASC')->get();
|
$set = Auth::user()->categories()->orderBy('name', 'ASC')->get();
|
||||||
$set = $set->sortBy(
|
$set = $set->sortBy(
|
||||||
@@ -55,9 +65,76 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$cache->store($set);
|
||||||
|
|
||||||
return $set;
|
return $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount earned without category by accounts in period.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function earnedNoCategoryForAccounts(Collection $accounts, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
|
||||||
|
$accountIds = [];
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$accountIds[] = $account->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is deposit AND account_from is in the list of $accounts
|
||||||
|
// not from any of the accounts in the list?
|
||||||
|
|
||||||
|
return Auth::user()
|
||||||
|
->transactionjournals()
|
||||||
|
->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->whereNull('category_transaction_journal.id')
|
||||||
|
->before($end)
|
||||||
|
->after($start)
|
||||||
|
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->whereIn('transactions.account_id', $accountIds)
|
||||||
|
->transactionTypes([TransactionType::DEPOSIT])
|
||||||
|
->get(['transaction_journals.*'])->sum('amount');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount spent without category by accounts in period.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function spentNoCategoryForAccounts(Collection $accounts, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
|
||||||
|
$accountIds = [];
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$accountIds[] = $account->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is withdrawal or transfer AND account_from is in the list of $accounts
|
||||||
|
|
||||||
|
|
||||||
|
return Auth::user()
|
||||||
|
->transactionjournals()
|
||||||
|
->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->whereNull('category_transaction_journal.id')
|
||||||
|
->before($end)
|
||||||
|
->after($start)
|
||||||
|
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->whereIn('transactions.account_id', $accountIds)
|
||||||
|
->transactionTypes([TransactionType::WITHDRAWAL])
|
||||||
|
->get(['transaction_journals.*'])->sum('amount');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -66,7 +143,7 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getCategoriesAndExpensesCorrected(Carbon $start, Carbon $end)
|
public function getCategoriesAndExpenses(Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
$set = Auth::user()->transactionjournals()
|
$set = Auth::user()->transactionjournals()
|
||||||
->leftJoin(
|
->leftJoin(
|
||||||
@@ -76,7 +153,7 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
|||||||
->before($end)
|
->before($end)
|
||||||
->where('categories.user_id', Auth::user()->id)
|
->where('categories.user_id', Auth::user()->id)
|
||||||
->after($start)
|
->after($start)
|
||||||
->transactionTypes(['Withdrawal'])
|
->transactionTypes([TransactionType::WITHDRAWAL])
|
||||||
->get(['categories.id as category_id', 'categories.encrypted as category_encrypted', 'categories.name', 'transaction_journals.*']);
|
->get(['categories.id as category_id', 'categories.encrypted as category_encrypted', 'categories.name', 'transaction_journals.*']);
|
||||||
|
|
||||||
bcscale(2);
|
bcscale(2);
|
||||||
@@ -177,17 +254,16 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Category $category
|
* @param Category $category
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
*
|
* @param Collection $accounts
|
||||||
* @param bool $shared
|
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function balanceInPeriod(Category $category, Carbon $start, Carbon $end, $shared = false)
|
public function balanceInPeriod(Category $category, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
return $this->commonBalanceInPeriod($category, $start, $end, $shared);
|
return $this->commonBalanceInPeriod($category, $start, $end, $accounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -198,9 +274,9 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function spentOnDaySumCorrected(Category $category, Carbon $date)
|
public function spentOnDaySum(Category $category, Carbon $date)
|
||||||
{
|
{
|
||||||
return $category->transactionjournals()->transactionTypes(['Withdrawal'])->onDate($date)->get(['transaction_journals.*'])->sum('amount');
|
return $category->transactionjournals()->transactionTypes([TransactionType::WITHDRAWAL])->onDate($date)->get(['transaction_journals.*'])->sum('amount');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -237,6 +313,7 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* This method returns the sum of the journals in the category, optionally
|
* This method returns the sum of the journals in the category, optionally
|
||||||
* limited by a start or end date.
|
* limited by a start or end date.
|
||||||
*
|
*
|
||||||
@@ -285,9 +362,10 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
|||||||
return $cache->get(); // @codeCoverageIgnore
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$sum = $category->transactionjournals()->transactionTypes(['Withdrawal'])->before($end)->after($start)->get(['transaction_journals.*'])->sum(
|
$sum = $category->transactionjournals()->transactionTypes([TransactionType::WITHDRAWAL])->before($end)->after($start)->get(['transaction_journals.*'])
|
||||||
'amount'
|
->sum(
|
||||||
);
|
'amount'
|
||||||
|
);
|
||||||
|
|
||||||
$cache->store($sum);
|
$cache->store($sum);
|
||||||
|
|
||||||
@@ -315,9 +393,10 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
|||||||
return $cache->get(); // @codeCoverageIgnore
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$sum = $category->transactionjournals()->transactionTypes(['Deposit'])->before($end)->after($start)->get(['transaction_journals.*'])->sum(
|
$sum = $category->transactionjournals()->transactionTypes([TransactionType::DEPOSIT])->before($end)->after($start)->get(['transaction_journals.*'])
|
||||||
'amount'
|
->sum(
|
||||||
);
|
'amount'
|
||||||
|
);
|
||||||
|
|
||||||
$cache->store($sum);
|
$cache->store($sum);
|
||||||
|
|
||||||
@@ -365,8 +444,165 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
|||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
public function earnedOnDaySumCorrected(Category $category, Carbon $date)
|
public function earnedOnDaySum(Category $category, Carbon $date)
|
||||||
{
|
{
|
||||||
return $category->transactionjournals()->transactionTypes(['Deposit'])->onDate($date)->get(['transaction_journals.*'])->sum('amount');
|
return $category->transactionjournals()->transactionTypes([TransactionType::DEPOSIT])->onDate($date)->get(['transaction_journals.*'])->sum('amount');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates how much is spent in this period.
|
||||||
|
*
|
||||||
|
* @param Category $category
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function spentInPeriodForAccounts(Category $category, Collection $accounts, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
$accountIds = [];
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$accountIds[] = $account->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sum
|
||||||
|
= $category
|
||||||
|
->transactionjournals()
|
||||||
|
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->after($start)
|
||||||
|
->before($end)
|
||||||
|
->whereIn('transactions.account_id', $accountIds)
|
||||||
|
->transactionTypes([TransactionType::WITHDRAWAL])
|
||||||
|
->get(['transaction_journals.*'])
|
||||||
|
->sum('amount');
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate how much is earned in this period.
|
||||||
|
*
|
||||||
|
* @param Category $category
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function earnedInPeriodForAccounts(Category $category, Collection $accounts, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
$accountIds = [];
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$accountIds[] = $account->id;
|
||||||
|
}
|
||||||
|
$sum
|
||||||
|
= $category
|
||||||
|
->transactionjournals()
|
||||||
|
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->before($end)
|
||||||
|
->whereIn('transactions.account_id', $accountIds)
|
||||||
|
->transactionTypes([TransactionType::DEPOSIT])
|
||||||
|
->after($start)
|
||||||
|
->get(['transaction_journals.*'])
|
||||||
|
->sum('amount');
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of Categories appended with the amount of money that has been earned
|
||||||
|
* in these categories, based on the $accounts involved, in period X.
|
||||||
|
* The amount earned in category X in period X is saved in field "earned".
|
||||||
|
*
|
||||||
|
* @param $accounts
|
||||||
|
* @param $start
|
||||||
|
* @param $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function earnedForAccounts(Collection $accounts, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
$accountIds = [];
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$accountIds[] = $account->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$collection = Auth::user()->categories()
|
||||||
|
->leftJoin('category_transaction_journal', 'category_transaction_journal.category_id', '=', 'categories.id')
|
||||||
|
->leftJoin('transaction_journals', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||||
|
->leftJoin(
|
||||||
|
'transactions AS t_src', function (JoinClause $join) {
|
||||||
|
$join->on('t_src.transaction_journal_id', '=', 'transaction_journals.id')->where('t_src.amount', '<', 0);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->leftJoin(
|
||||||
|
'transactions AS t_dest', function (JoinClause $join) {
|
||||||
|
$join->on('t_dest.transaction_journal_id', '=', 'transaction_journals.id')->where('t_dest.amount', '>', 0);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->whereIn('t_dest.account_id', $accountIds)// to these accounts (earned)
|
||||||
|
->whereNotIn('t_src.account_id', $accountIds)//-- but not from these accounts
|
||||||
|
->whereIn(
|
||||||
|
'transaction_types.type', [TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]
|
||||||
|
)// earned from these things.
|
||||||
|
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||||
|
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||||
|
->groupBy('categories.id')
|
||||||
|
->get(['categories.*', DB::Raw('SUM(`t_dest`.`amount`) AS `earned`')]);
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of Categories appended with the amount of money that has been spent
|
||||||
|
* in these categories, based on the $accounts involved, in period X.
|
||||||
|
* The amount earned in category X in period X is saved in field "spent".
|
||||||
|
*
|
||||||
|
* @param $accounts
|
||||||
|
* @param $start
|
||||||
|
* @param $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function spentForAccounts(Collection $accounts, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
$accountIds = [];
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$accountIds[] = $account->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$collection = Auth::user()->categories()
|
||||||
|
->leftJoin('category_transaction_journal', 'category_transaction_journal.category_id', '=', 'categories.id')
|
||||||
|
->leftJoin('transaction_journals', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||||
|
->leftJoin(
|
||||||
|
'transactions AS t_src', function (JoinClause $join) {
|
||||||
|
$join->on('t_src.transaction_journal_id', '=', 'transaction_journals.id')->where('t_src.amount', '<', 0);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->leftJoin(
|
||||||
|
'transactions AS t_dest', function (JoinClause $join) {
|
||||||
|
$join->on('t_dest.transaction_journal_id', '=', 'transaction_journals.id')->where('t_dest.amount', '>', 0);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->whereIn('t_src.account_id', $accountIds)// from these accounts (spent)
|
||||||
|
->whereNotIn('t_dest.account_id', $accountIds)//-- but not from these accounts (spent internally)
|
||||||
|
->whereIn(
|
||||||
|
'transaction_types.type', [TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]
|
||||||
|
)// spent on these things.
|
||||||
|
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||||
|
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||||
|
->groupBy('categories.id')
|
||||||
|
->get(['categories.*', DB::Raw('SUM(`t_dest`.`amount`) AS `spent`')]);
|
||||||
|
|
||||||
|
return $collection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,11 +34,84 @@ interface CategoryRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function destroy(Category $category);
|
public function destroy(Category $category);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of Categories appended with the amount of money that has been earned
|
||||||
|
* in these categories, based on the $accounts involved, in period X.
|
||||||
|
* The amount earned in category X in period X is saved in field "earned".
|
||||||
|
*
|
||||||
|
* @param $accounts
|
||||||
|
* @param $start
|
||||||
|
* @param $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function earnedForAccounts(Collection $accounts, Carbon $start, Carbon $end);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of Categories appended with the amount of money that has been spent
|
||||||
|
* in these categories, based on the $accounts involved, in period X.
|
||||||
|
* The amount earned in category X in period X is saved in field "spent".
|
||||||
|
*
|
||||||
|
* @param $accounts
|
||||||
|
* @param $start
|
||||||
|
* @param $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function spentForAccounts(Collection $accounts, Carbon $start, Carbon $end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function getCategories();
|
public function getCategories();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates how much is spent in this period.
|
||||||
|
*
|
||||||
|
* @param Category $category
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function spentInPeriodForAccounts(Category $category, Collection $accounts, Carbon $start, Carbon $end);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate how much is earned in this period.
|
||||||
|
*
|
||||||
|
* @param Category $category
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function earnedInPeriodForAccounts(Category $category, Collection $accounts, Carbon $start, Carbon $end);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount spent without category by accounts in period.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function spentNoCategoryForAccounts(Collection $accounts, Carbon $start, Carbon $end);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount earned without category by accounts in period.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function earnedNoCategoryForAccounts(Collection $accounts, Carbon $start, Carbon $end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Corrected for tags.
|
* Corrected for tags.
|
||||||
*
|
*
|
||||||
@@ -47,7 +120,7 @@ interface CategoryRepositoryInterface
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getCategoriesAndExpensesCorrected(Carbon $start, Carbon $end);
|
public function getCategoriesAndExpenses(Carbon $start, Carbon $end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Category $category
|
* @param Category $category
|
||||||
@@ -73,12 +146,13 @@ interface CategoryRepositoryInterface
|
|||||||
public function getJournalsInRange(Category $category, $page, Carbon $start, Carbon $end);
|
public function getJournalsInRange(Category $category, $page, Carbon $start, Carbon $end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* This method returns the sum of the journals in the category, optionally
|
* This method returns the sum of the journals in the category, optionally
|
||||||
* limited by a start or end date.
|
* limited by a start or end date.
|
||||||
*
|
*
|
||||||
* @param Category $category
|
* @param Category $category
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@@ -100,17 +174,16 @@ interface CategoryRepositoryInterface
|
|||||||
public function getWithoutCategory(Carbon $start, Carbon $end);
|
public function getWithoutCategory(Carbon $start, Carbon $end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Corrected for tags.
|
* Corrected for tags and list of accounts.
|
||||||
*
|
*
|
||||||
* @param Category $category
|
* @param Category $category
|
||||||
* @param \Carbon\Carbon $start
|
* @param \Carbon\Carbon $start
|
||||||
* @param \Carbon\Carbon $end
|
* @param \Carbon\Carbon $end
|
||||||
*
|
* @param Collection $accounts
|
||||||
* @param bool $shared
|
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function balanceInPeriod(Category $category, Carbon $start, Carbon $end, $shared = false);
|
public function balanceInPeriod(Category $category, Carbon $start, Carbon $end, Collection $accounts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Category $category
|
* @param Category $category
|
||||||
@@ -143,7 +216,7 @@ interface CategoryRepositoryInterface
|
|||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
public function spentOnDaySumCorrected(Category $category, Carbon $date);
|
public function spentOnDaySum(Category $category, Carbon $date);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -154,7 +227,7 @@ interface CategoryRepositoryInterface
|
|||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
public function earnedOnDaySumCorrected(Category $category, Carbon $date);
|
public function earnedOnDaySum(Category $category, Carbon $date);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use FireflyIII\Models\Tag;
|
|||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Log;
|
use Log;
|
||||||
@@ -44,7 +45,16 @@ class JournalRepository implements JournalRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function first()
|
public function first()
|
||||||
{
|
{
|
||||||
return Auth::user()->transactionjournals()->orderBy('date', 'ASC')->first(['transaction_journals.*']);
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('user-first-journal');
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
$entry = Auth::user()->transactionjournals()->orderBy('date', 'ASC')->first(['transaction_journals.*']);
|
||||||
|
$cache->store($entry);
|
||||||
|
|
||||||
|
return $entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -164,7 +174,7 @@ class JournalRepository implements JournalRepositoryInterface
|
|||||||
[
|
[
|
||||||
'user_id' => $data['user'],
|
'user_id' => $data['user'],
|
||||||
'transaction_type_id' => $transactionType->id,
|
'transaction_type_id' => $transactionType->id,
|
||||||
'transaction_currency_id' => $data['amount_currency_id'],
|
'transaction_currency_id' => $data['amount_currency_id_amount'],
|
||||||
'description' => $data['description'],
|
'description' => $data['description'],
|
||||||
'completed' => 0,
|
'completed' => 0,
|
||||||
'date' => $data['date'],
|
'date' => $data['date'],
|
||||||
@@ -327,15 +337,15 @@ class JournalRepository implements JournalRepositoryInterface
|
|||||||
$fromAccount = null;
|
$fromAccount = null;
|
||||||
$toAccount = null;
|
$toAccount = null;
|
||||||
switch ($type->type) {
|
switch ($type->type) {
|
||||||
case 'Withdrawal':
|
case TransactionType::WITHDRAWAL:
|
||||||
list($fromAccount, $toAccount) = $this->storeWithdrawalAccounts($data);
|
list($fromAccount, $toAccount) = $this->storeWithdrawalAccounts($data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Deposit':
|
case TransactionType::DEPOSIT:
|
||||||
list($fromAccount, $toAccount) = $this->storeDepositAccounts($data);
|
list($fromAccount, $toAccount) = $this->storeDepositAccounts($data);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'Transfer':
|
case TransactionType::TRANSFER:
|
||||||
$fromAccount = Account::find($data['account_from_id']);
|
$fromAccount = Account::find($data['account_from_id']);
|
||||||
$toAccount = Account::find($data['account_to_id']);
|
$toAccount = Account::find($data['account_to_id']);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,149 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace FireflyIII\Repositories\PiggyBank;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use FireflyIII\Models\PiggyBankRepetition;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class PiggyBankPart
|
|
||||||
*
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
* @package FireflyIII\Collection
|
|
||||||
*/
|
|
||||||
class PiggyBankPart
|
|
||||||
{
|
|
||||||
/** @var float */
|
|
||||||
public $amountPerBar;
|
|
||||||
/** @var float */
|
|
||||||
public $cumulativeAmount;
|
|
||||||
/** @var float */
|
|
||||||
public $currentamount;
|
|
||||||
|
|
||||||
/** @var PiggyBankRepetition */
|
|
||||||
public $repetition;
|
|
||||||
|
|
||||||
/** @var Carbon */
|
|
||||||
public $startdate;
|
|
||||||
|
|
||||||
/** @var Carbon */
|
|
||||||
public $targetdate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return PiggyBankRepetition
|
|
||||||
*/
|
|
||||||
public function getRepetition()
|
|
||||||
{
|
|
||||||
return $this->repetition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param PiggyBankRepetition $repetition
|
|
||||||
*/
|
|
||||||
public function setRepetition($repetition)
|
|
||||||
{
|
|
||||||
$this->repetition = $repetition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Carbon
|
|
||||||
*/
|
|
||||||
public function getStartdate()
|
|
||||||
{
|
|
||||||
return $this->startdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Carbon $startdate
|
|
||||||
*/
|
|
||||||
public function setStartdate($startdate)
|
|
||||||
{
|
|
||||||
$this->startdate = $startdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Carbon
|
|
||||||
*/
|
|
||||||
public function getTargetdate()
|
|
||||||
{
|
|
||||||
return $this->targetdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Carbon $targetdate
|
|
||||||
*/
|
|
||||||
public function setTargetdate($targetdate)
|
|
||||||
{
|
|
||||||
$this->targetdate = $targetdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return float|int
|
|
||||||
*/
|
|
||||||
public function percentage()
|
|
||||||
{
|
|
||||||
bcscale(2);
|
|
||||||
if ($this->getCurrentamount() < $this->getCumulativeAmount()) {
|
|
||||||
$pct = 0;
|
|
||||||
// calculate halfway point?
|
|
||||||
if (bcsub($this->getCumulativeAmount(), $this->getCurrentamount()) < $this->getAmountPerBar()) {
|
|
||||||
$left = $this->getCurrentamount() % $this->getAmountPerBar();
|
|
||||||
$pct = round($left / $this->getAmountPerBar() * 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $pct;
|
|
||||||
} else {
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return float
|
|
||||||
*/
|
|
||||||
public function getCurrentamount()
|
|
||||||
{
|
|
||||||
return $this->currentamount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param float $currentamount
|
|
||||||
*/
|
|
||||||
public function setCurrentamount($currentamount)
|
|
||||||
{
|
|
||||||
$this->currentamount = $currentamount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return float
|
|
||||||
*/
|
|
||||||
public function getCumulativeAmount()
|
|
||||||
{
|
|
||||||
return $this->cumulativeAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param float $cumulativeAmount
|
|
||||||
*/
|
|
||||||
public function setCumulativeAmount($cumulativeAmount)
|
|
||||||
{
|
|
||||||
$this->cumulativeAmount = $cumulativeAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return float
|
|
||||||
*/
|
|
||||||
public function getAmountPerBar()
|
|
||||||
{
|
|
||||||
return $this->amountPerBar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param float $amountPerBar
|
|
||||||
*/
|
|
||||||
public function setAmountPerBar($amountPerBar)
|
|
||||||
{
|
|
||||||
$this->amountPerBar = $amountPerBar;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -3,8 +3,11 @@
|
|||||||
namespace FireflyIII\Repositories\Shared;
|
namespace FireflyIII\Repositories\Shared;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Database\Query\JoinClause;
|
use Illuminate\Database\Query\JoinClause;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ComponentRepository
|
* Class ComponentRepository
|
||||||
@@ -14,46 +17,42 @@ use Illuminate\Database\Query\JoinClause;
|
|||||||
class ComponentRepository
|
class ComponentRepository
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $object
|
* @param $object
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
*
|
* @param Collection $accounts
|
||||||
* @param bool $shared
|
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function commonBalanceInPeriod($object, Carbon $start, Carbon $end, $shared = false)
|
protected function commonBalanceInPeriod($object, Carbon $start, Carbon $end, Collection $accounts)
|
||||||
{
|
{
|
||||||
$cache = new CacheProperties; // we must cache this.
|
$cache = new CacheProperties; // we must cache this.
|
||||||
$cache->addProperty($object->id);
|
$cache->addProperty($object->id);
|
||||||
$cache->addProperty(get_class($object));
|
$cache->addProperty(get_class($object));
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty($shared);
|
$cache->addProperty($accounts);
|
||||||
$cache->addProperty('balanceInPeriod');
|
$cache->addProperty('balanceInPeriodList');
|
||||||
|
|
||||||
|
$ids = [];
|
||||||
|
/** @var Account $account */
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$ids[] = $account->id;
|
||||||
|
}
|
||||||
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return $cache->get(); // @codeCoverageIgnore
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($shared === true) { // shared is true: always ignore transfers between accounts!
|
$sum = $object->transactionjournals()
|
||||||
$sum = $object->transactionjournals()->transactionTypes(['Withdrawal', 'Deposit', 'Opening balance'])->before($end)->after($start)
|
->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE])
|
||||||
->get(['transaction_journals.*'])->sum('amount');
|
->before($end)
|
||||||
} else {
|
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
// do something else, SEE budgets.
|
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
||||||
// get all journals in this month where the asset account is NOT shared.
|
->whereIn('accounts.id', $ids)
|
||||||
$sum = $object->transactionjournals()->before($end)->after($start)
|
->after($start)
|
||||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
->get(['transaction_journals.*'])->sum('amount');
|
||||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
|
||||||
->transactionTypes(['Withdrawal', 'Deposit', 'Opening balance'])
|
|
||||||
->leftJoin(
|
|
||||||
'account_meta', function (JoinClause $join) {
|
|
||||||
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
|
|
||||||
}
|
|
||||||
)->where('account_meta.data', '!=', '"sharedAsset"')->get(['transaction_journals.*'])->sum('amount');
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache->store($sum);
|
$cache->store($sum);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use FireflyIII\Models\Account;
|
|||||||
use FireflyIII\Models\Tag;
|
use FireflyIII\Models\Tag;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,6 +55,7 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* This method scans the transaction journals from or to the given asset account
|
* This method scans the transaction journals from or to the given asset account
|
||||||
* and checks if these are part of a balancing act. If so, it will sum up the amounts
|
* and checks if these are part of a balancing act. If so, it will sum up the amounts
|
||||||
* transferred into the balancing act (if any) and return this amount.
|
* transferred into the balancing act (if any) and return this amount.
|
||||||
@@ -77,7 +79,9 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
|
|
||||||
/** @var Tag $tag */
|
/** @var Tag $tag */
|
||||||
foreach ($tags as $tag) {
|
foreach ($tags as $tag) {
|
||||||
$journals = $tag->transactionjournals()->after($start)->before($end)->transactionTypes(['Transfer'])->get(['transaction_journals.*']);
|
$journals = $tag->transactionjournals()->after($start)->before($end)->transactionTypes([TransactionType::TRANSFER])->get(
|
||||||
|
['transaction_journals.*']
|
||||||
|
);
|
||||||
|
|
||||||
/** @var TransactionJournal $journal */
|
/** @var TransactionJournal $journal */
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
@@ -108,6 +112,13 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function get()
|
public function get()
|
||||||
{
|
{
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('tags-list');
|
||||||
|
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get();
|
||||||
|
}
|
||||||
|
|
||||||
/** @var Collection $tags */
|
/** @var Collection $tags */
|
||||||
$tags = Auth::user()->tags()->get();
|
$tags = Auth::user()->tags()->get();
|
||||||
$tags = $tags->sortBy(
|
$tags = $tags->sortBy(
|
||||||
@@ -116,6 +127,8 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$cache->store($tags);
|
||||||
|
|
||||||
return $tags;
|
return $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +171,7 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
|
|
||||||
if ($tag->tagMode == 'balancingAct' || $tag->tagMode == 'nothing') {
|
if ($tag->tagMode == 'balancingAct' || $tag->tagMode == 'nothing') {
|
||||||
foreach ($tag->transactionjournals as $journal) {
|
foreach ($tag->transactionjournals as $journal) {
|
||||||
if ($journal->transactionType->type == 'Transfer') {
|
if ($journal->isTransfer()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,7 +182,7 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
$count = 0;
|
$count = 0;
|
||||||
foreach ($tag->transactionjournals as $journal) {
|
foreach ($tag->transactionjournals as $journal) {
|
||||||
if ($journal->transactionType->type == 'Withdrawal') {
|
if ($journal->isWithdrawal()) {
|
||||||
$count++;
|
$count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,7 +214,7 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
* If any transaction is a deposit, cannot become a balancing act.
|
* If any transaction is a deposit, cannot become a balancing act.
|
||||||
*/
|
*/
|
||||||
foreach ($tag->transactionjournals as $journal) {
|
foreach ($tag->transactionjournals as $journal) {
|
||||||
if ($journal->transactionType->type == 'Deposit') {
|
if ($journal->isDeposit()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,10 +252,10 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
protected function connectBalancingAct(TransactionJournal $journal, Tag $tag)
|
protected function connectBalancingAct(TransactionJournal $journal, Tag $tag)
|
||||||
{
|
{
|
||||||
/** @var TransactionType $withdrawal */
|
/** @var TransactionType $withdrawal */
|
||||||
$withdrawal = TransactionType::whereType('Withdrawal')->first();
|
$withdrawal = TransactionType::whereType(TransactionType::WITHDRAWAL)->first();
|
||||||
$withdrawals = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->count();
|
$withdrawals = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->count();
|
||||||
/** @var TransactionType $transfer */
|
/** @var TransactionType $transfer */
|
||||||
$transfer = TransactionType::whereType('Transfer')->first();
|
$transfer = TransactionType::whereType(TransactionType::TRANSFER)->first();
|
||||||
$transfers = $tag->transactionjournals()->where('transaction_type_id', $transfer->id)->count();
|
$transfers = $tag->transactionjournals()->where('transaction_type_id', $transfer->id)->count();
|
||||||
|
|
||||||
|
|
||||||
@@ -275,11 +288,11 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
protected function connectAdvancePayment(TransactionJournal $journal, Tag $tag)
|
protected function connectAdvancePayment(TransactionJournal $journal, Tag $tag)
|
||||||
{
|
{
|
||||||
/** @var TransactionType $transfer */
|
/** @var TransactionType $transfer */
|
||||||
$transfer = TransactionType::whereType('Transfer')->first();
|
$transfer = TransactionType::whereType(TransactionType::TRANSFER)->first();
|
||||||
/** @var TransactionType $withdrawal */
|
/** @var TransactionType $withdrawal */
|
||||||
$withdrawal = TransactionType::whereType('Withdrawal')->first();
|
$withdrawal = TransactionType::whereType(TransactionType::WITHDRAWAL)->first();
|
||||||
/** @var TransactionType $deposit */
|
/** @var TransactionType $deposit */
|
||||||
$deposit = TransactionType::whereType('Deposit')->first();
|
$deposit = TransactionType::whereType(TransactionType::DEPOSIT)->first();
|
||||||
|
|
||||||
$withdrawals = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->count();
|
$withdrawals = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->count();
|
||||||
$deposits = $tag->transactionjournals()->where('transaction_type_id', $deposit->id)->count();
|
$deposits = $tag->transactionjournals()->where('transaction_type_id', $deposit->id)->count();
|
||||||
@@ -326,10 +339,10 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
foreach ($tag->transactionjournals as $check) {
|
foreach ($tag->transactionjournals as $check) {
|
||||||
// $checkAccount is the source_account for a withdrawal
|
// $checkAccount is the source_account for a withdrawal
|
||||||
// $checkAccount is the destination_account for a deposit
|
// $checkAccount is the destination_account for a deposit
|
||||||
if ($check->transactionType->type == 'Withdrawal' && $check->source_account->id != $journal->destination_account->id) {
|
if ($check->isWithdrawal() && $check->source_account->id != $journal->destination_account->id) {
|
||||||
$match = false;
|
$match = false;
|
||||||
}
|
}
|
||||||
if ($check->transactionType->type == 'Deposit' && $check->destination_account->id != $journal->destination_account->id) {
|
if ($check->isDeposit() && $check->destination_account->id != $journal->destination_account->id) {
|
||||||
$match = false;
|
$match = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ interface TagRepositoryInterface
|
|||||||
public function connect(TransactionJournal $journal, Tag $tag);
|
public function connect(TransactionJournal $journal, Tag $tag);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* This method scans the transaction journals from or to the given asset account
|
* This method scans the transaction journals from or to the given asset account
|
||||||
* and checks if these are part of a balancing act. If so, it will sum up the amounts
|
* and checks if these are part of a balancing act. If so, it will sum up the amounts
|
||||||
* transferred into the balancing act (if any) and return this amount.
|
* transferred into the balancing act (if any) and return this amount.
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class Amount
|
|||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return $cache->get();
|
return $cache->get();
|
||||||
} else {
|
} else {
|
||||||
$currencyPreference = Prefs::get('currencyPreference', 'EUR');
|
$currencyPreference = Prefs::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR'));
|
||||||
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||||
|
|
||||||
$cache->store($currency->symbol);
|
$cache->store($currency->symbol);
|
||||||
@@ -60,7 +60,7 @@ class Amount
|
|||||||
{
|
{
|
||||||
$amount = floatval($amount);
|
$amount = floatval($amount);
|
||||||
$amount = round($amount, 2);
|
$amount = round($amount, 2);
|
||||||
$string = number_format($amount, 2, ',', '.');
|
$string = money_format('%!.2n', $amount);
|
||||||
|
|
||||||
if ($coloured === true) {
|
if ($coloured === true) {
|
||||||
if ($amount === 0.0) {
|
if ($amount === 0.0) {
|
||||||
@@ -100,13 +100,13 @@ class Amount
|
|||||||
$symbol = $journal->symbol;
|
$symbol = $journal->symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($journal->transactionType->type == 'Transfer' && $coloured) {
|
if ($journal->isTransfer() && $coloured) {
|
||||||
$txt = '<span class="text-info">' . $this->formatWithSymbol($symbol, $journal->amount_positive, false) . '</span>';
|
$txt = '<span class="text-info">' . $this->formatWithSymbol($symbol, $journal->amount_positive, false) . '</span>';
|
||||||
$cache->store($txt);
|
$cache->store($txt);
|
||||||
|
|
||||||
return $txt;
|
return $txt;
|
||||||
}
|
}
|
||||||
if ($journal->transactionType->type == 'Transfer' && !$coloured) {
|
if ($journal->isTransfer() && !$coloured) {
|
||||||
$txt = $this->formatWithSymbol($symbol, $journal->amount_positive, false);
|
$txt = $this->formatWithSymbol($symbol, $journal->amount_positive, false);
|
||||||
$cache->store($txt);
|
$cache->store($txt);
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ class Amount
|
|||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return $cache->get();
|
return $cache->get();
|
||||||
} else {
|
} else {
|
||||||
$currencyPreference = Prefs::get('currencyPreference', 'EUR');
|
$currencyPreference = Prefs::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR'));
|
||||||
|
|
||||||
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||||
if ($currency) {
|
if ($currency) {
|
||||||
@@ -161,9 +161,9 @@ class Amount
|
|||||||
|
|
||||||
return $currency->code;
|
return $currency->code;
|
||||||
}
|
}
|
||||||
$cache->store('EUR');
|
$cache->store(env('DEFAULT_CURRENCY', 'EUR'));
|
||||||
|
|
||||||
return 'EUR'; // @codeCoverageIgnore
|
return env('DEFAULT_CURRENCY', 'EUR'); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,54 @@ class Steam
|
|||||||
return round($balance, 2);
|
return round($balance, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the balance for the given account during the whole range, using this format:
|
||||||
|
*
|
||||||
|
* [yyyy-mm-dd] => 123,2
|
||||||
|
*
|
||||||
|
* @param Account $account
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*/
|
||||||
|
public function balanceInRange(Account $account, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
// abuse chart properties:
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($account->id);
|
||||||
|
$cache->addProperty('balance-in-range');
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
$balances = [];
|
||||||
|
$start->subDay();
|
||||||
|
$end->addDay();
|
||||||
|
$startBalance = $this->balance($account, $start);
|
||||||
|
$balances[$start->format('Y-m-d')] = $startBalance;
|
||||||
|
$start->addDay();
|
||||||
|
|
||||||
|
// query!
|
||||||
|
$set = $account->transactions()
|
||||||
|
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||||
|
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||||
|
->groupBy('transaction_journals.date')
|
||||||
|
->get(['transaction_journals.date', DB::Raw('SUM(`transactions`.`amount`) as `modified`')]);
|
||||||
|
$currentBalance = $startBalance;
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$currentBalance = bcadd($currentBalance, $entry->modified);
|
||||||
|
$balances[$entry->date] = $currentBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cache->store($balances);
|
||||||
|
|
||||||
|
return $balances;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param array $ids
|
* @param array $ids
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ class Budget extends Twig_Extension
|
|||||||
{
|
{
|
||||||
$functions = [];
|
$functions = [];
|
||||||
$functions[] = new Twig_SimpleFunction(
|
$functions[] = new Twig_SimpleFunction(
|
||||||
'spentInRepetitionCorrected', function (LimitRepetition $repetition) {
|
'spentInRepetition', function (LimitRepetition $repetition) {
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty($repetition->id);
|
$cache->addProperty($repetition->id);
|
||||||
$cache->addProperty('spentInRepetitionCorrected');
|
$cache->addProperty('spentInRepetition');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return $cache->get(); // @codeCoverageIgnore
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,19 +68,17 @@ class Journal extends Twig_Extension
|
|||||||
return $cache->get(); // @codeCoverageIgnore
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$type = $journal->transactionType->type;
|
switch (true) {
|
||||||
|
case $journal->isWithdrawal():
|
||||||
switch ($type) {
|
|
||||||
case 'Withdrawal':
|
|
||||||
$txt = '<i class="fa fa-long-arrow-left fa-fw" title="' . trans('firefly.withdrawal') . '"></i>';
|
$txt = '<i class="fa fa-long-arrow-left fa-fw" title="' . trans('firefly.withdrawal') . '"></i>';
|
||||||
break;
|
break;
|
||||||
case 'Deposit':
|
case $journal->isDeposit():
|
||||||
$txt = '<i class="fa fa-long-arrow-right fa-fw" title="' . trans('firefly.deposit') . '"></i>';
|
$txt = '<i class="fa fa-long-arrow-right fa-fw" title="' . trans('firefly.deposit') . '"></i>';
|
||||||
break;
|
break;
|
||||||
case 'Transfer':
|
case $journal->isTransfer():
|
||||||
$txt = '<i class="fa fa-fw fa-exchange" title="' . trans('firefly.transfer') . '"></i>';
|
$txt = '<i class="fa fa-fw fa-exchange" title="' . trans('firefly.transfer') . '"></i>';
|
||||||
break;
|
break;
|
||||||
case 'Opening balance':
|
case $journal->isOpeningBalance():
|
||||||
$txt = '<i class="fa-fw fa fa-ban" title="' . trans('firefly.openingBalance') . '"></i>';
|
$txt = '<i class="fa-fw fa fa-ban" title="' . trans('firefly.openingBalance') . '"></i>';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -189,7 +187,7 @@ class Journal extends Twig_Extension
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($tag->tagMode == 'advancePayment') {
|
if ($tag->tagMode == 'advancePayment') {
|
||||||
if ($journal->transactionType->type == 'Deposit') {
|
if ($journal->isDeposit()) {
|
||||||
$amount = app('amount')->formatJournal($journal, false);
|
$amount = app('amount')->formatJournal($journal, false);
|
||||||
$string = '<a href="' . route('tags.show', [$tag->id]) . '" class="label label-success" title="' . $amount
|
$string = '<a href="' . route('tags.show', [$tag->id]) . '" class="label label-success" title="' . $amount
|
||||||
. '"><i class="fa fa-fw fa-sort-numeric-desc"></i> ' . $tag->tag . '</a>';
|
. '"><i class="fa fa-fw fa-sort-numeric-desc"></i> ' . $tag->tag . '</a>';
|
||||||
@@ -201,7 +199,7 @@ class Journal extends Twig_Extension
|
|||||||
* AdvancePayment with a withdrawal will show the amount with a link to
|
* AdvancePayment with a withdrawal will show the amount with a link to
|
||||||
* the tag. The TransactionJournal should properly calculate the amount.
|
* the tag. The TransactionJournal should properly calculate the amount.
|
||||||
*/
|
*/
|
||||||
if ($journal->transactionType->type == 'Withdrawal') {
|
if ($journal->isWithdrawal()) {
|
||||||
$amount = app('amount')->formatJournal($journal);
|
$amount = app('amount')->formatJournal($journal);
|
||||||
|
|
||||||
$string = '<a href="' . route('tags.show', [$tag->id]) . '">' . $amount . '</a>';
|
$string = '<a href="' . route('tags.show', [$tag->id]) . '">' . $amount . '</a>';
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ class FireflyValidator extends Validator
|
|||||||
|
|
||||||
// get entries from table
|
// get entries from table
|
||||||
$set = DB::table($table)->where('user_id', Auth::user()->id)
|
$set = DB::table($table)->where('user_id', Auth::user()->id)
|
||||||
->where('id', '!=', $exclude)->get([$field]);
|
->where('id', '!=', $exclude)->get([$field]);
|
||||||
|
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
$fieldValue = $this->tryDecrypt($entry->$field);
|
$fieldValue = $this->tryDecrypt($entry->$field);
|
||||||
|
|||||||
737
composer.lock
generated
737
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'locale' => 'en',
|
'locale' => 'en_US',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -65,7 +65,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'fallback_locale' => 'en',
|
'fallback_locale' => 'en_US',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -139,8 +139,8 @@ return [
|
|||||||
'TwigBridge\ServiceProvider',
|
'TwigBridge\ServiceProvider',
|
||||||
|
|
||||||
'DaveJamesMiller\Breadcrumbs\ServiceProvider',
|
'DaveJamesMiller\Breadcrumbs\ServiceProvider',
|
||||||
//'Barryvdh\Debugbar\ServiceProvider',
|
// 'Barryvdh\Debugbar\ServiceProvider',
|
||||||
//'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
|
// 'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
|
||||||
'Zizaco\Entrust\EntrustServiceProvider',
|
'Zizaco\Entrust\EntrustServiceProvider',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ return [
|
|||||||
|
|
||||||
'sqlite' => [
|
'sqlite' => [
|
||||||
'driver' => 'sqlite',
|
'driver' => 'sqlite',
|
||||||
'database' => __DIR__ . '/../storage/database/testing.db',
|
'database' => storage_path('database/testing.db'),
|
||||||
'prefix' => '',
|
'prefix' => '',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'chart' => 'chartjs',
|
'chart' => 'chartjs',
|
||||||
'version' => '3.5.2',
|
'version' => '3.5.5',
|
||||||
'index_periods' => ['1D', '1W', '1M', '3M', '6M', '1Y', 'custom'],
|
'index_periods' => ['1D', '1W', '1M', '3M', '6M', '1Y', 'custom'],
|
||||||
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
|
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
|
||||||
'csv_import_enabled' => true,
|
'csv_import_enabled' => true,
|
||||||
'maxUploadSize' => 5242880,
|
'maxUploadSize' => 5242880,
|
||||||
'allowedMimes' => ['image/png', 'image/jpeg', 'application/pdf'],
|
'allowedMimes' => ['image/png', 'image/jpeg', 'application/pdf'],
|
||||||
'piggy_bank_periods' => [
|
'piggy_bank_periods' => [
|
||||||
'week' => 'Week',
|
'week' => 'Week',
|
||||||
'month' => 'Month',
|
'month' => 'Month',
|
||||||
'quarter' => 'Quarter',
|
'quarter' => 'Quarter',
|
||||||
'year' => 'Year'
|
'year' => 'Year'
|
||||||
],
|
],
|
||||||
'periods_to_text' => [
|
'periods_to_text' => [
|
||||||
'weekly' => 'A week',
|
'weekly' => 'A week',
|
||||||
'monthly' => 'A month',
|
'monthly' => 'A month',
|
||||||
'quarterly' => 'A quarter',
|
'quarterly' => 'A quarter',
|
||||||
@@ -22,7 +22,7 @@ return [
|
|||||||
'yearly' => 'A year',
|
'yearly' => 'A year',
|
||||||
],
|
],
|
||||||
|
|
||||||
'accountRoles' => [
|
'accountRoles' => [
|
||||||
'defaultAsset' => 'Default asset account',
|
'defaultAsset' => 'Default asset account',
|
||||||
'sharedAsset' => 'Shared asset account',
|
'sharedAsset' => 'Shared asset account',
|
||||||
'savingAsset' => 'Savings account',
|
'savingAsset' => 'Savings account',
|
||||||
@@ -98,13 +98,23 @@ return [
|
|||||||
'Revenue account' => 'revenue',
|
'Revenue account' => 'revenue',
|
||||||
'Cash account' => 'cash',
|
'Cash account' => 'cash',
|
||||||
],
|
],
|
||||||
|
'languages' => [
|
||||||
|
'en_US' => ['name_locale' => 'English', 'name_english' => 'English', 'complete' => true],
|
||||||
|
'nl_NL' => ['name_locale' => 'Nederlands', 'name_english' => 'Dutch', 'complete' => true],
|
||||||
|
'pt_BR' => ['name_locale' => 'Português do Brasil', 'name_english' => 'Portugese (Brazil)', 'complete' => false],
|
||||||
|
'fr_FR' => ['name_locale' => 'Français', 'name_english' => 'French', 'complete' => false],
|
||||||
|
],
|
||||||
'lang' => [
|
'lang' => [
|
||||||
'en' => 'English',
|
'en_US' => 'English',
|
||||||
'nl' => 'Nederlands'
|
'nl_NL' => 'Nederlands',
|
||||||
|
'fr_FR' => 'Français',
|
||||||
|
'pt_BR' => 'Português do Brasil',
|
||||||
],
|
],
|
||||||
'locales' => [
|
'locales' => [
|
||||||
'en' => ['en', 'English', 'en_US', 'en_US.utf8'],
|
'en_US' => ['en', 'English', 'en_US', 'en_US.utf8'],
|
||||||
'nl' => ['nl', 'Dutch', 'nl_NL', 'nl_NL.utf8'],
|
'nl_NL' => ['nl', 'Dutch', 'nl_NL', 'nl_NL.utf8'],
|
||||||
|
'pt_BR' => ['pt_BR', 'pt_BR.utf8'],
|
||||||
|
'fr_FR' => ['fr_FR', 'fr_FR.utf8'],
|
||||||
],
|
],
|
||||||
'transactionTypesByWhat' => [
|
'transactionTypesByWhat' => [
|
||||||
'expenses' => ['Withdrawal'],
|
'expenses' => ['Withdrawal'],
|
||||||
@@ -124,13 +134,17 @@ return [
|
|||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'month' => [
|
'month' => [
|
||||||
'en' => '%B %Y',
|
'en_US' => '%B %Y',
|
||||||
'nl' => '%B %Y',
|
'nl_NL' => '%B %Y',
|
||||||
|
'fr_FR' => '%B %Y',
|
||||||
|
'pt_BR' => '%B %Y',
|
||||||
],
|
],
|
||||||
'monthAndDay' => [
|
'monthAndDay' => [
|
||||||
'en' => '%B %e, %Y',
|
'en_US' => '%B %e, %Y',
|
||||||
'nl' => '%e %B %Y',
|
'nl_NL' => '%e %B %Y',
|
||||||
|
'fr_FR' => '%B %e, %Y',
|
||||||
|
'pt_BR' => '%B %e, %Y',
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'driver' => env('EMAIL_DRIVER', 'smtp'),
|
'blocked_domains' => explode(',', env('BLOCKED_DOMAINS')),
|
||||||
|
'driver' => env('EMAIL_DRIVER', 'smtp'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -28,7 +29,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'host' => env('EMAIL_SMTP', 'smtp.mailgun.org'),
|
'host' => env('EMAIL_SMTP', 'smtp.mailgun.org'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -41,7 +42,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'port' => 587,
|
'port' => 587,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -54,7 +55,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'from' => ['address' => env('EMAIL_USERNAME', null), 'name' => 'Firefly III Mailer'],
|
'from' => ['address' => env('EMAIL_USERNAME', null), 'name' => 'Firefly III Mailer'],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -80,7 +81,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'username' => env('EMAIL_USERNAME', null),
|
'username' => env('EMAIL_USERNAME', null),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -93,7 +94,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'password' => env('EMAIL_PASSWORD', null),
|
'password' => env('EMAIL_PASSWORD', null),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -106,7 +107,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'sendmail' => '/usr/sbin/sendmail -bs',
|
'sendmail' => '/usr/sbin/sendmail -bs',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -119,6 +120,6 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'pretend' => env('EMAIL_PRETEND', false),
|
'pretend' => env('EMAIL_PRETEND', false),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class TestDataSeeder extends Seeder
|
|||||||
$this->createPiggybanks();
|
$this->createPiggybanks();
|
||||||
|
|
||||||
// dates:
|
// dates:
|
||||||
$start = Carbon::now()->subyear()->startOfMonth();
|
$start = Carbon::now()->subYears(5)->startOfMonth();
|
||||||
$end = Carbon::now()->endOfDay();
|
$end = Carbon::now()->endOfDay();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ class TransactionTypeSeeder extends Seeder
|
|||||||
|
|
||||||
DB::table('transaction_types')->delete();
|
DB::table('transaction_types')->delete();
|
||||||
|
|
||||||
TransactionType::create(['type' => 'Withdrawal']);
|
TransactionType::create(['type' => TransactionType::WITHDRAWAL]);
|
||||||
TransactionType::create(['type' => 'Deposit']);
|
TransactionType::create(['type' => TransactionType::DEPOSIT]);
|
||||||
TransactionType::create(['type' => 'Transfer']);
|
TransactionType::create(['type' => TransactionType::TRANSFER]);
|
||||||
TransactionType::create(['type' => 'Opening balance']);
|
TransactionType::create(['type' => TransactionType::OPENING_BALANCE]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
4
public/dist/css/AdminLTE.min.css
vendored
4
public/dist/css/AdminLTE.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
.skin-blue-light .main-header .navbar{background-color:#3c8dbc}.skin-blue-light .main-header .navbar .nav>li>a{color:#fff}.skin-blue-light .main-header .navbar .nav>li>a:hover,.skin-blue-light .main-header .navbar .nav>li>a:active,.skin-blue-light .main-header .navbar .nav>li>a:focus,.skin-blue-light .main-header .navbar .nav .open>a,.skin-blue-light .main-header .navbar .nav .open>a:hover,.skin-blue-light .main-header .navbar .nav .open>a:focus{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-blue-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-blue-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue-light .main-header .navbar .sidebar-toggle:hover{background-color:#367fa9}@media (max-width:767px){.skin-blue-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-blue-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-blue-light .main-header .navbar .dropdown-menu li a:hover{background:#367fa9}}.skin-blue-light .main-header .logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue-light .main-header .logo:hover{background-color:#3b8ab8}.skin-blue-light .main-header li.user-header{background-color:#3c8dbc}.skin-blue-light .content-header{background:transparent}.skin-blue-light .wrapper,.skin-blue-light .main-sidebar,.skin-blue-light .left-side{background-color:#f9fafc}.skin-blue-light .content-wrapper,.skin-blue-light .main-footer{border-left:1px solid #d2d6de}.skin-blue-light .user-panel>.info,.skin-blue-light .user-panel>.info>a{color:#444}.skin-blue-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-blue-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-blue-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-blue-light .sidebar-menu>li:hover>a,.skin-blue-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-blue-light .sidebar-menu>li.active{border-left-color:#3c8dbc}.skin-blue-light .sidebar-menu>li.active>a{font-weight:600}.skin-blue-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-blue-light .sidebar a{color:#444}.skin-blue-light .sidebar a:hover{text-decoration:none}.skin-blue-light .treeview-menu>li>a{color:#777}.skin-blue-light .treeview-menu>li.active>a,.skin-blue-light .treeview-menu>li>a:hover{color:#000}.skin-blue-light .treeview-menu>li.active>a{font-weight:600}.skin-blue-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-blue-light .sidebar-form input[type="text"],.skin-blue-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-blue-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px !important;border-top-right-radius:0 !important;border-bottom-right-radius:0 !important;border-bottom-left-radius:2px !important}.skin-blue-light .sidebar-form input[type="text"]:focus,.skin-blue-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-blue-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-blue-light .sidebar-form .btn{color:#999;border-top-left-radius:0 !important;border-top-right-radius:2px !important;border-bottom-right-radius:2px !important;border-bottom-left-radius:0 !important}@media (min-width:768px){.skin-blue-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}.skin-blue-light .main-footer{border-top-color:#d2d6de}.skin-blue.layout-top-nav .main-header>.logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue.layout-top-nav .main-header>.logo:hover{background-color:#3b8ab8}
|
.skin-blue-light .main-header .navbar{background-color:#3c8dbc}.skin-blue-light .main-header .navbar .nav>li>a{color:#fff}.skin-blue-light .main-header .navbar .nav>li>a:hover,.skin-blue-light .main-header .navbar .nav>li>a:active,.skin-blue-light .main-header .navbar .nav>li>a:focus,.skin-blue-light .main-header .navbar .nav .open>a,.skin-blue-light .main-header .navbar .nav .open>a:hover,.skin-blue-light .main-header .navbar .nav .open>a:focus,.skin-blue-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-blue-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-blue-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue-light .main-header .navbar .sidebar-toggle:hover{background-color:#367fa9}@media (max-width:767px){.skin-blue-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-blue-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-blue-light .main-header .navbar .dropdown-menu li a:hover{background:#367fa9}}.skin-blue-light .main-header .logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue-light .main-header .logo:hover{background-color:#3b8ab8}.skin-blue-light .main-header li.user-header{background-color:#3c8dbc}.skin-blue-light .content-header{background:transparent}.skin-blue-light .wrapper,.skin-blue-light .main-sidebar,.skin-blue-light .left-side{background-color:#f9fafc}.skin-blue-light .content-wrapper,.skin-blue-light .main-footer{border-left:1px solid #d2d6de}.skin-blue-light .user-panel>.info,.skin-blue-light .user-panel>.info>a{color:#444}.skin-blue-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-blue-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-blue-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-blue-light .sidebar-menu>li:hover>a,.skin-blue-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-blue-light .sidebar-menu>li.active{border-left-color:#3c8dbc}.skin-blue-light .sidebar-menu>li.active>a{font-weight:600}.skin-blue-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-blue-light .sidebar a{color:#444}.skin-blue-light .sidebar a:hover{text-decoration:none}.skin-blue-light .treeview-menu>li>a{color:#777}.skin-blue-light .treeview-menu>li.active>a,.skin-blue-light .treeview-menu>li>a:hover{color:#000}.skin-blue-light .treeview-menu>li.active>a{font-weight:600}.skin-blue-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-blue-light .sidebar-form input[type="text"],.skin-blue-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-blue-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-blue-light .sidebar-form input[type="text"]:focus,.skin-blue-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-blue-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-blue-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-blue-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}.skin-blue-light .main-footer{border-top-color:#d2d6de}.skin-blue.layout-top-nav .main-header>.logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue.layout-top-nav .main-header>.logo:hover{background-color:#3b8ab8}
|
||||||
BIN
public/dist/img/icons.png
vendored
BIN
public/dist/img/icons.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.1 KiB |
4
public/dist/js/app.min.js
vendored
4
public/dist/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
4
public/js/accounting.min.js
vendored
Normal file
4
public/js/accounting.min.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/*!
|
||||||
|
* accounting.js v0.4.2, copyright 2014 Open Exchange Rates, MIT license, http://openexchangerates.github.io/accounting.js
|
||||||
|
*/
|
||||||
|
(function(p,z){function q(a){return!!(""===a||a&&a.charCodeAt&&a.substr)}function m(a){return u?u(a):"[object Array]"===v.call(a)}function r(a){return"[object Object]"===v.call(a)}function s(a,b){var d,a=a||{},b=b||{};for(d in b)b.hasOwnProperty(d)&&null==a[d]&&(a[d]=b[d]);return a}function j(a,b,d){var c=[],e,h;if(!a)return c;if(w&&a.map===w)return a.map(b,d);for(e=0,h=a.length;e<h;e++)c[e]=b.call(d,a[e],e,a);return c}function n(a,b){a=Math.round(Math.abs(a));return isNaN(a)?b:a}function x(a){var b=c.settings.currency.format;"function"===typeof a&&(a=a());return q(a)&&a.match("%v")?{pos:a,neg:a.replace("-","").replace("%v","-%v"),zero:a}:!a||!a.pos||!a.pos.match("%v")?!q(b)?b:c.settings.currency.format={pos:b,neg:b.replace("%v","-%v"),zero:b}:a}var c={version:"0.4.1",settings:{currency:{symbol:"$",format:"%s%v",decimal:".",thousand:",",precision:2,grouping:3},number:{precision:0,grouping:3,thousand:",",decimal:"."}}},w=Array.prototype.map,u=Array.isArray,v=Object.prototype.toString,o=c.unformat=c.parse=function(a,b){if(m(a))return j(a,function(a){return o(a,b)});a=a||0;if("number"===typeof a)return a;var b=b||".",c=RegExp("[^0-9-"+b+"]",["g"]),c=parseFloat((""+a).replace(/\((.*)\)/,"-$1").replace(c,"").replace(b,"."));return!isNaN(c)?c:0},y=c.toFixed=function(a,b){var b=n(b,c.settings.number.precision),d=Math.pow(10,b);return(Math.round(c.unformat(a)*d)/d).toFixed(b)},t=c.formatNumber=c.format=function(a,b,d,i){if(m(a))return j(a,function(a){return t(a,b,d,i)});var a=o(a),e=s(r(b)?b:{precision:b,thousand:d,decimal:i},c.settings.number),h=n(e.precision),f=0>a?"-":"",g=parseInt(y(Math.abs(a||0),h),10)+"",l=3<g.length?g.length%3:0;return f+(l?g.substr(0,l)+e.thousand:"")+g.substr(l).replace(/(\d{3})(?=\d)/g,"$1"+e.thousand)+(h?e.decimal+y(Math.abs(a),h).split(".")[1]:"")},A=c.formatMoney=function(a,b,d,i,e,h){if(m(a))return j(a,function(a){return A(a,b,d,i,e,h)});var a=o(a),f=s(r(b)?b:{symbol:b,precision:d,thousand:i,decimal:e,format:h},c.settings.currency),g=x(f.format);return(0<a?g.pos:0>a?g.neg:g.zero).replace("%s",f.symbol).replace("%v",t(Math.abs(a),n(f.precision),f.thousand,f.decimal))};c.formatColumn=function(a,b,d,i,e,h){if(!a)return[];var f=s(r(b)?b:{symbol:b,precision:d,thousand:i,decimal:e,format:h},c.settings.currency),g=x(f.format),l=g.pos.indexOf("%s")<g.pos.indexOf("%v")?!0:!1,k=0,a=j(a,function(a){if(m(a))return c.formatColumn(a,f);a=o(a);a=(0<a?g.pos:0>a?g.neg:g.zero).replace("%s",f.symbol).replace("%v",t(Math.abs(a),n(f.precision),f.thousand,f.decimal));if(a.length>k)k=a.length;return a});return j(a,function(a){return q(a)&&a.length<k?l?a.replace(f.symbol,f.symbol+Array(k-a.length+1).join(" ")):Array(k-a.length+1).join(" ")+a:a})};if("undefined"!==typeof exports){if("undefined"!==typeof module&&module.exports)exports=module.exports=c;exports.accounting=c}else"function"===typeof define&&define.amd?define([],function(){return c}):(c.noConflict=function(a){return function(){p.accounting=a;c.noConflict=z;return c}}(p.accounting),p.accounting=c)})(this);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* globals $, Chart, currencySymbol */
|
/* globals $, Chart, currencySymbol,mon_decimal_point ,accounting, mon_thousands_sep, frac_digits */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Make some colours:
|
Make some colours:
|
||||||
@@ -24,6 +24,23 @@ var colourSet = [
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Settings object that controls default parameters for library methods:
|
||||||
|
accounting.settings = {
|
||||||
|
currency: {
|
||||||
|
symbol : currencySymbol, // default currency symbol is '$'
|
||||||
|
format: "%s %v", // controls output: %s = symbol, %v = value/number (can be object: see below)
|
||||||
|
decimal : mon_decimal_point, // decimal point separator
|
||||||
|
thousand: mon_thousands_sep, // thousands separator
|
||||||
|
precision : frac_digits // decimal places
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
precision : 0, // default precision on numbers is 0
|
||||||
|
thousand: ",",
|
||||||
|
decimal : "."
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
var fillColors = [];
|
var fillColors = [];
|
||||||
var strokePointHighColors = [];
|
var strokePointHighColors = [];
|
||||||
|
|
||||||
@@ -45,9 +62,9 @@ var defaultAreaOptions = {
|
|||||||
animation: false,
|
animation: false,
|
||||||
scaleFontSize: 10,
|
scaleFontSize: 10,
|
||||||
responsive: false,
|
responsive: false,
|
||||||
scaleLabel: " <%= '" + currencySymbol + " ' + Number(value).toFixed(0).replace('.', ',') %>",
|
scaleLabel: " <%= accounting.formatMoney(value) %>",
|
||||||
tooltipFillColor: "rgba(0,0,0,0.5)",
|
tooltipFillColor: "rgba(0,0,0,0.5)",
|
||||||
multiTooltipTemplate: "<%=datasetLabel%>: <%= '" + currencySymbol + " ' + Number(value).toFixed(2).replace('.', ',') %>"
|
multiTooltipTemplate: "<%=datasetLabel%>: <%= accounting.formatMoney(value) %>"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -61,7 +78,7 @@ var defaultPieOptions = {
|
|||||||
scaleFontSize: 10,
|
scaleFontSize: 10,
|
||||||
responsive: false,
|
responsive: false,
|
||||||
tooltipFillColor: "rgba(0,0,0,0.5)",
|
tooltipFillColor: "rgba(0,0,0,0.5)",
|
||||||
tooltipTemplate: "<%if (label){%><%=label%>: <%}%>" + currencySymbol + " <%= value %>",
|
tooltipTemplate: "<%if (label){%><%=label%>: <%}%> <%= accounting.formatMoney(value) %>",
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -90,10 +107,10 @@ var defaultColumnOptions = {
|
|||||||
scaleFontSize: 10,
|
scaleFontSize: 10,
|
||||||
responsive: false,
|
responsive: false,
|
||||||
animation: false,
|
animation: false,
|
||||||
scaleLabel: "<%= '" + currencySymbol + " ' + Number(value).toFixed(0).replace('.', ',') %>",
|
scaleLabel: "<%= accounting.formatMoney(value) %>",
|
||||||
tooltipFillColor: "rgba(0,0,0,0.5)",
|
tooltipFillColor: "rgba(0,0,0,0.5)",
|
||||||
tooltipTemplate: "<%if (label){%><%=label%>: <%}%>" + currencySymbol + " <%= value %>",
|
tooltipTemplate: "<%if (label){%><%=label%>: <%}%> <%= accounting.formatMoney(value) %>",
|
||||||
multiTooltipTemplate: "<%=datasetLabel%>: " + currencySymbol + " <%= Number(value).toFixed(2).replace('.', ',') %>"
|
multiTooltipTemplate: "<%=datasetLabel%>: <%= accounting.formatMoney(value) %>"
|
||||||
};
|
};
|
||||||
|
|
||||||
var defaultStackedColumnOptions = {
|
var defaultStackedColumnOptions = {
|
||||||
@@ -105,9 +122,9 @@ var defaultStackedColumnOptions = {
|
|||||||
animation: false,
|
animation: false,
|
||||||
scaleFontSize: 10,
|
scaleFontSize: 10,
|
||||||
responsive: false,
|
responsive: false,
|
||||||
scaleLabel: "<%= '" + currencySymbol + " ' + Number(value).toFixed(0).replace('.', ',') %>",
|
scaleLabel: "<%= accounting.formatMoney(value) %>",
|
||||||
tooltipFillColor: "rgba(0,0,0,0.5)",
|
tooltipFillColor: "rgba(0,0,0,0.5)",
|
||||||
multiTooltipTemplate: "<%=datasetLabel%>: " + currencySymbol + " <%= Number(value).toFixed(2).replace('.', ',') %>"
|
multiTooltipTemplate: "<%=datasetLabel%>: <%= accounting.formatMoney(value) %>"
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
/* globals token, dateRangeConfig, $, */
|
/* globals token, dateRangeConfig, $, */
|
||||||
$(function () {
|
$(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
$('.currencySelect').click(currencySelect);
|
|
||||||
|
// when you click on a currency, this happens:
|
||||||
|
$('.currency-option').click(currencySelect);
|
||||||
|
|
||||||
var ranges = {};
|
var ranges = {};
|
||||||
// range for the current month:
|
// range for the current month:
|
||||||
@@ -62,21 +64,51 @@ $(function () {
|
|||||||
|
|
||||||
function currencySelect(e) {
|
function currencySelect(e) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var target = $(e.target);
|
// clicked on
|
||||||
|
var target = $(e.target); // target is the <A> tag.
|
||||||
|
|
||||||
|
// name of the field in question:
|
||||||
|
var name = target.data('name');
|
||||||
|
|
||||||
|
// id of menu button (used later on):
|
||||||
|
var menuID = 'currency_dropdown_' + name;
|
||||||
|
|
||||||
|
// the hidden input with the actual value of the selected currency:
|
||||||
|
var hiddenInputName = 'amount_currency_id_' + target.data('name');
|
||||||
|
|
||||||
|
// span with the current selection (next to the caret):
|
||||||
|
var spanId = 'currency_select_symbol_' + target.data('name');
|
||||||
|
|
||||||
|
// the selected currency symbol:
|
||||||
var symbol = target.data('symbol');
|
var symbol = target.data('symbol');
|
||||||
var code = target.data('code');
|
|
||||||
|
// id of the selected currency.
|
||||||
var id = target.data('id');
|
var id = target.data('id');
|
||||||
var fieldType = target.data('field');
|
|
||||||
var menu = $('.' + fieldType + 'CurrencyDropdown');
|
|
||||||
|
|
||||||
var symbolHolder = $('#' + fieldType + 'CurrentSymbol');
|
// update the hidden input:
|
||||||
symbolHolder.text(symbol);
|
$('input[name="' + hiddenInputName + '"]').val(id);
|
||||||
$('input[name="' + fieldType + '_currency_id"]').val(id);
|
|
||||||
|
|
||||||
// close dropdown (hack hack)
|
// update the symbol:
|
||||||
menu.click();
|
$('#' + spanId).text(symbol);
|
||||||
|
|
||||||
|
// close the menu (hack hack)
|
||||||
|
$('#' + menuID).click();
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
//var code = target.data('code');
|
||||||
|
//var fieldType = target.data('field');
|
||||||
|
//var menu = $('.' + fieldType + 'CurrencyDropdown');
|
||||||
|
//
|
||||||
|
//var symbolHolder = $('#' + fieldType + 'CurrentSymbol');
|
||||||
|
//symbolHolder.text(symbol);
|
||||||
|
//$('input[name="' + fieldType + '_currency_id"]').val(id);
|
||||||
|
//
|
||||||
|
// close dropdown (hack hack)
|
||||||
|
//menu.click();
|
||||||
|
|
||||||
|
|
||||||
|
//return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
/* globals google, expenseRestShow:true, incomeRestShow:true, year, shared, month, hideTheRest, showTheRest, showTheRestExpense, hideTheRestExpense, columnChart, lineChart, stackedColumnChart */
|
|
||||||
|
|
||||||
$(function () {
|
|
||||||
"use strict";
|
|
||||||
drawChart();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
function drawChart() {
|
|
||||||
"use strict";
|
|
||||||
if (typeof columnChart !== 'undefined' && typeof year !== 'undefined' && typeof month === 'undefined') {
|
|
||||||
columnChart('chart/report/in-out/' + year + shared, 'income-expenses-chart');
|
|
||||||
columnChart('chart/report/in-out-sum/' + year + shared, 'income-expenses-sum-chart');
|
|
||||||
}
|
|
||||||
if (typeof stackedColumnChart !== 'undefined' && typeof year !== 'undefined' && typeof month === 'undefined') {
|
|
||||||
stackedColumnChart('chart/budget/year/' + year + shared, 'budgets');
|
|
||||||
stackedColumnChart('chart/category/spent-in-year/' + year + shared, 'categories-spent-in-year');
|
|
||||||
stackedColumnChart('chart/category/earned-in-year/' + year + shared, 'categories-earned-in-year');
|
|
||||||
}
|
|
||||||
if (typeof lineChart !== 'undefined' && typeof month !== 'undefined') {
|
|
||||||
lineChart('/chart/account/month/' + year + '/' + month + shared, 'account-balances-chart');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function openModal(e) {
|
|
||||||
"use strict";
|
|
||||||
var target = $(e.target).parent();
|
|
||||||
var URL = target.attr('href');
|
|
||||||
|
|
||||||
$.get(URL).success(function (data) {
|
|
||||||
$('#defaultModal').empty().html(data).modal('show');
|
|
||||||
|
|
||||||
}).fail(function () {
|
|
||||||
alert('Could not load data.');
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function showIncomes() {
|
|
||||||
"use strict";
|
|
||||||
if (incomeRestShow) {
|
|
||||||
// hide everything, make button say "show"
|
|
||||||
$('#showIncomes').text(showTheRest);
|
|
||||||
$('.incomesCollapsed').removeClass('in').addClass('out');
|
|
||||||
|
|
||||||
// toggle:
|
|
||||||
incomeRestShow = false;
|
|
||||||
} else {
|
|
||||||
// show everything, make button say "hide".
|
|
||||||
$('#showIncomes').text(hideTheRest);
|
|
||||||
$('.incomesCollapsed').removeClass('out').addClass('in');
|
|
||||||
|
|
||||||
// toggle:
|
|
||||||
incomeRestShow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function showExpenses() {
|
|
||||||
"use strict";
|
|
||||||
if (expenseRestShow) {
|
|
||||||
// hide everything, make button say "show"
|
|
||||||
$('#showExpenses').text(showTheRestExpense);
|
|
||||||
$('.expenseCollapsed').removeClass('in').addClass('out');
|
|
||||||
|
|
||||||
// toggle:
|
|
||||||
expenseRestShow = false;
|
|
||||||
} else {
|
|
||||||
// show everything, make button say "hide".
|
|
||||||
$('#showExpenses').text(hideTheRestExpense);
|
|
||||||
$('.expenseCollapsed').removeClass('out').addClass('in');
|
|
||||||
|
|
||||||
// toggle:
|
|
||||||
expenseRestShow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(function () {
|
|
||||||
"use strict";
|
|
||||||
$('.openModal').on('click', openModal);
|
|
||||||
|
|
||||||
|
|
||||||
// click open the top X income list:
|
|
||||||
$('#showIncomes').click(showIncomes);
|
|
||||||
// click open the top X expense list:
|
|
||||||
$('#showExpenses').click(showExpenses);
|
|
||||||
});
|
|
||||||
64
public/js/reports/default/month.js
Normal file
64
public/js/reports/default/month.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/* globals google, startDate ,reportURL, endDate , reportType ,accountIds , picker:true, minDate, expenseRestShow:true, incomeRestShow:true, year, month, hideTheRest, showTheRest, showTheRestExpense, hideTheRestExpense, columnChart, lineChart, stackedColumnChart */
|
||||||
|
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
"use strict";
|
||||||
|
drawChart();
|
||||||
|
|
||||||
|
// click open the top X income list:
|
||||||
|
$('#showIncomes').click(showIncomes);
|
||||||
|
// click open the top X expense list:
|
||||||
|
$('#showExpenses').click(showExpenses);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function drawChart() {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// month view:
|
||||||
|
// draw account chart
|
||||||
|
lineChart('/chart/account/report/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'account-balances-chart');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showIncomes() {
|
||||||
|
"use strict";
|
||||||
|
if (incomeRestShow) {
|
||||||
|
// hide everything, make button say "show"
|
||||||
|
$('#showIncomes').text(showTheRest);
|
||||||
|
$('.incomesCollapsed').removeClass('in').addClass('out');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
incomeRestShow = false;
|
||||||
|
} else {
|
||||||
|
// show everything, make button say "hide".
|
||||||
|
$('#showIncomes').text(hideTheRest);
|
||||||
|
$('.incomesCollapsed').removeClass('out').addClass('in');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
incomeRestShow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showExpenses() {
|
||||||
|
"use strict";
|
||||||
|
if (expenseRestShow) {
|
||||||
|
// hide everything, make button say "show"
|
||||||
|
$('#showExpenses').text(showTheRestExpense);
|
||||||
|
$('.expenseCollapsed').removeClass('in').addClass('out');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
expenseRestShow = false;
|
||||||
|
} else {
|
||||||
|
// show everything, make button say "hide".
|
||||||
|
$('#showExpenses').text(hideTheRestExpense);
|
||||||
|
$('.expenseCollapsed').removeClass('out').addClass('in');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
expenseRestShow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
155
public/js/reports/default/multi-year.js
Normal file
155
public/js/reports/default/multi-year.js
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/* globals google, startDate ,reportURL, endDate , reportType ,accountIds , picker:true, minDate, expenseRestShow:true, incomeRestShow:true, year, month, hideTheRest, showTheRest, showTheRestExpense, hideTheRestExpense, columnChart, lineChart, stackedColumnChart */
|
||||||
|
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
"use strict";
|
||||||
|
drawChart();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function drawChart() {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// income and expense over multi year:
|
||||||
|
columnChart('chart/report/in-out/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'income-expenses-chart');
|
||||||
|
columnChart('chart/report/in-out-sum/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'income-expenses-sum-chart');
|
||||||
|
|
||||||
|
|
||||||
|
$.each($('.account-chart'), function (i, v) {
|
||||||
|
var holder = $(v);
|
||||||
|
console.log('Will draw chart for account #' + holder.data('id'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// draw budget chart based on selected budgets:
|
||||||
|
$('.budget-checkbox').on('change', updateBudgetChart);
|
||||||
|
selectBudgetsByCookie();
|
||||||
|
updateBudgetChart();
|
||||||
|
|
||||||
|
// draw category chart based on selected budgets:
|
||||||
|
$('.category-checkbox').on('change', updateCategoryChart);
|
||||||
|
selectCategoriesByCookie();
|
||||||
|
updateCategoryChart();
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectBudgetsByCookie() {
|
||||||
|
"use strict";
|
||||||
|
var cookie = readCookie('multi-year-budgets');
|
||||||
|
if (cookie !== null) {
|
||||||
|
var cookieArray = cookie.split(',');
|
||||||
|
for (var x in cookieArray) {
|
||||||
|
var budgetId = cookieArray[x];
|
||||||
|
$('.budget-checkbox[value="' + budgetId + '"').prop('checked', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectCategoriesByCookie() {
|
||||||
|
"use strict";
|
||||||
|
var cookie = readCookie('multi-year-categories');
|
||||||
|
if (cookie !== null) {
|
||||||
|
var cookieArray = cookie.split(',');
|
||||||
|
for (var x in cookieArray) {
|
||||||
|
var categoryId = cookieArray[x];
|
||||||
|
$('.category-checkbox[value="' + categoryId + '"').prop('checked', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBudgetChart() {
|
||||||
|
"use strict";
|
||||||
|
console.log('will update budget chart.');
|
||||||
|
// get all budget ids:
|
||||||
|
var budgets = [];
|
||||||
|
$.each($('.budget-checkbox'), function (i, v) {
|
||||||
|
var current = $(v);
|
||||||
|
if (current.prop('checked')) {
|
||||||
|
budgets.push(current.val());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (budgets.length > 0) {
|
||||||
|
|
||||||
|
var budgetIds = budgets.join(',');
|
||||||
|
|
||||||
|
// remove old chart:
|
||||||
|
$('#budgets-chart').replaceWith('<canvas id="budgets-chart" class="budgets-chart" style="width:100%;height:400px;"></canvas>');
|
||||||
|
|
||||||
|
// hide message:
|
||||||
|
$('#budgets-chart-message').hide();
|
||||||
|
|
||||||
|
// draw chart. Redraw when exists? Not sure if we support that.
|
||||||
|
columnChart('chart/budget/multi-year/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds + '/' + budgetIds, 'budgets-chart');
|
||||||
|
createCookie('multi-year-budgets', budgets, 365);
|
||||||
|
} else {
|
||||||
|
// hide canvas, show message:
|
||||||
|
$('#budgets-chart-message').show();
|
||||||
|
$('#budgets-chart').hide();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCategoryChart() {
|
||||||
|
"use strict";
|
||||||
|
console.log('will update category chart.');
|
||||||
|
// get all category ids:
|
||||||
|
var categories = [];
|
||||||
|
$.each($('.category-checkbox'), function (i, v) {
|
||||||
|
var current = $(v);
|
||||||
|
if (current.prop('checked')) {
|
||||||
|
categories.push(current.val());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (categories.length > 0) {
|
||||||
|
|
||||||
|
var categoryIds = categories.join(',');
|
||||||
|
|
||||||
|
// remove old chart:
|
||||||
|
$('#categories-chart').replaceWith('<canvas id="categories-chart" class="budgets-chart" style="width:100%;height:400px;"></canvas>');
|
||||||
|
|
||||||
|
// hide message:
|
||||||
|
$('#categories-chart-message').hide();
|
||||||
|
|
||||||
|
// draw chart. Redraw when exists? Not sure if we support that.
|
||||||
|
columnChart('chart/category/multi-year/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds + '/' + categoryIds, 'categories-chart');
|
||||||
|
createCookie('multi-year-categories', categories, 365);
|
||||||
|
} else {
|
||||||
|
// hide canvas, show message:
|
||||||
|
$('#categories-chart-message').show();
|
||||||
|
$('#categories-chart').hide();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createCookie(name, value, days) {
|
||||||
|
"use strict";
|
||||||
|
var expires;
|
||||||
|
|
||||||
|
if (days) {
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||||
|
expires = "; expires=" + date.toGMTString();
|
||||||
|
} else {
|
||||||
|
expires = "";
|
||||||
|
}
|
||||||
|
document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/";
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCookie(name) {
|
||||||
|
"use strict";
|
||||||
|
var nameEQ = encodeURIComponent(name) + "=";
|
||||||
|
var ca = document.cookie.split(';');
|
||||||
|
for (var i = 0; i < ca.length; i++) {
|
||||||
|
var c = ca[i];
|
||||||
|
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
|
||||||
|
if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length, c.length));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function eraseCookie(name) {
|
||||||
|
createCookie(name, "", -1);
|
||||||
|
}
|
||||||
208
public/js/reports/default/reports.js
Normal file
208
public/js/reports/default/reports.js
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/* globals google, startDate ,reportURL, endDate , reportType ,accountIds , picker:true, minDate, expenseRestShow:true, incomeRestShow:true, year, month, hideTheRest, showTheRest, showTheRestExpense, hideTheRestExpense, columnChart, lineChart, stackedColumnChart */
|
||||||
|
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
"use strict";
|
||||||
|
drawChart();
|
||||||
|
|
||||||
|
if ($('#inputDateRange').length > 0) {
|
||||||
|
|
||||||
|
picker = $('#inputDateRange').daterangepicker(
|
||||||
|
{
|
||||||
|
locale: {
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
firstDay: 1,
|
||||||
|
},
|
||||||
|
minDate: minDate,
|
||||||
|
drops: 'up',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// set values from cookies, if any:
|
||||||
|
if (readCookie('report-type') !== null) {
|
||||||
|
$('select[name="report_type"]').val(readCookie('report-type'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((readCookie('report-accounts') !== null)) {
|
||||||
|
var arr = readCookie('report-accounts').split(',');
|
||||||
|
arr.forEach(function (val) {
|
||||||
|
$('input[type="checkbox"][value="' + val + '"]').prop('checked', true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// set date:
|
||||||
|
var startStr = readCookie('report-start');
|
||||||
|
var endStr = readCookie('report-end');
|
||||||
|
if (startStr !== null && endStr !== null && startStr.length == 8 && endStr.length == 8) {
|
||||||
|
var startDate = moment(startStr, "YYYYMMDD");
|
||||||
|
var endDate = moment(endStr, "YYYYMMDD");
|
||||||
|
var datePicker = $('#inputDateRange').data('daterangepicker');
|
||||||
|
datePicker.setStartDate(startDate);
|
||||||
|
datePicker.setEndDate(endDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('.openModal').on('click', openModal);
|
||||||
|
|
||||||
|
$('.date-select').on('click', preSelectDate);
|
||||||
|
|
||||||
|
$('#report-form').on('submit', catchSubmit);
|
||||||
|
|
||||||
|
|
||||||
|
// click open the top X income list:
|
||||||
|
$('#showIncomes').click(showIncomes);
|
||||||
|
// click open the top X expense list:
|
||||||
|
$('#showExpenses').click(showExpenses);
|
||||||
|
});
|
||||||
|
|
||||||
|
function catchSubmit() {
|
||||||
|
"use strict";
|
||||||
|
// default;20141201;20141231;4;5
|
||||||
|
// report name:
|
||||||
|
var url = '' + $('select[name="report_type"]').val() + '/';
|
||||||
|
|
||||||
|
// date, processed:
|
||||||
|
var picker = $('#inputDateRange').data('daterangepicker');
|
||||||
|
url += moment(picker.startDate).format("YYYYMMDD") + '/';
|
||||||
|
url += moment(picker.endDate).format("YYYYMMDD") + '/';
|
||||||
|
|
||||||
|
// all account ids:
|
||||||
|
var count = 0;
|
||||||
|
var accounts = [];
|
||||||
|
$.each($('.account-checkbox'), function (i, v) {
|
||||||
|
var c = $(v);
|
||||||
|
if (c.prop('checked')) {
|
||||||
|
url += c.val() + ';';
|
||||||
|
accounts.push(c.val());
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (count > 0) {
|
||||||
|
// set cookie to remember choices.
|
||||||
|
createCookie('report-type', $('select[name="report_type"]').val(), 365);
|
||||||
|
createCookie('report-accounts', accounts, 365);
|
||||||
|
createCookie('report-start', moment(picker.startDate).format("YYYYMMDD"), 365);
|
||||||
|
createCookie('report-end', moment(picker.endDate).format("YYYYMMDD"), 365);
|
||||||
|
|
||||||
|
window.location.href = reportURL + "/" + url;
|
||||||
|
}
|
||||||
|
//console.log(url);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function preSelectDate(e) {
|
||||||
|
"use strict";
|
||||||
|
var link = $(e.target);
|
||||||
|
var picker = $('#inputDateRange').data('daterangepicker');
|
||||||
|
picker.setStartDate(link.data('start'));
|
||||||
|
picker.setEndDate(link.data('end'));
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawChart() {
|
||||||
|
"use strict";
|
||||||
|
if (typeof columnChart !== 'undefined' && typeof year !== 'undefined' && typeof month === 'undefined') {
|
||||||
|
|
||||||
|
columnChart('chart/report/in-out/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'income-expenses-chart');
|
||||||
|
columnChart('chart/report/in-out-sum/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'income-expenses-sum-chart');
|
||||||
|
}
|
||||||
|
if (typeof stackedColumnChart !== 'undefined' && typeof year !== 'undefined' && typeof month === 'undefined') {
|
||||||
|
stackedColumnChart('chart/budget/year/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'budgets');
|
||||||
|
stackedColumnChart('chart/category/spent-in-year/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'categories-spent-in-year');
|
||||||
|
stackedColumnChart('chart/category/earned-in-year/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'categories-earned-in-year');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof lineChart !== 'undefined' && typeof accountIds !== 'undefined') {
|
||||||
|
lineChart('/chart/account/report/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'account-balances-chart');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function openModal(e) {
|
||||||
|
"use strict";
|
||||||
|
var target = $(e.target).parent();
|
||||||
|
var URL = target.attr('href');
|
||||||
|
|
||||||
|
$.get(URL).success(function (data) {
|
||||||
|
$('#defaultModal').empty().html(data).modal('show');
|
||||||
|
|
||||||
|
}).fail(function () {
|
||||||
|
alert('Could not load data.');
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showIncomes() {
|
||||||
|
"use strict";
|
||||||
|
if (incomeRestShow) {
|
||||||
|
// hide everything, make button say "show"
|
||||||
|
$('#showIncomes').text(showTheRest);
|
||||||
|
$('.incomesCollapsed').removeClass('in').addClass('out');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
incomeRestShow = false;
|
||||||
|
} else {
|
||||||
|
// show everything, make button say "hide".
|
||||||
|
$('#showIncomes').text(hideTheRest);
|
||||||
|
$('.incomesCollapsed').removeClass('out').addClass('in');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
incomeRestShow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showExpenses() {
|
||||||
|
"use strict";
|
||||||
|
if (expenseRestShow) {
|
||||||
|
// hide everything, make button say "show"
|
||||||
|
$('#showExpenses').text(showTheRestExpense);
|
||||||
|
$('.expenseCollapsed').removeClass('in').addClass('out');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
expenseRestShow = false;
|
||||||
|
} else {
|
||||||
|
// show everything, make button say "hide".
|
||||||
|
$('#showExpenses').text(hideTheRestExpense);
|
||||||
|
$('.expenseCollapsed').removeClass('out').addClass('in');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
expenseRestShow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCookie(name, value, days) {
|
||||||
|
var expires;
|
||||||
|
|
||||||
|
if (days) {
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||||
|
expires = "; expires=" + date.toGMTString();
|
||||||
|
} else {
|
||||||
|
expires = "";
|
||||||
|
}
|
||||||
|
document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/";
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCookie(name) {
|
||||||
|
var nameEQ = encodeURIComponent(name) + "=";
|
||||||
|
var ca = document.cookie.split(';');
|
||||||
|
for (var i = 0; i < ca.length; i++) {
|
||||||
|
var c = ca[i];
|
||||||
|
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
|
||||||
|
if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length, c.length));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function eraseCookie(name) {
|
||||||
|
createCookie(name, "", -1);
|
||||||
|
}
|
||||||
67
public/js/reports/default/year.js
Normal file
67
public/js/reports/default/year.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/* globals google, startDate ,reportURL, endDate , reportType ,accountIds , picker:true, minDate, expenseRestShow:true, incomeRestShow:true, year, month, hideTheRest, showTheRest, showTheRestExpense, hideTheRestExpense, columnChart, lineChart, stackedColumnChart */
|
||||||
|
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
"use strict";
|
||||||
|
drawChart();
|
||||||
|
|
||||||
|
// click open the top X income list:
|
||||||
|
$('#showIncomes').click(showIncomes);
|
||||||
|
// click open the top X expense list:
|
||||||
|
$('#showExpenses').click(showExpenses);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function drawChart() {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
columnChart('chart/report/in-out/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'income-expenses-chart');
|
||||||
|
columnChart('chart/report/in-out-sum/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'income-expenses-sum-chart');
|
||||||
|
stackedColumnChart('chart/budget/year/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'budgets');
|
||||||
|
stackedColumnChart('chart/category/spent-in-period/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'categories-spent-in-period');
|
||||||
|
stackedColumnChart('chart/category/earned-in-period/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'categories-earned-in-period');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showIncomes() {
|
||||||
|
"use strict";
|
||||||
|
if (incomeRestShow) {
|
||||||
|
// hide everything, make button say "show"
|
||||||
|
$('#showIncomes').text(showTheRest);
|
||||||
|
$('.incomesCollapsed').removeClass('in').addClass('out');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
incomeRestShow = false;
|
||||||
|
} else {
|
||||||
|
// show everything, make button say "hide".
|
||||||
|
$('#showIncomes').text(hideTheRest);
|
||||||
|
$('.incomesCollapsed').removeClass('out').addClass('in');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
incomeRestShow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showExpenses() {
|
||||||
|
"use strict";
|
||||||
|
if (expenseRestShow) {
|
||||||
|
// hide everything, make button say "show"
|
||||||
|
$('#showExpenses').text(showTheRestExpense);
|
||||||
|
$('.expenseCollapsed').removeClass('in').addClass('out');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
expenseRestShow = false;
|
||||||
|
} else {
|
||||||
|
// show everything, make button say "hide".
|
||||||
|
$('#showExpenses').text(hideTheRestExpense);
|
||||||
|
$('.expenseCollapsed').removeClass('out').addClass('in');
|
||||||
|
|
||||||
|
// toggle:
|
||||||
|
expenseRestShow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
122
public/js/reports/index.js
Normal file
122
public/js/reports/index.js
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/* globals google, startDate ,reportURL, endDate , reportType ,accountIds , picker:true, minDate, expenseRestShow:true, incomeRestShow:true, year, month, hideTheRest, showTheRest, showTheRestExpense, hideTheRestExpense, columnChart, lineChart, stackedColumnChart */
|
||||||
|
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
if ($('#inputDateRange').length > 0) {
|
||||||
|
|
||||||
|
picker = $('#inputDateRange').daterangepicker(
|
||||||
|
{
|
||||||
|
locale: {
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
firstDay: 1,
|
||||||
|
},
|
||||||
|
minDate: minDate,
|
||||||
|
drops: 'up',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// set values from cookies, if any:
|
||||||
|
if (readCookie('report-type') !== null) {
|
||||||
|
$('select[name="report_type"]').val(readCookie('report-type'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((readCookie('report-accounts') !== null)) {
|
||||||
|
var arr = readCookie('report-accounts').split(',');
|
||||||
|
arr.forEach(function (val) {
|
||||||
|
$('input[type="checkbox"][value="' + val + '"]').prop('checked', true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// set date:
|
||||||
|
var startStr = readCookie('report-start');
|
||||||
|
var endStr = readCookie('report-end');
|
||||||
|
if (startStr !== null && endStr !== null && startStr.length == 8 && endStr.length == 8) {
|
||||||
|
var startDate = moment(startStr, "YYYYMMDD");
|
||||||
|
var endDate = moment(endStr, "YYYYMMDD");
|
||||||
|
var datePicker = $('#inputDateRange').data('daterangepicker');
|
||||||
|
datePicker.setStartDate(startDate);
|
||||||
|
datePicker.setEndDate(endDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('.date-select').on('click', preSelectDate);
|
||||||
|
$('#report-form').on('submit', catchSubmit);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function catchSubmit() {
|
||||||
|
"use strict";
|
||||||
|
// default;20141201;20141231;4;5
|
||||||
|
// report name:
|
||||||
|
var url = '' + $('select[name="report_type"]').val() + '/';
|
||||||
|
|
||||||
|
// date, processed:
|
||||||
|
var picker = $('#inputDateRange').data('daterangepicker');
|
||||||
|
url += moment(picker.startDate).format("YYYYMMDD") + '/';
|
||||||
|
url += moment(picker.endDate).format("YYYYMMDD") + '/';
|
||||||
|
|
||||||
|
// all account ids:
|
||||||
|
var count = 0;
|
||||||
|
var accounts = [];
|
||||||
|
$.each($('.account-checkbox'), function (i, v) {
|
||||||
|
var c = $(v);
|
||||||
|
if (c.prop('checked')) {
|
||||||
|
url += c.val() + ',';
|
||||||
|
accounts.push(c.val());
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (count > 0) {
|
||||||
|
// set cookie to remember choices.
|
||||||
|
createCookie('report-type', $('select[name="report_type"]').val(), 365);
|
||||||
|
createCookie('report-accounts', accounts, 365);
|
||||||
|
createCookie('report-start', moment(picker.startDate).format("YYYYMMDD"), 365);
|
||||||
|
createCookie('report-end', moment(picker.endDate).format("YYYYMMDD"), 365);
|
||||||
|
|
||||||
|
window.location.href = reportURL + "/" + url;
|
||||||
|
}
|
||||||
|
//console.log(url);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function preSelectDate(e) {
|
||||||
|
"use strict";
|
||||||
|
var link = $(e.target);
|
||||||
|
var picker = $('#inputDateRange').data('daterangepicker');
|
||||||
|
picker.setStartDate(link.data('start'));
|
||||||
|
picker.setEndDate(link.data('end'));
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createCookie(name, value, days) {
|
||||||
|
"use strict";
|
||||||
|
var expires;
|
||||||
|
|
||||||
|
if (days) {
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||||
|
expires = "; expires=" + date.toGMTString();
|
||||||
|
} else {
|
||||||
|
expires = "";
|
||||||
|
}
|
||||||
|
document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/";
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCookie(name) {
|
||||||
|
"use strict";
|
||||||
|
var nameEQ = encodeURIComponent(name) + "=";
|
||||||
|
var ca = document.cookie.split(';');
|
||||||
|
for (var i = 0; i < ca.length; i++) {
|
||||||
|
var c = ca[i];
|
||||||
|
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
|
||||||
|
if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length, c.length));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -27,8 +27,8 @@ return [
|
|||||||
|
|
||||||
// reports
|
// reports
|
||||||
'reports' => 'Reports',
|
'reports' => 'Reports',
|
||||||
'monthly_report' => 'Montly report for :date',
|
'monthly_report' => 'Monthly report for :date',
|
||||||
'monthly_report_shared' => 'Montly report for :date (including shared accounts)',
|
'monthly_report_shared' => 'Monthly report for :date (including shared accounts)',
|
||||||
'yearly_report' => 'Yearly report for :date',
|
'yearly_report' => 'Yearly report for :date',
|
||||||
'yearly_report_shared' => 'Yearly report for :date (including shared accounts)',
|
'yearly_report_shared' => 'Yearly report for :date (including shared accounts)',
|
||||||
'budget_report' => 'Budget report for :date',
|
'budget_report' => 'Budget report for :date',
|
||||||
8
resources/lang/en_US/config.php
Normal file
8
resources/lang/en_US/config.php
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'locale' => 'en, English, en_US, en_US.utf8',
|
||||||
|
'month' => '%B %Y',
|
||||||
|
'month_and_day' => '%B %e, %Y',
|
||||||
|
|
||||||
|
];
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
// general stuff:
|
// general stuff:
|
||||||
|
'language_incomplete' => 'This language is not yet fully translated',
|
||||||
'test' => 'You have selected English.',
|
'test' => 'You have selected English.',
|
||||||
'close' => 'Close',
|
'close' => 'Close',
|
||||||
'pleaseHold' => 'Please hold...',
|
'pleaseHold' => 'Please hold...',
|
||||||
@@ -22,6 +23,7 @@ return [
|
|||||||
'search_results_for' => 'Search results for ":query"',
|
'search_results_for' => 'Search results for ":query"',
|
||||||
'bounced_error' => 'The message sent to :email bounced, so no access for you.',
|
'bounced_error' => 'The message sent to :email bounced, so no access for you.',
|
||||||
'deleted_error' => 'These credentials do not match our records.',
|
'deleted_error' => 'These credentials do not match our records.',
|
||||||
|
'general_blocked_error' => 'Your account has been disabled, so you cannot login.',
|
||||||
'removed_amount' => 'Removed :amount',
|
'removed_amount' => 'Removed :amount',
|
||||||
'added_amount' => 'Added :amount',
|
'added_amount' => 'Added :amount',
|
||||||
'asset_account_role_help' => 'Any extra options resulting from your choice can be set later.',
|
'asset_account_role_help' => 'Any extra options resulting from your choice can be set later.',
|
||||||
@@ -66,8 +68,7 @@ return [
|
|||||||
'new_password' => 'New password',
|
'new_password' => 'New password',
|
||||||
'new_password_again' => 'New password (again)',
|
'new_password_again' => 'New password (again)',
|
||||||
'delete_your_account' => 'Delete your account',
|
'delete_your_account' => 'Delete your account',
|
||||||
'delete_your_account_help' => 'Deleting your account will also delete any accounts, transactions, <em>anything</em> you might have saved' .
|
'delete_your_account_help' => 'Deleting your account will also delete any accounts, transactions, <em>anything</em> you might have saved into Firefly III. It\'ll be GONE.',
|
||||||
' into Firefly III. It\'ll be GONE.',
|
|
||||||
'delete_your_account_password' => 'Enter your password to continue.',
|
'delete_your_account_password' => 'Enter your password to continue.',
|
||||||
'password' => 'Password',
|
'password' => 'Password',
|
||||||
'are_you_sure' => 'Are you sure? You cannot undo this.',
|
'are_you_sure' => 'Are you sure? You cannot undo this.',
|
||||||
@@ -108,23 +109,15 @@ return [
|
|||||||
'csv_define_column_roles' => 'Define column roles',
|
'csv_define_column_roles' => 'Define column roles',
|
||||||
'csv_map_values' => 'Map found values to existing values',
|
'csv_map_values' => 'Map found values to existing values',
|
||||||
'csv_download_config' => 'Download CSV configuration file.',
|
'csv_download_config' => 'Download CSV configuration file.',
|
||||||
'csv_index_text' => 'This form allows you to import a CSV file with transactions into Firefly. It is based on the excellent CSV' .
|
'csv_index_text' => 'This form allows you to import a CSV file with transactions into Firefly. It is based on the excellent CSV importer made by the folks at <a href="https://www.atlassian.com/">Atlassian</a>. Simply upload your CSV file and follow the instructions. If you would like to learn more, please click on the <i class="fa fa-question-circle"></i> button at the top of this page.',
|
||||||
' importer made by the folks at <a href="https://www.atlassian.com/">Atlassian</a>. Simply upload your CSV' .
|
|
||||||
' file and follow the instructions. If you would like to learn more, please click on the <i ' .
|
|
||||||
'class="fa fa-question-circle"></i> button at the top of this page.',
|
|
||||||
'csv_index_beta_warning' => 'This tool is very much in beta. Please proceed with caution',
|
'csv_index_beta_warning' => 'This tool is very much in beta. Please proceed with caution',
|
||||||
'csv_header_help' => 'Check this box when your CSV file\'s first row consists of column names, not actual data',
|
'csv_header_help' => 'Check this box when your CSV file\'s first row consists of column names, not actual data',
|
||||||
'csv_date_help' => 'Date time format in your CSV. Follow the format like <a href="https://secure.php.net/manual/en/' .
|
'csv_date_help' => 'Date time format in your CSV. Follow the format like <a href="https://secure.php.net/manual/en/datetime.createfromformat.php#refsect1-datetime.createfromformat-parameters">this page</a> indicates. The default value will parse dates that look like this: :dateExample.',
|
||||||
'datetime.createfromformat.php#refsect1-datetime.createfromformat-parameters">this page</a> ' .
|
|
||||||
'indicates. The default value will parse dates that look like this: ' . date('Ymd'),
|
|
||||||
'csv_csv_file_help' => 'Select the CSV file here. You can only upload one file at a time',
|
'csv_csv_file_help' => 'Select the CSV file here. You can only upload one file at a time',
|
||||||
'csv_csv_config_file_help' => 'Select your CSV import configuration here. If you do not know what this is, ignore it. It will be explained later.',
|
'csv_csv_config_file_help' => 'Select your CSV import configuration here. If you do not know what this is, ignore it. It will be explained later.',
|
||||||
'csv_upload_button' => 'Start importing CSV',
|
'csv_upload_button' => 'Start importing CSV',
|
||||||
'csv_column_roles_title' => 'Define column roles',
|
'csv_column_roles_title' => 'Define column roles',
|
||||||
'csv_column_roles_text' => 'Firefly does not know what each column means. You need to indicate what every column is. ' .
|
'csv_column_roles_text' => 'Firefly does not know what each column means. You need to indicate what every column is. Please check out the example data if you\'re not sure yourself. Click on the question mark (top right of the page) to learn what each column means. If you want to map imported data onto existing data in Firefly, use the checkbox. The next step will show you what this button does.',
|
||||||
'Please check out the example data if you\'re not sure yourself. Click on the question mark ' .
|
|
||||||
'(top right of the page) to learn what each column means. If you want to map imported data ' .
|
|
||||||
'onto existing data in Firefly, use the checkbox. The next step will show you what this button does.',
|
|
||||||
'csv_column_roles_table' => 'Column roles',
|
'csv_column_roles_table' => 'Column roles',
|
||||||
'csv_column' => 'CSV column',
|
'csv_column' => 'CSV column',
|
||||||
'csv_column_name' => 'CSV column name',
|
'csv_column_name' => 'CSV column name',
|
||||||
@@ -134,15 +127,13 @@ return [
|
|||||||
'csv_continue' => 'Continue to the next step',
|
'csv_continue' => 'Continue to the next step',
|
||||||
'csv_go_back' => 'Go back to the previous step',
|
'csv_go_back' => 'Go back to the previous step',
|
||||||
'csv_map_title' => 'Map found values to existing values',
|
'csv_map_title' => 'Map found values to existing values',
|
||||||
'csv_map_text' => 'This page allows you to map the values from the CSV file to existing entries in your ' .
|
'csv_map_text' => 'This page allows you to map the values from the CSV file to existing entries in your database. This ensures that accounts and other things won\'t be created twice.',
|
||||||
'database. This ensures that accounts and other things won\'t be created twice.',
|
|
||||||
'csv_field_value' => 'Field value from CSV',
|
'csv_field_value' => 'Field value from CSV',
|
||||||
'csv_field_mapped_to' => 'Must be mapped to...',
|
'csv_field_mapped_to' => 'Must be mapped to...',
|
||||||
'csv_do_not_map' => 'Do not map this value',
|
'csv_do_not_map' => 'Do not map this value',
|
||||||
'csv_download_config_title' => 'Download CSV configuration',
|
'csv_download_config_title' => 'Download CSV configuration',
|
||||||
'csv_download_config_text' => 'Everything you\'ve just set up can be downloaded as a configuration file. Click the button to do so.',
|
'csv_download_config_text' => 'Everything you\'ve just set up can be downloaded as a configuration file. Click the button to do so.',
|
||||||
'csv_more_information_text' => 'If the import fails, you can use this configuration file so you don\'t have to start all ' .
|
'csv_more_information_text' => 'If the import fails, you can use this configuration file so you don\'t have to start all over again. But, if the import succeeds, it will be easier to upload similar CSV files.',
|
||||||
'over again. But, if the import succeeds, it will be easier to upload similar CSV files.',
|
|
||||||
'csv_do_download_config' => 'Download configuration file.',
|
'csv_do_download_config' => 'Download configuration file.',
|
||||||
'csv_empty_description' => '(empty description)',
|
'csv_empty_description' => '(empty description)',
|
||||||
'csv_upload_form' => 'CSV upload form',
|
'csv_upload_form' => 'CSV upload form',
|
||||||
@@ -188,11 +179,9 @@ return [
|
|||||||
'csv_column_tags-space' => 'Tags (space separated)',
|
'csv_column_tags-space' => 'Tags (space separated)',
|
||||||
'csv_specifix_RabobankDescription' => 'Select this when you\'re importing Rabobank CSV export files.',
|
'csv_specifix_RabobankDescription' => 'Select this when you\'re importing Rabobank CSV export files.',
|
||||||
'csv_specifix_Dummy' => 'Checking this has no effect whatsoever.',
|
'csv_specifix_Dummy' => 'Checking this has no effect whatsoever.',
|
||||||
'csv_import_account_help' => 'If your CSV file does NOT contain information about your asset account(s), use this dropdown to select to which'
|
'csv_import_account_help' => 'If your CSV file does NOT contain information about your asset account(s), use this dropdown to select to which account the transactions in the CSV belong to.',
|
||||||
. ' account the transactions in the CSV belong to.',
|
|
||||||
'csv_date_parse_error' => 'Could not parse a valid date from ":value", using the format ":format". Are you sure your CSV is correct?',
|
'csv_date_parse_error' => 'Could not parse a valid date from ":value", using the format ":format". Are you sure your CSV is correct?',
|
||||||
|
|
||||||
|
|
||||||
// create new stuff:
|
// create new stuff:
|
||||||
'create_new_withdrawal' => 'Create new withdrawal',
|
'create_new_withdrawal' => 'Create new withdrawal',
|
||||||
'create_new_deposit' => 'Create new deposit',
|
'create_new_deposit' => 'Create new deposit',
|
||||||
@@ -203,7 +192,6 @@ return [
|
|||||||
'create_new_piggy_bank' => 'Create new piggy bank',
|
'create_new_piggy_bank' => 'Create new piggy bank',
|
||||||
'create_new_bill' => 'Create new bill',
|
'create_new_bill' => 'Create new bill',
|
||||||
|
|
||||||
|
|
||||||
// currencies:
|
// currencies:
|
||||||
'create_currency' => 'Create a new currency',
|
'create_currency' => 'Create a new currency',
|
||||||
'edit_currency' => 'Edit currency ":name"',
|
'edit_currency' => 'Edit currency ":name"',
|
||||||
@@ -249,35 +237,27 @@ return [
|
|||||||
'details_for_expense' => 'Details for expense account ":name"',
|
'details_for_expense' => 'Details for expense account ":name"',
|
||||||
'details_for_revenue' => 'Details for revenue account ":name"',
|
'details_for_revenue' => 'Details for revenue account ":name"',
|
||||||
'details_for_cash' => 'Details for cash account ":name"',
|
'details_for_cash' => 'Details for cash account ":name"',
|
||||||
|
|
||||||
'store_new_asset_account' => 'Store new asset account',
|
'store_new_asset_account' => 'Store new asset account',
|
||||||
'store_new_expense_account' => 'Store new expense account',
|
'store_new_expense_account' => 'Store new expense account',
|
||||||
'store_new_revenue_account' => 'Store new revenue account',
|
'store_new_revenue_account' => 'Store new revenue account',
|
||||||
|
|
||||||
'edit_asset_account' => 'Edit asset account ":name"',
|
'edit_asset_account' => 'Edit asset account ":name"',
|
||||||
'edit_expense_account' => 'Edit expense account ":name"',
|
'edit_expense_account' => 'Edit expense account ":name"',
|
||||||
'edit_revenue_account' => 'Edit revenue account ":name"',
|
'edit_revenue_account' => 'Edit revenue account ":name"',
|
||||||
|
|
||||||
'delete_asset_account' => 'Delete asset account ":name"',
|
'delete_asset_account' => 'Delete asset account ":name"',
|
||||||
'delete_expense_account' => 'Delete expense account ":name"',
|
'delete_expense_account' => 'Delete expense account ":name"',
|
||||||
'delete_revenue_account' => 'Delete revenue account ":name"',
|
'delete_revenue_account' => 'Delete revenue account ":name"',
|
||||||
|
|
||||||
'asset_deleted' => 'Successfully deleted asset account ":name"',
|
'asset_deleted' => 'Successfully deleted asset account ":name"',
|
||||||
'expense_deleted' => 'Successfully deleted expense account ":name"',
|
'expense_deleted' => 'Successfully deleted expense account ":name"',
|
||||||
'revenue_deleted' => 'Successfully deleted revenue account ":name"',
|
'revenue_deleted' => 'Successfully deleted revenue account ":name"',
|
||||||
|
|
||||||
'update_asset_account' => 'Update asset account',
|
'update_asset_account' => 'Update asset account',
|
||||||
'update_expense_account' => 'Update expense account',
|
'update_expense_account' => 'Update expense account',
|
||||||
'update_revenue_account' => 'Update revenue account',
|
'update_revenue_account' => 'Update revenue account',
|
||||||
|
|
||||||
'make_new_asset_account' => 'Create a new asset account',
|
'make_new_asset_account' => 'Create a new asset account',
|
||||||
'make_new_expense_account' => 'Create a new expense account',
|
'make_new_expense_account' => 'Create a new expense account',
|
||||||
'make_new_revenue_account' => 'Create a new revenue account',
|
'make_new_revenue_account' => 'Create a new revenue account',
|
||||||
|
|
||||||
'asset_accounts' => 'Asset accounts',
|
'asset_accounts' => 'Asset accounts',
|
||||||
'expense_accounts' => 'Expense accounts',
|
'expense_accounts' => 'Expense accounts',
|
||||||
'revenue_accounts' => 'Revenue accounts',
|
'revenue_accounts' => 'Revenue accounts',
|
||||||
|
|
||||||
'accountExtraHelp_asset' => '',
|
'accountExtraHelp_asset' => '',
|
||||||
'accountExtraHelp_expense' => '',
|
'accountExtraHelp_expense' => '',
|
||||||
'accountExtraHelp_revenue' => '',
|
'accountExtraHelp_revenue' => '',
|
||||||
@@ -340,6 +320,7 @@ return [
|
|||||||
'Default account' => 'Asset account',
|
'Default account' => 'Asset account',
|
||||||
'Expense account' => 'Expense account',
|
'Expense account' => 'Expense account',
|
||||||
'Revenue account' => 'Revenue account',
|
'Revenue account' => 'Revenue account',
|
||||||
|
'Initial balance account' => 'Initial balance account',
|
||||||
'budgets' => 'Budgets',
|
'budgets' => 'Budgets',
|
||||||
'tags' => 'Tags',
|
'tags' => 'Tags',
|
||||||
'reports' => 'Reports',
|
'reports' => 'Reports',
|
||||||
@@ -375,10 +356,13 @@ return [
|
|||||||
'profile' => 'Profile',
|
'profile' => 'Profile',
|
||||||
|
|
||||||
// reports:
|
// reports:
|
||||||
'reportForYear' => 'Yearly report for :year',
|
'report_default' => 'Default financial report for :start until :end',
|
||||||
'reportForYearShared' => 'Yearly report for :year (including shared accounts)',
|
'quick_link_reports' => 'Quick links',
|
||||||
'reportForMonth' => 'Montly report for :month',
|
'quick_link_default_report' => 'Default financial report',
|
||||||
'reportForMonthShared' => 'Montly report for :month (including shared accounts)',
|
'report_this_month_quick' => 'Current month, all accounts',
|
||||||
|
'report_this_year_quick' => 'Current year, all accounts',
|
||||||
|
'report_all_time_quick' => 'All-time, all accounts',
|
||||||
|
'reports_can_bookmark' => 'Remember that reports can be bookmarked.',
|
||||||
'incomeVsExpenses' => 'Income vs. expenses',
|
'incomeVsExpenses' => 'Income vs. expenses',
|
||||||
'accountBalances' => 'Account balances',
|
'accountBalances' => 'Account balances',
|
||||||
'balanceStartOfYear' => 'Balance at start of year',
|
'balanceStartOfYear' => 'Balance at start of year',
|
||||||
@@ -397,6 +381,7 @@ return [
|
|||||||
'outsideOfBudgets' => 'Outside of budgets',
|
'outsideOfBudgets' => 'Outside of budgets',
|
||||||
'leftInBudget' => 'Left in budget',
|
'leftInBudget' => 'Left in budget',
|
||||||
'sumOfSums' => 'Sum of sums',
|
'sumOfSums' => 'Sum of sums',
|
||||||
|
'noCategory' => '(no category)',
|
||||||
'notCharged' => 'Not charged (yet)',
|
'notCharged' => 'Not charged (yet)',
|
||||||
'inactive' => 'Inactive',
|
'inactive' => 'Inactive',
|
||||||
'difference' => 'Difference',
|
'difference' => 'Difference',
|
||||||
@@ -406,9 +391,18 @@ return [
|
|||||||
'showTheRest' => 'Show everything',
|
'showTheRest' => 'Show everything',
|
||||||
'hideTheRest' => 'Show only the top :number',
|
'hideTheRest' => 'Show only the top :number',
|
||||||
'sum_of_year' => 'Sum of year',
|
'sum_of_year' => 'Sum of year',
|
||||||
|
'sum_of_years' => 'Sum of years',
|
||||||
'average_of_year' => 'Average of year',
|
'average_of_year' => 'Average of year',
|
||||||
|
'average_of_years' => 'Average of years',
|
||||||
'categories_earned_in_year' => 'Categories (by earnings)',
|
'categories_earned_in_year' => 'Categories (by earnings)',
|
||||||
'categories_spent_in_year' => 'Categories (by spendings)',
|
'categories_spent_in_year' => 'Categories (by spendings)',
|
||||||
|
'report_type' => 'Report type',
|
||||||
|
'report_type_default' => 'Default financial report',
|
||||||
|
'report_included_accounts' => 'Included accounts',
|
||||||
|
'report_date_range' => 'Date range',
|
||||||
|
'report_include_help' => 'In all cases, transfers to shared accounts count as expenses, and transfers from shared accounts count as income.',
|
||||||
|
'report_preset_ranges' => 'Pre-set ranges',
|
||||||
|
'shared' => 'Shared',
|
||||||
|
|
||||||
// charts:
|
// charts:
|
||||||
'dayOfMonth' => 'Day of the month',
|
'dayOfMonth' => 'Day of the month',
|
||||||
@@ -469,7 +463,6 @@ return [
|
|||||||
'regular_tag' => 'Just a regular tag.',
|
'regular_tag' => 'Just a regular tag.',
|
||||||
'balancing_act' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.',
|
'balancing_act' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.',
|
||||||
'advance_payment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
|
'advance_payment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
|
||||||
|
|
||||||
'delete_tag' => 'Delete tag ":tag"',
|
'delete_tag' => 'Delete tag ":tag"',
|
||||||
'new_tag' => 'Make new tag',
|
'new_tag' => 'Make new tag',
|
||||||
'edit_tag' => 'Edit tag ":tag"',
|
'edit_tag' => 'Edit tag ":tag"',
|
||||||
@@ -478,17 +471,8 @@ return [
|
|||||||
'tag_title_nothing' => 'Default tags',
|
'tag_title_nothing' => 'Default tags',
|
||||||
'tag_title_balancingAct' => 'Balancing act tags',
|
'tag_title_balancingAct' => 'Balancing act tags',
|
||||||
'tag_title_advancePayment' => 'Advance payment tags',
|
'tag_title_advancePayment' => 'Advance payment tags',
|
||||||
'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like' .
|
'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like <span class="label label-info">expensive</span>, <span class="label label-info">bill</span> or <span class="label label-info">for-party</span>. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called <span class="label label-success"> Christmas dinner with friends</span> and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.',
|
||||||
' <span class="label label-info">expensive</span>, <span class="label label-info">bill</span>' .
|
'tags_group' => 'Tags group transactions together, which makes it possible to store reimbursements (in case you front money for others) and other "balancing acts" where expenses are summed up (the payments on your new TV) or where expenses and deposits are cancelling each other out (buying something with saved money). It\'s all up to you. Using tags the old-fashioned way is of course always possible.',
|
||||||
' or <span class="label label-info">for-party</span>. In Firefly III, tags can have more properties' .
|
|
||||||
' such as a date, description and location. This allows you to join transactions together in a more' .
|
|
||||||
' meaningful way. For example, you could make a tag called <span class="label label-success">' .
|
|
||||||
'Christmas dinner with friends</span> and add information about the restaurant. Such tags are "singular",' .
|
|
||||||
' you would only use them for a single occasion, perhaps with multiple transactions.',
|
|
||||||
'tags_group' => 'Tags group transactions together, which makes it possible to store reimbursements (in case you front money' .
|
|
||||||
' for others) and other "balancing acts" where expenses are summed up (the payments on your new TV) or where ' .
|
|
||||||
'expenses and deposits are cancelling each other out (buying something with saved money). It\'s all up to you.' .
|
|
||||||
' Using tags the old-fashioned way is of course always possible. ',
|
|
||||||
'tags_start' => 'Create a tag to get started or enter tags when creating new transactions.',
|
'tags_start' => 'Create a tag to get started or enter tags when creating new transactions.',
|
||||||
|
|
||||||
];
|
];
|
||||||
@@ -6,7 +6,8 @@ return [
|
|||||||
'bank_balance' => 'Balance',
|
'bank_balance' => 'Balance',
|
||||||
'savings_balance' => 'Savings balance',
|
'savings_balance' => 'Savings balance',
|
||||||
'credit_card_limit' => 'Credit card limit',
|
'credit_card_limit' => 'Credit card limit',
|
||||||
|
'automatch' => 'Match automatically',
|
||||||
|
'skip' => 'Skip',
|
||||||
'name' => 'Name',
|
'name' => 'Name',
|
||||||
'active' => 'Active',
|
'active' => 'Active',
|
||||||
'amount_min' => 'Minimum amount',
|
'amount_min' => 'Minimum amount',
|
||||||
@@ -68,35 +69,29 @@ return [
|
|||||||
'size' => 'Size',
|
'size' => 'Size',
|
||||||
|
|
||||||
|
|
||||||
'delete_account' => 'Delete account ":name"',
|
'delete_account' => 'Delete account ":name"',
|
||||||
'delete_bill' => 'Delete bill ":name"',
|
'delete_bill' => 'Delete bill ":name"',
|
||||||
'delete_budget' => 'Delete budget ":name"',
|
'delete_budget' => 'Delete budget ":name"',
|
||||||
'delete_category' => 'Delete category ":name"',
|
'delete_category' => 'Delete category ":name"',
|
||||||
'delete_currency' => 'Delete currency ":name"',
|
'delete_currency' => 'Delete currency ":name"',
|
||||||
'delete_journal' => 'Delete transaction with description ":description"',
|
'delete_journal' => 'Delete transaction with description ":description"',
|
||||||
'delete_attachment' => 'Delete attachment ":name"',
|
'delete_attachment' => 'Delete attachment ":name"',
|
||||||
|
|
||||||
'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?',
|
'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?',
|
||||||
'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?',
|
'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?',
|
||||||
'bill_areYouSure' => 'Are you sure you want to delete the bill named ":name"?',
|
'bill_areYouSure' => 'Are you sure you want to delete the bill named ":name"?',
|
||||||
'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?',
|
'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?',
|
||||||
'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?',
|
'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?',
|
||||||
'currency_areYouSure' => 'Are you sure you want to delete the currency named ":name"?',
|
'currency_areYouSure' => 'Are you sure you want to delete the currency named ":name"?',
|
||||||
'piggyBank_areYouSure' => 'Are you sure you want to delete the piggy bank named ":name"?',
|
'piggyBank_areYouSure' => 'Are you sure you want to delete the piggy bank named ":name"?',
|
||||||
'journal_areYouSure' => 'Are you sure you want to delete the transaction described ":description"?',
|
'journal_areYouSure' => 'Are you sure you want to delete the transaction described ":description"?',
|
||||||
'tag_areYouSure' => 'Are you sure you want to delete the tag ":tag"?',
|
'tag_areYouSure' => 'Are you sure you want to delete the tag ":tag"?',
|
||||||
|
|
||||||
'permDeleteWarning' => 'Deleting stuff from Firely is permanent and cannot be undone.',
|
'permDeleteWarning' => 'Deleting stuff from Firely is permanent and cannot be undone.',
|
||||||
'also_delete_transactions' => 'The only transaction connected to this account will be deleted as well.' .
|
'also_delete_transactions' => 'The only transaction connected to this account will be deleted as well.|All :count transactions connected to this account will be deleted as well.',
|
||||||
'|All :count transactions connected to this account will be deleted as well.',
|
'also_delete_piggyBanks' => 'The only piggy bank connected to this account will be deleted as well.|All :count piggy bank connected to this account will be deleted as well.',
|
||||||
'also_delete_piggyBanks' => 'The only piggy bank connected to this account will be deleted as well.' .
|
'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.|All :count transactions connected to this bill will spared deletion.',
|
||||||
'|All :count piggy bank connected to this account will be deleted as well.',
|
'budget_keep_transactions' => 'The only transaction connected to this budget will not be deleted.|All :count transactions connected to this budget will spared deletion.',
|
||||||
'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.' .
|
'category_keep_transactions' => 'The only transaction connected to this category will not be deleted.|All :count transactions connected to this category will spared deletion.',
|
||||||
'|All :count transactions connected to this bill will spared deletion.',
|
'tag_keep_transactions' => 'The only transaction connected to this tag will not be deleted.|All :count transactions connected to this tag will spared deletion.',
|
||||||
'budget_keep_transactions' => 'The only transaction connected to this budget will not be deleted.' .
|
|
||||||
'|All :count transactions connected to this budget will spared deletion.',
|
|
||||||
'category_keep_transactions' => 'The only transaction connected to this category will not be deleted.' .
|
|
||||||
'|All :count transactions connected to this category will spared deletion.',
|
|
||||||
'tag_keep_transactions' => 'The only transaction connected to this tag will not be deleted.' .
|
|
||||||
'|All :count transactions connected to this tag will spared deletion.',
|
|
||||||
];
|
];
|
||||||
84
resources/lang/en_US/help.php
Normal file
84
resources/lang/en_US/help.php
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
|
||||||
|
// tour!
|
||||||
|
'main-content-title' => 'Welcome to Firefly III',
|
||||||
|
'main-content-text' => 'Do yourself a favor and follow this short guide to make sure you know your way around.',
|
||||||
|
'sidebar-toggle-title' => 'Sidebar to create stuff',
|
||||||
|
'sidebar-toggle-text' => 'Hidden under the plus icon are all the buttons to create new stuff. Accounts, transactions, everything!',
|
||||||
|
'account-menu-title' => 'All your accounts',
|
||||||
|
'account-menu-text' => 'Here you can find all the accounts you\'ve made.',
|
||||||
|
'budget-menu-title' => 'Budgets',
|
||||||
|
'budget-menu-text' => 'Use this page to organise your finances and limit spending.',
|
||||||
|
'report-menu-title' => 'Reports',
|
||||||
|
'report-menu-text' => 'Check this out when you want a solid overview of your fiances.',
|
||||||
|
'transaction-menu-title' => 'Transactions',
|
||||||
|
'transaction-menu-text' => 'All transactions you\'ve created can be found here.',
|
||||||
|
'option-menu-title' => 'Options',
|
||||||
|
'option-menu-text' => 'This is pretty self-explanatory.',
|
||||||
|
'main-content-end-title' => 'The end!',
|
||||||
|
'main-content-end-text' => 'Remember that every page has a small question mark at the right top. Click it to get help about the page you\'re on.',
|
||||||
|
|
||||||
|
|
||||||
|
'index' => 'index',
|
||||||
|
'home' => 'home',
|
||||||
|
'accounts-index' => 'accounts.index',
|
||||||
|
'accounts-create' => 'accounts.create',
|
||||||
|
'accounts-edit' => 'accounts.edit',
|
||||||
|
'accounts-delete' => 'accounts.delete',
|
||||||
|
'accounts-show' => 'accounts.show',
|
||||||
|
'attachments-edit' => 'attachments.edit',
|
||||||
|
'attachments-delete' => 'attachments.delete',
|
||||||
|
'attachments-show' => 'attachments.show',
|
||||||
|
'attachments-preview' => 'attachments.preview',
|
||||||
|
'bills-index' => 'bills.index',
|
||||||
|
'bills-create' => 'bills.create',
|
||||||
|
'bills-edit' => 'bills.edit',
|
||||||
|
'bills-delete' => 'bills.delete',
|
||||||
|
'bills-show' => 'bills.show',
|
||||||
|
'budgets-index' => 'budgets.index',
|
||||||
|
'budgets-create' => 'budgets.create',
|
||||||
|
'budgets-edit' => 'budgets.edit',
|
||||||
|
'budgets-delete' => 'budgets.delete',
|
||||||
|
'budgets-show' => 'budgets.show',
|
||||||
|
'budgets-noBudget' => 'budgets.noBudget',
|
||||||
|
'categories-index' => 'categories.index',
|
||||||
|
'categories-create' => 'categories.create',
|
||||||
|
'categories-edit' => 'categories.edit',
|
||||||
|
'categories-delete' => 'categories.delete',
|
||||||
|
'categories-show' => 'categories.show',
|
||||||
|
'categories-show-date' => 'categories.show.date',
|
||||||
|
'categories-noCategory' => 'categories.noCategory',
|
||||||
|
'csv-index' => 'csv.index',
|
||||||
|
'csv-column-roles' => 'csv.column-roles',
|
||||||
|
'csv-map' => 'csv.map',
|
||||||
|
'csv-download-config-page' => 'csv.download-config-page',
|
||||||
|
'csv-process' => 'csv.process',
|
||||||
|
'currency-index' => 'currency.index',
|
||||||
|
'currency-create' => 'currency.create',
|
||||||
|
'currency-edit' => 'currency.edit',
|
||||||
|
'currency-delete' => 'currency.delete',
|
||||||
|
'new-user-index' => 'new-user.index',
|
||||||
|
'piggy-banks-index' => 'piggy-banks.index',
|
||||||
|
'piggy-banks-create' => 'piggy-banks.create',
|
||||||
|
'piggy-banks-edit' => 'piggy-banks.edit',
|
||||||
|
'piggy-banks-delete' => 'piggy-banks.delete',
|
||||||
|
'piggy-banks-show' => 'piggy-banks.show',
|
||||||
|
'preferences' => 'preferences',
|
||||||
|
'profile' => 'profile',
|
||||||
|
'profile-change-password' => 'profile.change-password',
|
||||||
|
'profile-delete-account' => 'profile.delete-account',
|
||||||
|
'reports-index' => 'reports.index',
|
||||||
|
'reports-report' => 'reports.report',
|
||||||
|
'search' => 'search',
|
||||||
|
'tags-index' => 'tags.index',
|
||||||
|
'tags-create' => 'tags.create',
|
||||||
|
'tags-show' => 'tags.show',
|
||||||
|
'tags-edit' => 'tags.edit',
|
||||||
|
'tags-delete' => 'tags.delete',
|
||||||
|
'transactions-index' => 'transactions.index',
|
||||||
|
'transactions-create' => 'transactions.create',
|
||||||
|
'transactions-edit' => 'transactions.edit',
|
||||||
|
'transactions-delete' => 'transactions.delete',
|
||||||
|
'transactions-show' => 'transactions.show',
|
||||||
|
];
|
||||||
@@ -14,7 +14,7 @@ return [
|
|||||||
'matchingAmount' => 'Amount',
|
'matchingAmount' => 'Amount',
|
||||||
'lastMatch' => 'Last match',
|
'lastMatch' => 'Last match',
|
||||||
'expectedMatch' => 'Expected match',
|
'expectedMatch' => 'Expected match',
|
||||||
'automatch' => 'Automatch?',
|
'automatch' => 'Auto match?',
|
||||||
'repeat_freq' => 'Repeats',
|
'repeat_freq' => 'Repeats',
|
||||||
'description' => 'Description',
|
'description' => 'Description',
|
||||||
'amount' => 'Amount',
|
'amount' => 'Amount',
|
||||||
@@ -17,5 +17,6 @@ return [
|
|||||||
"token" => "This password reset token is invalid.",
|
"token" => "This password reset token is invalid.",
|
||||||
"sent" => "We have e-mailed your password reset link!",
|
"sent" => "We have e-mailed your password reset link!",
|
||||||
"reset" => "Your password has been reset!",
|
"reset" => "Your password has been reset!",
|
||||||
|
'blocked' => 'Nice try though.'
|
||||||
|
|
||||||
];
|
];
|
||||||
@@ -1,18 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'invalid_domain' => 'Due to security constraints, you cannot register from this domain.',
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Validation Language Lines
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The following language lines contain the default error messages used by
|
|
||||||
| the validator class. Some of these rules have multiple versions such
|
|
||||||
| as the size rules. Feel free to tweak each of these messages here.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'file_already_attached' => 'Uploaded file ":name" is already attached to this object.',
|
'file_already_attached' => 'Uploaded file ":name" is already attached to this object.',
|
||||||
'file_attached' => 'Succesfully uploaded file ":name".',
|
'file_attached' => 'Succesfully uploaded file ":name".',
|
||||||
'file_invalid_mime' => 'File ":name" is of type ":mime" which is not accepted as a new upload.',
|
'file_invalid_mime' => 'File ":name" is of type ":mime" which is not accepted as a new upload.',
|
||||||
@@ -28,12 +17,10 @@ return [
|
|||||||
"before" => "The :attribute must be a date before :date.",
|
"before" => "The :attribute must be a date before :date.",
|
||||||
'unique_object_for_user' => 'This name is already in use',
|
'unique_object_for_user' => 'This name is already in use',
|
||||||
'unique_account_for_user' => 'This account name is already in use',
|
'unique_account_for_user' => 'This account name is already in use',
|
||||||
"between" => [
|
"between.numeric" => "The :attribute must be between :min and :max.",
|
||||||
"numeric" => "The :attribute must be between :min and :max.",
|
"between.file" => "The :attribute must be between :min and :max kilobytes.",
|
||||||
"file" => "The :attribute must be between :min and :max kilobytes.",
|
"between.string" => "The :attribute must be between :min and :max characters.",
|
||||||
"string" => "The :attribute must be between :min and :max characters.",
|
"between.array" => "The :attribute must have between :min and :max items.",
|
||||||
"array" => "The :attribute must have between :min and :max items.",
|
|
||||||
],
|
|
||||||
"boolean" => "The :attribute field must be true or false.",
|
"boolean" => "The :attribute field must be true or false.",
|
||||||
"confirmed" => "The :attribute confirmation does not match.",
|
"confirmed" => "The :attribute confirmation does not match.",
|
||||||
"date" => "The :attribute is not a valid date.",
|
"date" => "The :attribute is not a valid date.",
|
||||||
@@ -48,67 +35,33 @@ return [
|
|||||||
"in" => "The selected :attribute is invalid.",
|
"in" => "The selected :attribute is invalid.",
|
||||||
"integer" => "The :attribute must be an integer.",
|
"integer" => "The :attribute must be an integer.",
|
||||||
"ip" => "The :attribute must be a valid IP address.",
|
"ip" => "The :attribute must be a valid IP address.",
|
||||||
"max" => [
|
'json' => 'The :attribute must be a valid JSON string.',
|
||||||
"numeric" => "The :attribute may not be greater than :max.",
|
"max.numeric" => "The :attribute may not be greater than :max.",
|
||||||
"file" => "The :attribute may not be greater than :max kilobytes.",
|
"max.file" => "The :attribute may not be greater than :max kilobytes.",
|
||||||
"string" => "The :attribute may not be greater than :max characters.",
|
"max.string" => "The :attribute may not be greater than :max characters.",
|
||||||
"array" => "The :attribute may not have more than :max items.",
|
"max.array" => "The :attribute may not have more than :max items.",
|
||||||
],
|
|
||||||
"mimes" => "The :attribute must be a file of type: :values.",
|
"mimes" => "The :attribute must be a file of type: :values.",
|
||||||
"min" => [
|
"min.numeric" => "The :attribute must be at least :min.",
|
||||||
"numeric" => "The :attribute must be at least :min.",
|
"min.file" => "The :attribute must be at least :min kilobytes.",
|
||||||
"file" => "The :attribute must be at least :min kilobytes.",
|
"min.string" => "The :attribute must be at least :min characters.",
|
||||||
"string" => "The :attribute must be at least :min characters.",
|
"min.array" => "The :attribute must have at least :min items.",
|
||||||
"array" => "The :attribute must have at least :min items.",
|
|
||||||
],
|
|
||||||
"not_in" => "The selected :attribute is invalid.",
|
"not_in" => "The selected :attribute is invalid.",
|
||||||
"numeric" => "The :attribute must be a number.",
|
"numeric" => "The :attribute must be a number.",
|
||||||
"regex" => "The :attribute format is invalid.",
|
"regex" => "The :attribute format is invalid.",
|
||||||
"required" => "The :attribute field is required.",
|
"required" => "The :attribute field is required.",
|
||||||
"required_if" => "The :attribute field is required when :other is :value.",
|
"required_if" => "The :attribute field is required when :other is :value.",
|
||||||
|
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
||||||
"required_with" => "The :attribute field is required when :values is present.",
|
"required_with" => "The :attribute field is required when :values is present.",
|
||||||
"required_with_all" => "The :attribute field is required when :values is present.",
|
"required_with_all" => "The :attribute field is required when :values is present.",
|
||||||
"required_without" => "The :attribute field is required when :values is not present.",
|
"required_without" => "The :attribute field is required when :values is not present.",
|
||||||
"required_without_all" => "The :attribute field is required when none of :values are present.",
|
"required_without_all" => "The :attribute field is required when none of :values are present.",
|
||||||
"same" => "The :attribute and :other must match.",
|
"same" => "The :attribute and :other must match.",
|
||||||
"size" => [
|
"size.numeric" => "The :attribute must be :size.",
|
||||||
"numeric" => "The :attribute must be :size.",
|
"size.file" => "The :attribute must be :size kilobytes.",
|
||||||
"file" => "The :attribute must be :size kilobytes.",
|
"size.string" => "The :attribute must be :size characters.",
|
||||||
"string" => "The :attribute must be :size characters.",
|
"size.array" => "The :attribute must contain :size items.",
|
||||||
"array" => "The :attribute must contain :size items.",
|
|
||||||
],
|
|
||||||
"unique" => "The :attribute has already been taken.",
|
"unique" => "The :attribute has already been taken.",
|
||||||
|
'string' => 'The :attribute must be a string.',
|
||||||
"url" => "The :attribute format is invalid.",
|
"url" => "The :attribute format is invalid.",
|
||||||
"timezone" => "The :attribute must be a valid zone.",
|
"timezone" => "The :attribute must be a valid zone.",
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Custom Validation Language Lines
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Here you may specify custom validation messages for attributes using the
|
|
||||||
| convention "attribute.rule" to name the lines. This makes it quick to
|
|
||||||
| specify a specific custom language line for a given attribute rule.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'custom' => [
|
|
||||||
'attribute-name' => [
|
|
||||||
'rule-name' => 'custom-message',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Custom Validation Attributes
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The following language lines are used to swap attribute place-holders
|
|
||||||
| with something more reader friendly such as E-Mail Address instead
|
|
||||||
| of "email". This simply helps us make messages a little cleaner.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'attributes' => [],
|
|
||||||
|
|
||||||
];
|
];
|
||||||
60
resources/lang/fr_FR/breadcrumbs.php
Normal file
60
resources/lang/fr_FR/breadcrumbs.php
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'home' => 'Accueil',
|
||||||
|
|
||||||
|
// accounts
|
||||||
|
'cash_accounts' => 'Cash accounts',
|
||||||
|
'edit_account' => 'Editer le compte : ":name"',
|
||||||
|
|
||||||
|
// currencies
|
||||||
|
'edit_currency' => 'Editer la devise : ";name"',
|
||||||
|
'delete_currency' => 'Supprimer la devise ":name"',
|
||||||
|
|
||||||
|
// piggy banks
|
||||||
|
'newPiggyBank' => 'Create a new piggy bank',
|
||||||
|
'edit_piggyBank' => 'Edit piggy bank ":name"',
|
||||||
|
|
||||||
|
// top menu
|
||||||
|
'preferences' => 'Preferences',
|
||||||
|
'profile' => 'Profil',
|
||||||
|
'changePassword' => 'Modifier le mot de passe',
|
||||||
|
|
||||||
|
// bills
|
||||||
|
'bills' => 'Factures',
|
||||||
|
'newBill' => 'Nouvelle facture',
|
||||||
|
'edit_bill' => 'Editer la facture : ":name"',
|
||||||
|
'delete_bill' => 'Supprimer la facture ":name"',
|
||||||
|
|
||||||
|
// reports
|
||||||
|
'reports' => 'Rapport',
|
||||||
|
'monthly_report' => 'Rapport mensuel pour :date',
|
||||||
|
'monthly_report_shared' => 'Rapport mensuel pour :date (avec les comptes joints)',
|
||||||
|
'yearly_report' => 'Rapport annuel pour :date',
|
||||||
|
'yearly_report_shared' => 'Rapport annuel pour :date (avec les comptes joints)',
|
||||||
|
'budget_report' => 'Rapport budgetaire pour :date',
|
||||||
|
|
||||||
|
// search
|
||||||
|
'searchResult' => 'Resultat de recherche pour ":query"',
|
||||||
|
|
||||||
|
// transaction lists.
|
||||||
|
'withdrawal_list' => 'Dépenses',
|
||||||
|
'deposit_list' => 'Revenue, Salaire et depots ',
|
||||||
|
'transfer_list' => 'Transferts',
|
||||||
|
'transfers_list' => 'Transferts',
|
||||||
|
|
||||||
|
// create transactions
|
||||||
|
'create_withdrawal' => 'Creer un nouveau retrait',
|
||||||
|
'create_deposit' => 'Create new deposit',
|
||||||
|
'create_transfer' => 'Creer un nouveau transfert',
|
||||||
|
|
||||||
|
// edit transactions
|
||||||
|
'edit_journal' => 'Editer la transaction ":description"',
|
||||||
|
'delete_journal' => 'Supprimer la transaction ":description"',
|
||||||
|
|
||||||
|
// tags
|
||||||
|
'tags' => 'Tags',
|
||||||
|
'createTag' => 'Créer un nouveau tag',
|
||||||
|
'edit_tag' => 'Editer le tag ":tag"',
|
||||||
|
'delete_tag' => 'Supprimer le tag ":tag"',
|
||||||
|
|
||||||
|
];
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user