mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-08-22 13:19:29 +00:00
Compare commits
210 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 | ||
|
0fe682bfe6 |
13
.env.example
13
.env.example
@@ -2,6 +2,7 @@ APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_KEY=SomeRandomStringOf32CharsExactly
|
||||
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=localhost
|
||||
DB_DATABASE=homestead
|
||||
@@ -11,14 +12,22 @@ DB_PASSWORD=secret
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
DEFAULT_CURRENCY=EUR
|
||||
DEFAULT_LANGUAGE=en_US
|
||||
|
||||
EMAIL_SMTP=
|
||||
EMAIL_DRIVER=smtp
|
||||
EMAIL_USERNAME=
|
||||
EMAIL_PASSWORD=
|
||||
ANALYTICS_ID=
|
||||
EMAIL_PRETEND=false
|
||||
|
||||
SHOW_INCOMPLETE_TRANSLATIONS=false
|
||||
|
||||
ANALYTICS_ID=
|
||||
RUNCLEANUP=true
|
||||
SITE_OWNER=mail@example.com
|
||||
|
||||
SENDGRID_USERNAME=
|
||||
SENDGRID_PASSWORD=
|
||||
SENDGRID_PASSWORD=
|
||||
|
||||
BLOCKED_DOMAINS=
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,7 +5,7 @@ Thumbs.db
|
||||
.idea/
|
||||
tests/_output/*
|
||||
_ide_helper.php
|
||||
/build/logs/clover.xml
|
||||
/build/logs
|
||||
index.html*
|
||||
app/storage/firefly-export*
|
||||
.vagrant
|
||||
|
@@ -10,6 +10,9 @@ install:
|
||||
- composer update
|
||||
- php artisan env
|
||||
- mv -v .env.testing .env
|
||||
- touch storage/database/testing.db
|
||||
- php artisan migrate --env=testing
|
||||
- php artisan migrate --seed --env=testing
|
||||
|
||||
script:
|
||||
- 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.
|
||||
|
||||
|
||||
To get to know Firefly, and to see if it fits you, check out these resources:
|
||||
|
||||
- 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._
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
## 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)**.
|
||||
|
||||
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
|
||||
|
||||
|
@@ -14,15 +14,6 @@ use Illuminate\Support\Collection;
|
||||
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 Carbon $start
|
||||
|
@@ -3,10 +3,8 @@
|
||||
namespace FireflyIII\Generator\Chart\Account;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use FireflyIII\Models\Account;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
@@ -17,21 +15,6 @@ use Steam;
|
||||
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 Carbon $start
|
||||
@@ -42,10 +25,10 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
|
||||
public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end)
|
||||
{
|
||||
$data = [
|
||||
'count' => 1,
|
||||
'labels' => [], 'datasets' => [[
|
||||
'label' => trans('firefly.spent'),
|
||||
'data' => []]]];
|
||||
'count' => 1,
|
||||
'labels' => [], 'datasets' => [[
|
||||
'label' => trans('firefly.spent'),
|
||||
'data' => []]]];
|
||||
|
||||
bcscale(2);
|
||||
$start->subDay();
|
||||
@@ -105,21 +88,21 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
|
||||
public function frontpage(Collection $accounts, Carbon $start, Carbon $end)
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.monthAndDay.' . $language);
|
||||
$data = [
|
||||
$format = trans('config.month_and_day');
|
||||
$data = [
|
||||
'count' => 0,
|
||||
'labels' => [],
|
||||
'datasets' => [],
|
||||
];
|
||||
$current = clone $start;
|
||||
$current = clone $start;
|
||||
while ($current <= $end) {
|
||||
$data['labels'][] = $current->formatLocalized($format);
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
$set = [
|
||||
$set = [
|
||||
'label' => $account->name,
|
||||
'fillColor' => 'rgba(220,220,220,0.2)',
|
||||
'strokeColor' => 'rgba(220,220,220,1)',
|
||||
@@ -129,9 +112,15 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
|
||||
'pointHighlightStroke' => 'rgba(220,220,220,1)',
|
||||
'data' => [],
|
||||
];
|
||||
$current = clone $start;
|
||||
$current = clone $start;
|
||||
$range = Steam::balanceInRange($account, $start, $end);
|
||||
$previous = array_values($range)[0];
|
||||
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();
|
||||
}
|
||||
$data['datasets'][] = $set;
|
||||
@@ -151,8 +140,7 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
|
||||
public function single(Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.monthAndDay.' . $language);
|
||||
$format = trans('config.month_and_day');
|
||||
|
||||
$data = [
|
||||
'count' => 1,
|
||||
|
@@ -71,8 +71,7 @@ class ChartJsBillChartGenerator implements BillChartGenerator
|
||||
public function single(Bill $bill, Collection $entries)
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
$format = trans('config.month');
|
||||
|
||||
$data = [
|
||||
'count' => 3,
|
||||
|
@@ -32,6 +32,13 @@ interface BudgetChartGenerator
|
||||
*/
|
||||
public function frontpage(Collection $entries);
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function multiYear(Collection $entries);
|
||||
|
||||
/**
|
||||
* @param Collection $budgets
|
||||
* @param Collection $entries
|
||||
|
@@ -24,7 +24,7 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
|
||||
public function budget(Collection $entries, $dateFormat = 'month')
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$language = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US'))->data;
|
||||
$format = Config::get('firefly.' . $dateFormat . '.' . $language);
|
||||
|
||||
$data = [
|
||||
@@ -33,7 +33,7 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
|
||||
[
|
||||
'label' => 'Amount',
|
||||
'data' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -115,8 +115,7 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
|
||||
public function year(Collection $budgets, Collection $entries)
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
$format = trans('config.month');
|
||||
|
||||
$data = [
|
||||
'labels' => [],
|
||||
@@ -141,4 +140,37 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* @param Collection $categories
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function earnedInPeriod(Collection $categories, Collection $entries);
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
@@ -31,8 +39,14 @@ interface CategoryChartGenerator
|
||||
*
|
||||
* @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
|
||||
@@ -41,12 +55,4 @@ interface CategoryChartGenerator
|
||||
* @return array
|
||||
*/
|
||||
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;
|
||||
|
||||
use Config;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
|
||||
|
||||
/**
|
||||
@@ -101,8 +99,7 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
|
||||
{
|
||||
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
$format = trans('config.month');
|
||||
|
||||
$data = [
|
||||
'count' => 0,
|
||||
@@ -131,12 +128,11 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function earnedInYear(Collection $categories, Collection $entries)
|
||||
public function earnedInPeriod(Collection $categories, Collection $entries)
|
||||
{
|
||||
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
$format = trans('config.month');
|
||||
|
||||
$data = [
|
||||
'count' => 0,
|
||||
@@ -158,4 +154,74 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
|
||||
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 = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.monthAndDay.' . $language);
|
||||
$format = trans('config.month_and_day');
|
||||
|
||||
$data = [
|
||||
'count' => 1,
|
||||
|
@@ -22,8 +22,7 @@ class ChartJsReportChartGenerator implements ReportChartGenerator
|
||||
public function yearInOut(Collection $entries)
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
$format = trans('config.month');
|
||||
|
||||
$data = [
|
||||
'count' => 2,
|
||||
@@ -49,6 +48,39 @@ class ChartJsReportChartGenerator implements ReportChartGenerator
|
||||
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 $expense
|
||||
@@ -74,9 +106,40 @@ class ChartJsReportChartGenerator implements ReportChartGenerator
|
||||
],
|
||||
];
|
||||
$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'][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;
|
||||
}
|
||||
|
@@ -12,6 +12,22 @@ use Illuminate\Support\Collection;
|
||||
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
|
||||
*
|
||||
|
@@ -150,24 +150,4 @@ class BalanceLine
|
||||
{
|
||||
$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:
|
||||
if ($category->spent < 0) {
|
||||
$this->categories->push($category);
|
||||
$this->addTotal($category->spent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +56,7 @@ class Category
|
||||
*/
|
||||
public function getCategories()
|
||||
{
|
||||
$set = $this->categories->sortByDesc(
|
||||
$set = $this->categories->sortBy(
|
||||
function (CategoryModel $category) {
|
||||
return $category->spent;
|
||||
}
|
||||
|
@@ -33,18 +33,24 @@ class Expense
|
||||
*/
|
||||
public function addOrCreateExpense(TransactionJournal $entry)
|
||||
{
|
||||
bcscale(2);
|
||||
|
||||
$accountId = $entry->account_id;
|
||||
$amount = strval(round($entry->amount, 2));
|
||||
if (bccomp('0', $amount) === -1) {
|
||||
$amount = bcmul($amount, '-1');
|
||||
}
|
||||
|
||||
if (!$this->expenses->has($accountId)) {
|
||||
$newObject = new stdClass;
|
||||
$newObject->amount = strval(round($entry->amount_positive, 2));
|
||||
$newObject->amount = $amount;
|
||||
$newObject->name = $entry->name;
|
||||
$newObject->count = 1;
|
||||
$newObject->id = $accountId;
|
||||
$this->expenses->put($accountId, $newObject);
|
||||
} else {
|
||||
bcscale(2);
|
||||
$existing = $this->expenses->get($accountId);
|
||||
$existing->amount = bcadd($existing->amount, $entry->amount_positive);
|
||||
$existing->amount = bcadd($existing->amount, $amount);
|
||||
$existing->count++;
|
||||
$this->expenses->put($accountId, $existing);
|
||||
}
|
||||
@@ -55,8 +61,18 @@ class Expense
|
||||
*/
|
||||
public function addToTotal($add)
|
||||
{
|
||||
$add = strval(round($add, 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);
|
||||
}
|
||||
|
||||
@@ -65,7 +81,7 @@ class Expense
|
||||
*/
|
||||
public function getExpenses()
|
||||
{
|
||||
$set = $this->expenses->sortByDesc(
|
||||
$set = $this->expenses->sortBy(
|
||||
function (stdClass $object) {
|
||||
return $object->amount;
|
||||
}
|
||||
|
@@ -296,7 +296,7 @@ class Importer
|
||||
|
||||
// some debug info:
|
||||
$journalId = $journal->id;
|
||||
$type = $journal->transactionType->type;
|
||||
$type = $journal->getTransactionType();
|
||||
/** @var Account $asset */
|
||||
$asset = $this->importData['asset-account-object'];
|
||||
/** @var Account $opposing */
|
||||
@@ -314,13 +314,13 @@ class Importer
|
||||
*/
|
||||
protected function getTransactionType()
|
||||
{
|
||||
$transactionType = TransactionType::where('type', 'Deposit')->first();
|
||||
$transactionType = TransactionType::where('type', TransactionType::DEPOSIT)->first();
|
||||
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'])) {
|
||||
$transactionType = TransactionType::where('type', 'Transfer')->first();
|
||||
$transactionType = TransactionType::where('type', TransactionType::TRANSFER)->first();
|
||||
}
|
||||
|
||||
return $transactionType;
|
||||
|
@@ -24,7 +24,7 @@ class Currency implements PostProcessorInterface
|
||||
|
||||
// fix 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();
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,8 @@ use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Budget as BudgetModel;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use Illuminate\Support\Collection;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* the users asset and cash accounts.
|
||||
* given accounts
|
||||
*
|
||||
* @param Carbon $date
|
||||
* @param Carbon $end
|
||||
* @param $shared
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return AccountCollection
|
||||
*/
|
||||
public function getAccountReport(Carbon $date, Carbon $end, $shared)
|
||||
public function getAccountReport(Carbon $start, Carbon $end, Collection $accounts)
|
||||
{
|
||||
|
||||
|
||||
$accounts = $this->query->getAllAccounts($date, $end, $shared);
|
||||
$start = '0';
|
||||
$end = '0';
|
||||
$diff = '0';
|
||||
$startAmount = '0';
|
||||
$endAmount = '0';
|
||||
$diff = '0';
|
||||
bcscale(2);
|
||||
|
||||
// remove cash account, if any:
|
||||
$accounts = $accounts->filter(
|
||||
function (Account $account) {
|
||||
if ($account->accountType->type != 'Cash account') {
|
||||
return $account;
|
||||
}
|
||||
$accounts->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();
|
||||
|
||||
return null;
|
||||
/** @noinspection PhpParamsInspection */
|
||||
$account->startBalance = Steam::balance($account, $yesterday);
|
||||
$account->endBalance = Steam::balance($account, $end);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// summarize:
|
||||
foreach ($accounts as $account) {
|
||||
$start = bcadd($start, $account->startBalance);
|
||||
$end = bcadd($end, $account->endBalance);
|
||||
$diff = bcadd($diff, bcsub($account->endBalance, $account->startBalance));
|
||||
$startAmount = bcadd($startAmount, $account->startBalance);
|
||||
$endAmount = bcadd($endAmount, $account->endBalance);
|
||||
$diff = bcadd($diff, bcsub($account->endBalance, $account->startBalance));
|
||||
}
|
||||
|
||||
$object = new AccountCollection;
|
||||
$object->setStart($start);
|
||||
$object->setEnd($end);
|
||||
$object->setStart($startAmount);
|
||||
$object->setEnd($endAmount);
|
||||
$object->setDifference($diff);
|
||||
$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:
|
||||
* - A budget
|
||||
* - A number of BalanceEntry objects.
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* The BalanceEntry object holds:
|
||||
* - The same budget (again)
|
||||
* - A user asset account as mentioned in the BalanceHeader
|
||||
* - The amount of money spent on the budget by the user asset account
|
||||
* @return Expense
|
||||
*/
|
||||
public function getExpenseReport($start, $end, Collection $accounts)
|
||||
{
|
||||
$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
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
* @return BudgetCollection
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public function getBalanceReport(Carbon $start, Carbon $end, $shared)
|
||||
public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts)
|
||||
{
|
||||
$repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||
$tagRepository = app('FireflyIII\Repositories\Tag\TagRepositoryInterface');
|
||||
$balance = new Balance;
|
||||
|
||||
// build a balance header:
|
||||
$header = new BalanceHeader;
|
||||
|
||||
$accounts = $this->query->getAllAccounts($start, $end, $shared);
|
||||
$budgets = $repository->getBudgets();
|
||||
$header = new BalanceHeader;
|
||||
$budgets = $repository->getBudgets();
|
||||
foreach ($accounts as $account) {
|
||||
$header->addAccount($account);
|
||||
}
|
||||
@@ -134,6 +300,7 @@ class ReportHelper implements ReportHelperInterface
|
||||
|
||||
// get budget amount for current period:
|
||||
$rep = $repository->getCurrentRepetition($budget, $start, $end);
|
||||
// could be null?
|
||||
$line->setRepetition($rep);
|
||||
|
||||
// loop accounts:
|
||||
@@ -142,7 +309,7 @@ class ReportHelper implements ReportHelperInterface
|
||||
$balanceEntry->setAccount($account);
|
||||
|
||||
// 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);
|
||||
$line->addBalanceEntry($balanceEntry);
|
||||
@@ -153,6 +320,7 @@ class ReportHelper implements ReportHelperInterface
|
||||
|
||||
// then a new line for without budget.
|
||||
// and one for the tags:
|
||||
// and one for "left unbalanced".
|
||||
$empty = new BalanceLine;
|
||||
$tags = new BalanceLine;
|
||||
$diffLine = new BalanceLine;
|
||||
@@ -164,7 +332,7 @@ class ReportHelper implements ReportHelperInterface
|
||||
$spent = $this->query->spentNoBudget($account, $start, $end);
|
||||
$left = $tagRepository->coveredByBalancingActs($account, $start, $end);
|
||||
bcscale(2);
|
||||
$diff = bcsub($spent, $left);
|
||||
$diff = bcadd($spent, $left);
|
||||
|
||||
// budget
|
||||
$budgetEntry = new BalanceEntry;
|
||||
@@ -199,16 +367,19 @@ class ReportHelper implements ReportHelperInterface
|
||||
* This method generates a full report for the given period on all
|
||||
* the users bills and their payments.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* Excludes bills which have not had a payment on the mentioned accounts.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return BillCollection
|
||||
*/
|
||||
public function getBillReport(Carbon $start, Carbon $end)
|
||||
public function getBillReport(Carbon $start, Carbon $end, Collection $accounts)
|
||||
{
|
||||
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
|
||||
$repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface');
|
||||
$bills = $repository->getBills();
|
||||
$bills = $repository->getBillsForAccounts($accounts);
|
||||
$collection = new BillCollection;
|
||||
|
||||
/** @var Bill $bill */
|
||||
@@ -238,168 +409,5 @@ class ReportHelper implements ReportHelperInterface
|
||||
}
|
||||
|
||||
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\Expense;
|
||||
use FireflyIII\Helpers\Collection\Income;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface ReportHelperInterface
|
||||
@@ -21,75 +22,78 @@ interface ReportHelperInterface
|
||||
|
||||
/**
|
||||
* 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 $end
|
||||
* @param boolean $shared
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @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
|
||||
* the users bills and their payments.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* Excludes bills which have not had a payment on the mentioned accounts.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return BillCollection
|
||||
*/
|
||||
public function getBillReport(Carbon $start, Carbon $end);
|
||||
public function getBillReport(Carbon $start, Carbon $end, Collection $accounts);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return Balance
|
||||
*/
|
||||
public function getBalanceReport(Carbon $start, Carbon $end, $shared);
|
||||
public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return BudgetCollection
|
||||
*/
|
||||
public function getBudgetReport(Carbon $start, Carbon $end, $shared);
|
||||
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @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 $end
|
||||
* @param boolean $shared
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @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 $end
|
||||
* @param boolean $shared
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return Income
|
||||
*/
|
||||
public function getIncomeReport($start, $end, $shared);
|
||||
public function getIncomeReport($start, $end, Collection $accounts);
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
|
@@ -8,10 +8,10 @@ use Crypt;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class ReportQuery
|
||||
@@ -20,178 +20,6 @@ use Steam;
|
||||
*/
|
||||
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
|
||||
*
|
||||
@@ -202,22 +30,18 @@ class ReportQuery implements ReportQueryInterface
|
||||
*
|
||||
* @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 bcmul(
|
||||
Auth::user()->transactionjournals()
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->where('transactions.account_id', $account->id)
|
||||
->before($end)
|
||||
->after($start)
|
||||
->where('budget_transaction_journal.budget_id', $budget->id)
|
||||
->get(['transaction_journals.*'])->sum('amount'), -1
|
||||
);
|
||||
return Auth::user()->transactionjournals()
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->transactionTypes([TransactionType::WITHDRAWAL])
|
||||
->where('transactions.account_id', $account->id)
|
||||
->before($end)
|
||||
->after($start)
|
||||
->where('budget_transaction_journal.budget_id', $budget->id)
|
||||
->get(['transaction_journals.*'])->sum('amount');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,7 +57,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
Auth::user()->transactionjournals()
|
||||
->leftJoin('transactions', 'transactions.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)
|
||||
->before($end)
|
||||
->after($start)
|
||||
@@ -276,4 +100,144 @@ class ReportQuery implements ReportQueryInterface
|
||||
|
||||
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
|
||||
* 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 bool $includeShared
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return Collection
|
||||
*
|
||||
*/
|
||||
public function expenseInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
public function expenseInPeriod(Carbon $start, Carbon $end, Collection $accounts);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* regards to tags. It will only get the incomes to the specified accounts.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param bool $includeShared
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function incomeInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false);
|
||||
public function incomeInPeriod(Carbon $start, Carbon $end, Collection $accounts);
|
||||
|
||||
/**
|
||||
* Covers tags as well.
|
||||
@@ -65,7 +54,7 @@ interface ReportQueryInterface
|
||||
*
|
||||
* @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
|
||||
|
@@ -38,6 +38,8 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function create($what = 'asset')
|
||||
{
|
||||
|
||||
|
||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||
$subTitle = trans('firefly.make_new_' . $what . '_account');
|
||||
|
||||
@@ -211,13 +213,14 @@ class AccountController extends Controller
|
||||
'name' => $request->input('name'),
|
||||
'accountType' => $request->input('what'),
|
||||
'virtualBalance' => round($request->input('virtualBalance'), 2),
|
||||
'virtualBalanceCurrency' => intval($request->input('amount_currency_id_virtualBalance')),
|
||||
'active' => true,
|
||||
'user' => Auth::user()->id,
|
||||
'iban' => $request->input('iban'),
|
||||
'accountRole' => $request->input('accountRole'),
|
||||
'openingBalance' => round($request->input('openingBalance'), 2),
|
||||
'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;
|
||||
|
||||
use Auth;
|
||||
use Config;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Role;
|
||||
use FireflyIII\User;
|
||||
@@ -8,12 +9,12 @@ use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
|
||||
use Illuminate\Foundation\Auth\ThrottlesLogins;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Mail\Message;
|
||||
use Log;
|
||||
use Mail;
|
||||
use Request as Rq;
|
||||
use Session;
|
||||
use Twig;
|
||||
use Validator;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class AuthController
|
||||
@@ -32,9 +33,8 @@ class AuthController extends Controller
|
||||
public function getLogout()
|
||||
{
|
||||
Auth::logout();
|
||||
Log::debug('Logout and redirect to root.');
|
||||
|
||||
return redirect('/login');
|
||||
return redirect('/auth/login');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,8 +88,8 @@ class AuthController extends Controller
|
||||
$foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first();
|
||||
if (!is_null($foundUser)) {
|
||||
// if it exists, show message:
|
||||
$code = $foundUser->blocked_code;
|
||||
if(strlen($code) == 0) {
|
||||
$code = $foundUser->blocked_code;
|
||||
if (strlen($code) == 0) {
|
||||
$code = 'general_blocked';
|
||||
}
|
||||
$message = trans('firefly.' . $code . '_error', ['email' => $credentials['email']]);
|
||||
@@ -160,21 +160,35 @@ class AuthController extends Controller
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
|
||||
$data = $request->all();
|
||||
$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));
|
||||
|
||||
// get the email address
|
||||
if (Auth::user() instanceof User) {
|
||||
$email = Auth::user()->email;
|
||||
$address = route('index');
|
||||
$email = Auth::user()->email;
|
||||
$address = route('index');
|
||||
$ipAddress = $request->ip();
|
||||
// send email.
|
||||
Mail::send(
|
||||
['emails.registered-html', 'emails.registered'], ['address' => $address], function (Message $message) use ($email) {
|
||||
$message->to($email, $email)->subject('Welcome to Firefly III! ');
|
||||
try {
|
||||
Mail::send(
|
||||
['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
|
||||
Session::flash('success', 'You have registered successfully!');
|
||||
@@ -197,6 +211,35 @@ class AuthController extends Controller
|
||||
// @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.
|
||||
*
|
||||
|
@@ -1,7 +1,11 @@
|
||||
<?php namespace FireflyIII\Http\Controllers\Auth;
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Mail\Message;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
|
||||
/**
|
||||
* Class PasswordController
|
||||
@@ -41,4 +45,38 @@ class PasswordController extends Controller
|
||||
$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\Models\Budget;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use Input;
|
||||
use Navigation;
|
||||
@@ -135,7 +136,7 @@ class BudgetController extends Controller
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(BudgetRepositoryInterface $repository)
|
||||
public function index(BudgetRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$budgets = $repository->getActiveBudgets();
|
||||
$inactive = $repository->getInactiveBudgets();
|
||||
@@ -147,6 +148,8 @@ class BudgetController extends Controller
|
||||
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
|
||||
$budgetIncomeTotal = Preferences::get($key, 1000)->data;
|
||||
$period = Navigation::periodShow($start, $range);
|
||||
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
|
||||
|
||||
bcscale(2);
|
||||
/**
|
||||
* Do some cleanup:
|
||||
@@ -156,7 +159,7 @@ class BudgetController extends Controller
|
||||
// loop the budgets:
|
||||
/** @var Budget $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);
|
||||
if ($budget->currentRep) {
|
||||
$budgeted = bcadd($budgeted, $budget->currentRep->amount);
|
||||
@@ -170,7 +173,7 @@ class BudgetController extends Controller
|
||||
$defaultCurrency = Amount::getDefaultCurrency();
|
||||
|
||||
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 = [
|
||||
'name' => $request->input('name'),
|
||||
'active' => intval($request->input('active')) == 1
|
||||
'active' => intval($request->input('active')) == 1,
|
||||
];
|
||||
|
||||
$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 $year
|
||||
* @param $month
|
||||
* @param bool $shared
|
||||
* @param $url
|
||||
*
|
||||
* @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:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('all');
|
||||
$cache->addProperty('accounts');
|
||||
$cache->addProperty('default');
|
||||
$cache->addProperty($accounts);
|
||||
if ($cache->has()) {
|
||||
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:
|
||||
$data = $this->generator->all($accounts, $start, $end);
|
||||
$data = $this->generator->frontpage($accounts, $start, $end);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
|
@@ -6,6 +6,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -35,13 +36,86 @@ class BudgetController extends Controller
|
||||
$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 Budget $budget
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function budget(BudgetRepositoryInterface $repository, Budget $budget)
|
||||
public function budget(BudgetRepositoryInterface $repository, AccountRepositoryInterface $accountRepository, Budget $budget)
|
||||
{
|
||||
|
||||
// dates and times
|
||||
@@ -50,7 +124,9 @@ class BudgetController extends Controller
|
||||
$last = Session::get('end', new Carbon);
|
||||
$final = clone $last;
|
||||
$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:
|
||||
$cache = new CacheProperties();
|
||||
@@ -68,7 +144,7 @@ class BudgetController extends Controller
|
||||
$end->subDay();
|
||||
$chartDate = clone $end;
|
||||
$chartDate->startOfMonth();
|
||||
$spent = $repository->balanceInPeriod($budget, $first, $end) * -1;
|
||||
$spent = $repository->balanceInPeriod($budget, $first, $end, $accounts) * -1;
|
||||
$entries->push([$chartDate, $spent]);
|
||||
$first = Navigation::addPeriod($first, $range, 0);
|
||||
}
|
||||
@@ -113,7 +189,7 @@ class BudgetController extends Controller
|
||||
/*
|
||||
* Sum of expenses on this day:
|
||||
*/
|
||||
$sum = $repository->expensesOnDayCorrected($budget, $start);
|
||||
$sum = $repository->expensesOnDay($budget, $start);
|
||||
$amount = bcadd($amount, $sum);
|
||||
$entries->push([clone $start, $amount]);
|
||||
$start->addDay();
|
||||
@@ -133,12 +209,13 @@ class BudgetController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function frontpage(BudgetRepositoryInterface $repository)
|
||||
public function frontpage(BudgetRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$budgets = $repository->getBudgets();
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$allEntries = new Collection;
|
||||
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
@@ -156,13 +233,13 @@ class BudgetController extends Controller
|
||||
foreach ($budgets as $budget) {
|
||||
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
|
||||
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]);
|
||||
continue;
|
||||
}
|
||||
/** @var LimitRepetition $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.
|
||||
// $overspent can be more than zero ( = overspending)
|
||||
|
||||
@@ -197,11 +274,8 @@ class BudgetController extends Controller
|
||||
*
|
||||
* @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();
|
||||
$budgets = new Collection;
|
||||
|
||||
@@ -209,16 +283,17 @@ class BudgetController extends Controller
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($report_type);
|
||||
$cache->addProperty($accounts);
|
||||
$cache->addProperty('budget');
|
||||
$cache->addProperty('year');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// filter empty budgets:
|
||||
|
||||
// filter empty budgets:
|
||||
foreach ($allBudgets as $budget) {
|
||||
$spent = $repository->balanceInPeriod($budget, $start, $end, $shared);
|
||||
$spent = $repository->balanceInPeriod($budget, $start, $end, $accounts);
|
||||
if ($spent != 0) {
|
||||
$budgets->push($budget);
|
||||
}
|
||||
@@ -234,14 +309,14 @@ class BudgetController extends Controller
|
||||
|
||||
// each budget, fill the row:
|
||||
foreach ($budgets as $budget) {
|
||||
$spent = $repository->balanceInPeriod($budget, $start, $month, $shared);
|
||||
$spent = $repository->balanceInPeriod($budget, $start, $month, $accounts);
|
||||
$row[] = $spent * -1;
|
||||
}
|
||||
$entries->push($row);
|
||||
$start->endOfMonth()->addDay();
|
||||
}
|
||||
|
||||
$data = $this->generator->year($allBudgets, $entries);
|
||||
$data = $this->generator->year($budgets, $entries);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
|
@@ -107,7 +107,7 @@ class CategoryController extends Controller
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$array = $repository->getCategoriesAndExpensesCorrected($start, $end);
|
||||
$array = $repository->getCategoriesAndExpenses($start, $end);
|
||||
// sort by callback:
|
||||
uasort(
|
||||
$array,
|
||||
@@ -121,6 +121,84 @@ class CategoryController extends Controller
|
||||
);
|
||||
$set = new Collection($array);
|
||||
$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);
|
||||
|
||||
@@ -151,8 +229,8 @@ class CategoryController extends Controller
|
||||
|
||||
|
||||
while ($start <= $end) {
|
||||
$spent = $repository->spentOnDaySumCorrected($category, $start);
|
||||
$earned = $repository->earnedOnDaySumCorrected($category, $start);
|
||||
$spent = $repository->spentOnDaySum($category, $start);
|
||||
$earned = $repository->earnedOnDaySum($category, $start);
|
||||
$date = Navigation::periodShow($start, '1D');
|
||||
$entries->push([clone $start, $date, $spent, $earned]);
|
||||
$start->addDay();
|
||||
@@ -194,8 +272,8 @@ class CategoryController extends Controller
|
||||
|
||||
|
||||
while ($start <= $end) {
|
||||
$spent = $repository->spentOnDaySumCorrected($category, $start);
|
||||
$earned = $repository->earnedOnDaySumCorrected($category, $start);
|
||||
$spent = $repository->spentOnDaySum($category, $start);
|
||||
$earned = $repository->earnedOnDaySum($category, $start);
|
||||
$theDate = Navigation::periodShow($start, '1D');
|
||||
$entries->push([clone $start, $theDate, $spent, $earned]);
|
||||
$start->addDay();
|
||||
@@ -213,31 +291,32 @@ class CategoryController extends Controller
|
||||
* This chart will only show expenses.
|
||||
*
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
* @param $year
|
||||
* @param bool $shared
|
||||
* @param $report_type
|
||||
* @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->addProperty($start);
|
||||
$cache->addProperty($report_type);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($accounts);
|
||||
$cache->addProperty('category');
|
||||
$cache->addProperty('spent-in-year');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$shared = $shared == 'shared' ? true : false;
|
||||
$allCategories = $repository->getCategories();
|
||||
$entries = new Collection;
|
||||
$categories = $allCategories->filter(
|
||||
function (Category $category) use ($repository, $start, $end, $shared) {
|
||||
$spent = $repository->balanceInPeriod($category, $start, $end, $shared);
|
||||
function (Category $category) use ($repository, $start, $end, $accounts) {
|
||||
$spent = $repository->balanceInPeriod($category, $start, $end, $accounts);
|
||||
if ($spent < 0) {
|
||||
return $category;
|
||||
}
|
||||
@@ -252,7 +331,7 @@ class CategoryController extends Controller
|
||||
$row = [clone $start]; // make a 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) {
|
||||
$row[] = $spent * -1;
|
||||
} 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 $year
|
||||
* @param bool $shared
|
||||
* @param $report_type
|
||||
* @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');
|
||||
$end = new Carbon($year . '-12-31');
|
||||
|
||||
$cache = new CacheProperties; // chart properties for cache:
|
||||
$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('earned-in-year');
|
||||
$cache->addProperty('earned-in-period');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
$categories = new Collection;
|
||||
$sets = new Collection;
|
||||
$entries = new Collection;
|
||||
|
||||
$shared = $shared == 'shared' ? true : false;
|
||||
$allCategories = $repository->getCategories();
|
||||
$allEntries = new Collection;
|
||||
$categories = $allCategories->filter(
|
||||
function (Category $category) use ($repository, $start, $end, $shared) {
|
||||
$spent = $repository->balanceInPeriod($category, $start, $end, $shared);
|
||||
if ($spent > 0) {
|
||||
return $category;
|
||||
}
|
||||
|
||||
return null;
|
||||
// run a very special query each month:
|
||||
$start = clone $original;
|
||||
while ($start < $end) {
|
||||
$currentEnd = clone $start;
|
||||
$currentStart = clone $start;
|
||||
$currentStart->startOfMonth();
|
||||
$currentEnd->endOfMonth();
|
||||
// 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);
|
||||
$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) {
|
||||
$month = clone $start; // month is the current end of the period
|
||||
$month->endOfMonth();
|
||||
$row = [clone $start]; // make a row:
|
||||
$currentEnd = clone $start;
|
||||
$currentStart = clone $start;
|
||||
$currentStart->startOfMonth();
|
||||
$currentEnd->endOfMonth();
|
||||
|
||||
foreach ($categories as $category) { // each budget, fill the row
|
||||
$spent = $repository->balanceInPeriod($category, $start, $month, $shared);
|
||||
if ($spent > 0) {
|
||||
$row[] = $spent;
|
||||
// in $sets we have saved all the sets of data for each month
|
||||
// so now we need to retrieve the corrent one.
|
||||
// match is on date of course.
|
||||
$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 {
|
||||
$row[] = 0;
|
||||
}
|
||||
}
|
||||
$allEntries->push($row);
|
||||
$entries->push($row);
|
||||
$start->addMonth();
|
||||
}
|
||||
$data = $this->generator->earnedInYear($categories, $allEntries);
|
||||
|
||||
$data = $this->generator->earnedInPeriod($categories, $entries);
|
||||
$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 Illuminate\Support\Collection;
|
||||
use Response;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class ReportController
|
||||
@@ -37,41 +36,66 @@ class ReportController extends Controller
|
||||
* Summarizes all income and expenses, per month, for a given year.
|
||||
*
|
||||
* @param ReportQueryInterface $query
|
||||
* @param $year
|
||||
* @param bool $shared
|
||||
* @param $report_type
|
||||
* @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:
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('yearInOut');
|
||||
$cache->addProperty($year);
|
||||
$cache->addProperty($shared);
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($accounts);
|
||||
$cache->addProperty($end);
|
||||
if ($cache->has()) {
|
||||
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]);
|
||||
$start->addMonth();
|
||||
// per year?
|
||||
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);
|
||||
|
||||
@@ -81,54 +105,71 @@ class ReportController extends Controller
|
||||
* Summarizes all income and expenses for a given year. Gives a total and an average.
|
||||
*
|
||||
* @param ReportQueryInterface $query
|
||||
* @param $year
|
||||
* @param bool $shared
|
||||
* @param $report_type
|
||||
* @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:
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('yearInOutSummarized');
|
||||
$cache->addProperty($year);
|
||||
$cache->addProperty($shared);
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($accounts);
|
||||
if ($cache->has()) {
|
||||
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';
|
||||
$expense = '0';
|
||||
$count = 0;
|
||||
|
||||
bcscale(2);
|
||||
|
||||
while ($start < $end) {
|
||||
$month = clone $start;
|
||||
$month->endOfMonth();
|
||||
// total income and total expenses:
|
||||
$currentIncome = $query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
|
||||
$currentExpense = $query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
|
||||
|
||||
Log::debug('Date ['.$month->format('M Y').']: income = ['.$income.' + '.$currentIncome.'], out = ['.$expense.' + '.$currentExpense.']');
|
||||
|
||||
$income = bcadd($income, $currentIncome);
|
||||
$expense = bcadd($expense, $currentExpense);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$count++;
|
||||
$start->addMonth();
|
||||
if ($start->diffInMonths($end) > 12) {
|
||||
// per year
|
||||
while ($start < $end) {
|
||||
$startOfYear = clone $start;
|
||||
$startOfYear->startOfYear();
|
||||
$endOfYear = clone $startOfYear;
|
||||
$endOfYear->endOfYear();
|
||||
|
||||
// total income and total expenses:
|
||||
$currentIncome = $query->incomeInPeriod($startOfYear, $endOfYear, $accounts)->sum('amount_positive');
|
||||
$currentExpense = $query->expenseInPeriod($startOfYear, $endOfYear, $accounts)->sum('amount_positive');
|
||||
$income = bcadd($income, $currentIncome);
|
||||
$expense = bcadd($expense, $currentExpense);
|
||||
|
||||
$count++;
|
||||
$start->addYear();
|
||||
}
|
||||
|
||||
$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);
|
||||
|
||||
|
@@ -34,14 +34,15 @@ abstract class Controller extends BaseController
|
||||
View::share('hideTags', false);
|
||||
|
||||
if (Auth::check()) {
|
||||
$pref = Preferences::get('language', 'en');
|
||||
$pref = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US'));
|
||||
$lang = $pref->data;
|
||||
$this->monthFormat = Config::get('firefly.month.' . $lang);
|
||||
$this->monthAndDayFormat = Config::get('firefly.monthAndDay.' . $lang);
|
||||
$this->monthFormat = trans('config.month');
|
||||
$this->monthAndDayFormat = trans('config.month_and_day');
|
||||
|
||||
View::share('monthFormat', $this->monthFormat);
|
||||
View::share('monthAndDayFormat', $this->monthAndDayFormat);
|
||||
View::share('language', $lang);
|
||||
View::share('localeconv', localeconv());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -147,7 +147,7 @@ class CurrencyController extends Controller
|
||||
public function index(CurrencyRepositoryInterface $repository)
|
||||
{
|
||||
$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')) {
|
||||
|
@@ -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 Response;
|
||||
use Session;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class JsonController
|
||||
@@ -72,9 +71,8 @@ class JsonController extends Controller
|
||||
*/
|
||||
public function boxBillsPaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$amount = 0;
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
bcscale(2);
|
||||
|
||||
// works for json too!
|
||||
@@ -85,21 +83,14 @@ class JsonController extends Controller
|
||||
if ($cache->has()) {
|
||||
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 */
|
||||
foreach ($bills as $bill) {
|
||||
$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.
|
||||
// add credit card bill.
|
||||
$creditCards = $accountRepository->getCreditCards($end); // Find credit card accounts and possibly unpaid credit card bills.
|
||||
/** @var Account $creditCard */
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, $end, true); // if the balance is not zero, the monthly payment is still underway.
|
||||
if ($balance == 0) {
|
||||
if ($creditCard->balance == 0) {
|
||||
// find a transfer TO the credit card which should account for
|
||||
// anything paid. If not, the CC is not yet used.
|
||||
$amount = bcadd($amount, $accountRepository->getTransfersInRange($creditCard, $start, $end)->sum('amount'));
|
||||
@@ -149,14 +140,15 @@ class JsonController extends Controller
|
||||
}
|
||||
unset($bill, $bills, $range, $ranges);
|
||||
|
||||
$creditCards = $accountRepository->getCreditCards();
|
||||
$creditCards = $accountRepository->getCreditCards($end);
|
||||
|
||||
/** @var Account $creditCard */
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, $end, true);
|
||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||
if ($balance < 0) {
|
||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||
if ($creditCard->balance < 0) {
|
||||
// unpaid! create a fake bill that matches the amount.
|
||||
$description = $creditCard->name;
|
||||
$fakeAmount = $balance * -1;
|
||||
$fakeAmount = $creditCard->balance * -1;
|
||||
$fakeBill = $repository->createFakeBill($description, $date, $fakeAmount);
|
||||
$unpaid->push([$fakeBill, $date]);
|
||||
}
|
||||
@@ -178,7 +170,7 @@ class JsonController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxIn(ReportQueryInterface $reportQuery)
|
||||
public function boxIn(ReportQueryInterface $reportQuery, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
@@ -191,8 +183,8 @@ class JsonController extends Controller
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$amount = $reportQuery->incomeInPeriodCorrected($start, $end, true)->sum('amount');
|
||||
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
|
||||
$amount = $reportQuery->incomeInPeriod($start, $end, $accounts)->sum('to_amount');
|
||||
|
||||
$data = ['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
|
||||
$cache->store($data);
|
||||
@@ -205,11 +197,12 @@ class JsonController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxOut(ReportQueryInterface $reportQuery)
|
||||
public function boxOut(ReportQueryInterface $reportQuery, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
|
||||
|
||||
// works for json too!
|
||||
$cache = new CacheProperties;
|
||||
@@ -220,8 +213,7 @@ class JsonController extends Controller
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$amount = $reportQuery->expenseInPeriodCorrected($start, $end, true)->sum('amount');
|
||||
$amount = $amount * -1;
|
||||
$amount = $reportQuery->expenseInPeriod($start, $end, $accounts)->sum('to_amount');
|
||||
|
||||
$data = ['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
|
||||
$cache->store($data);
|
||||
@@ -243,7 +235,6 @@ class JsonController extends Controller
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
}
|
||||
sort($return);
|
||||
|
||||
return Response::json($return);
|
||||
}
|
||||
|
@@ -49,7 +49,6 @@ class NewUserController extends Controller
|
||||
*/
|
||||
public function submit(NewUserFormRequest $request, AccountRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
// create normal asset account:
|
||||
$assetAccount = [
|
||||
'name' => $request->get('bank_name'),
|
||||
@@ -61,7 +60,7 @@ class NewUserController extends Controller
|
||||
'accountRole' => 'defaultAsset',
|
||||
'openingBalance' => round($request->input('bank_balance'), 2),
|
||||
'openingBalanceDate' => new Carbon,
|
||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
||||
'openingBalanceCurrency' => intval($request->input('amount_currency_id_bank_balance')),
|
||||
];
|
||||
|
||||
$repository->store($assetAccount);
|
||||
@@ -78,7 +77,7 @@ class NewUserController extends Controller
|
||||
'accountRole' => 'savingAsset',
|
||||
'openingBalance' => round($request->input('savings_balance'), 2),
|
||||
'openingBalanceDate' => new Carbon,
|
||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
||||
'openingBalanceCurrency' => intval($request->input('amount_currency_id_savings_balance')),
|
||||
];
|
||||
$repository->store($savingsAccount);
|
||||
}
|
||||
@@ -96,7 +95,7 @@ class NewUserController extends Controller
|
||||
'accountRole' => 'ccAsset',
|
||||
'openingBalance' => null,
|
||||
'openingBalanceDate' => null,
|
||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
||||
'openingBalanceCurrency' => intval($request->input('amount_currency_id_credit_card_limit')),
|
||||
];
|
||||
$creditCard = $repository->store($creditAccount);
|
||||
|
||||
|
@@ -37,10 +37,12 @@ class PreferencesController extends Controller
|
||||
$viewRange = $viewRangePref->data;
|
||||
$frontPageAccounts = Preferences::get('frontPageAccounts', []);
|
||||
$budgetMax = Preferences::get('budgetMaximum', 1000);
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$language = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US'))->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:
|
||||
$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);
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Session;
|
||||
use View;
|
||||
|
||||
@@ -41,111 +42,190 @@ class ReportController extends Controller
|
||||
*/
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
{
|
||||
$start = Session::get('first');
|
||||
$months = $this->helper->listOfMonths($start);
|
||||
$start = Session::get('first');
|
||||
$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?
|
||||
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
|
||||
$hasShared = false;
|
||||
|
||||
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
|
||||
// get id's for quick links:
|
||||
$accountIds = [];
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
if ($account->getMeta('accountRole') == 'sharedAsset') {
|
||||
$hasShared = true;
|
||||
}
|
||||
$accountIds [] = $account->id;
|
||||
}
|
||||
$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 string $month
|
||||
* @param $report_type
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @param bool $shared
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
* @return 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;
|
||||
$expenseTopLength = 8;
|
||||
|
||||
if ($shared == 'shared') {
|
||||
$shared = true;
|
||||
$subTitle = trans('firefly.reportForYearShared', ['year' => $year]);
|
||||
}
|
||||
$end->endOfYear();
|
||||
|
||||
$accounts = $this->helper->getAccountReport($start, $end, $shared);
|
||||
$incomes = $this->helper->getIncomeReport($start, $end, $shared);
|
||||
$expenses = $this->helper->getExpenseReport($start, $end, $shared);
|
||||
$accountReport = $this->helper->getAccountReport($start, $end, $accounts);
|
||||
$incomes = $this->helper->getIncomeReport($start, $end, $accounts);
|
||||
$expenses = $this->helper->getExpenseReport($start, $end, $accounts);
|
||||
|
||||
Session::flash('gaEventCategory', 'report');
|
||||
Session::flash('gaEventAction', 'year');
|
||||
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(
|
||||
'reports.year',
|
||||
compact('start', 'shared', 'accounts', 'incomes', 'expenses', 'subTitle', 'subTitleIcon', 'incomeTopLength', 'expenseTopLength')
|
||||
'reports.default.year',
|
||||
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\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Input;
|
||||
@@ -45,8 +46,9 @@ class TransactionController extends Controller
|
||||
*
|
||||
* @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'));
|
||||
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
|
||||
$uploadSize = min($maxFileSize, $maxPostSize);
|
||||
@@ -95,7 +97,7 @@ class TransactionController extends Controller
|
||||
*/
|
||||
public function delete(TransactionJournal $journal)
|
||||
{
|
||||
$what = strtolower($journal->transactionType->type);
|
||||
$what = strtolower($journal->getTransactionType());
|
||||
$subTitle = trans('firefly.delete_' . $what, ['description' => $journal->description]);
|
||||
|
||||
// put previous url in session
|
||||
@@ -137,7 +139,7 @@ class TransactionController extends Controller
|
||||
public function edit(AccountRepositoryInterface $repository, TransactionJournal $journal)
|
||||
{
|
||||
// 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!');
|
||||
}
|
||||
|
||||
@@ -145,7 +147,7 @@ class TransactionController extends Controller
|
||||
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
|
||||
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
|
||||
$uploadSize = min($maxFileSize, $maxPostSize);
|
||||
$what = strtolower($journal->transactionType->type);
|
||||
$what = strtolower($journal->getTransactionType());
|
||||
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
||||
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
|
||||
$budgets[0] = trans('form.noBudget');
|
||||
@@ -181,7 +183,7 @@ class TransactionController extends Controller
|
||||
|
||||
$preFilled['amount'] = $journal->amount_positive;
|
||||
|
||||
if ($journal->transactionType->type == 'Withdrawal') {
|
||||
if ($journal->isWithdrawal()) {
|
||||
$preFilled['account_id'] = $journal->source_account->id;
|
||||
$preFilled['expense_account'] = $journal->destination_account->name_for_editform;
|
||||
} else {
|
||||
@@ -269,8 +271,8 @@ class TransactionController extends Controller
|
||||
$t->after = bcadd($t->before, $t->amount);
|
||||
}
|
||||
);
|
||||
$what = strtolower($journal->transactionType->type);
|
||||
$subTitle = trans('firefly.' . $journal->transactionType->type) . ' "' . e($journal->description) . '"';
|
||||
$what = strtolower($journal->getTransactionType());
|
||||
$subTitle = trans('firefly.' . $journal->getTransactionType()) . ' "' . e($journal->description) . '"';
|
||||
|
||||
return view('transactions.show', compact('journal', 'subTitle', 'what'));
|
||||
}
|
||||
@@ -287,7 +289,7 @@ class TransactionController extends Controller
|
||||
$journalData = $request->getJournalData();
|
||||
|
||||
// if not withdrawal, unset budgetid.
|
||||
if ($journalData['what'] != 'withdrawal') {
|
||||
if ($journalData['what'] != strtolower(TransactionType::WITHDRAWAL)) {
|
||||
$journalData['budget_id'] = 0;
|
||||
}
|
||||
|
||||
@@ -308,7 +310,7 @@ class TransactionController extends Controller
|
||||
// rescan journal, UpdateJournalConnection
|
||||
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'))));
|
||||
}
|
||||
|
||||
@@ -340,7 +342,7 @@ class TransactionController extends Controller
|
||||
{
|
||||
|
||||
// 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!');
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,14 @@
|
||||
<?php namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use App;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Closure;
|
||||
use Config;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Http\Request;
|
||||
use Preferences;
|
||||
use Auth;
|
||||
|
||||
/**
|
||||
* Class Authenticate
|
||||
*
|
||||
@@ -55,15 +56,19 @@ class Authenticate
|
||||
|
||||
if (intval($this->auth->user()->blocked) == 1) {
|
||||
Auth::logout();
|
||||
|
||||
return redirect()->route('index');
|
||||
}
|
||||
|
||||
// if logged in, set user language:
|
||||
$pref = Preferences::get('language', 'en');
|
||||
$pref = Preferences::get('language', env('DEFAULT_LANGUAGE','en_US'));
|
||||
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);
|
||||
}
|
||||
|
@@ -41,18 +41,19 @@ class AccountFormRequest extends Request
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $idRule,
|
||||
'name' => $nameRule,
|
||||
'openingBalance' => 'numeric',
|
||||
'iban' => 'iban',
|
||||
'virtualBalance' => 'numeric',
|
||||
'openingBalanceDate' => 'date',
|
||||
'accountRole' => 'in:' . $accountRoles,
|
||||
'active' => 'boolean',
|
||||
'ccType' => 'in:' . $ccPaymentTypes,
|
||||
'ccMonthlyPaymentDate' => 'date',
|
||||
'balance_currency_id' => 'exists:transaction_currencies,id',
|
||||
'what' => 'in:' . $types
|
||||
'id' => $idRule,
|
||||
'name' => $nameRule,
|
||||
'openingBalance' => 'numeric',
|
||||
'iban' => 'iban',
|
||||
'virtualBalance' => 'numeric',
|
||||
'openingBalanceDate' => 'date',
|
||||
'accountRole' => 'in:' . $accountRoles,
|
||||
'active' => 'boolean',
|
||||
'ccType' => 'in:' . $ccPaymentTypes,
|
||||
'ccMonthlyPaymentDate' => 'date',
|
||||
'amount_currency_id_openingBalance' => 'exists:transaction_currencies,id',
|
||||
'amount_currency_id_virtualBalance' => 'exists:transaction_currencies,id',
|
||||
'what' => 'in:' . $types
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -29,17 +29,18 @@ class BillFormRequest extends Request
|
||||
public function getBillData()
|
||||
{
|
||||
return [
|
||||
'name' => $this->get('name'),
|
||||
'match' => $this->get('match'),
|
||||
'amount_min' => round($this->get('amount_min'), 2),
|
||||
'amount_currency_id' => round($this->get('amount_currency_id'), 2),
|
||||
'amount_max' => round($this->get('amount_max'), 2),
|
||||
'date' => new Carbon($this->get('date')),
|
||||
'user' => Auth::user()->id,
|
||||
'repeat_freq' => $this->get('repeat_freq'),
|
||||
'skip' => intval($this->get('skip')),
|
||||
'automatch' => intval($this->get('automatch')) === 1,
|
||||
'active' => intval($this->get('active')) === 1,
|
||||
'name' => $this->get('name'),
|
||||
'match' => $this->get('match'),
|
||||
'amount_min' => round($this->get('amount_min'), 2),
|
||||
'amount_currency_id_amount_min' => intval($this->get('amount_currency_id_amount_min')),
|
||||
'amount_currency_id_amount_max' => intval($this->get('amount_currency_id_amount_max')),
|
||||
'amount_max' => round($this->get('amount_max'), 2),
|
||||
'date' => new Carbon($this->get('date')),
|
||||
'user' => Auth::user()->id,
|
||||
'repeat_freq' => $this->get('repeat_freq'),
|
||||
'skip' => intval($this->get('skip')),
|
||||
'automatch' => intval($this->get('automatch')) === 1,
|
||||
'active' => intval($this->get('active')) === 1,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -56,16 +57,17 @@ class BillFormRequest extends Request
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'name' => $nameRule,
|
||||
'match' => $matchRule,
|
||||
'amount_min' => 'required|numeric|min:0.01',
|
||||
'amount_max' => 'required|numeric|min:0.01',
|
||||
'amount_currency_id' => 'required|exists:transaction_currencies,id',
|
||||
'date' => 'required|date',
|
||||
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
|
||||
'skip' => 'required|between:0,31',
|
||||
'automatch' => 'in:1',
|
||||
'active' => 'in:1',
|
||||
'name' => $nameRule,
|
||||
'match' => $matchRule,
|
||||
'amount_min' => 'required|numeric|min:0.01',
|
||||
'amount_max' => 'required|numeric|min:0.01',
|
||||
'amount_currency_id_amount_min' => 'required|exists:transaction_currencies,id',
|
||||
'amount_currency_id_amount_max' => 'required|exists:transaction_currencies,id',
|
||||
'date' => 'required|date',
|
||||
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
|
||||
'skip' => 'required|between:0,31',
|
||||
'automatch' => 'in:1',
|
||||
'active' => 'in:1',
|
||||
];
|
||||
|
||||
return $rules;
|
||||
|
@@ -5,6 +5,7 @@ namespace FireflyIII\Http\Requests;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Input;
|
||||
|
||||
/**
|
||||
@@ -30,20 +31,20 @@ class JournalFormRequest extends Request
|
||||
public function getJournalData()
|
||||
{
|
||||
return [
|
||||
'what' => $this->get('what'),
|
||||
'description' => $this->get('description'),
|
||||
'account_id' => intval($this->get('account_id')),
|
||||
'account_from_id' => intval($this->get('account_from_id')),
|
||||
'account_to_id' => intval($this->get('account_to_id')),
|
||||
'expense_account' => $this->get('expense_account'),
|
||||
'revenue_account' => $this->get('revenue_account'),
|
||||
'amount' => round($this->get('amount'), 2),
|
||||
'user' => Auth::user()->id,
|
||||
'amount_currency_id' => intval($this->get('amount_currency_id')),
|
||||
'date' => new Carbon($this->get('date')),
|
||||
'budget_id' => intval($this->get('budget_id')),
|
||||
'category' => $this->get('category'),
|
||||
'tags' => explode(',', $this->get('tags')),
|
||||
'what' => $this->get('what'),
|
||||
'description' => $this->get('description'),
|
||||
'account_id' => intval($this->get('account_id')),
|
||||
'account_from_id' => intval($this->get('account_from_id')),
|
||||
'account_to_id' => intval($this->get('account_to_id')),
|
||||
'expense_account' => $this->get('expense_account'),
|
||||
'revenue_account' => $this->get('revenue_account'),
|
||||
'amount' => round($this->get('amount'), 2),
|
||||
'user' => Auth::user()->id,
|
||||
'amount_currency_id_amount' => intval($this->get('amount_currency_id_amount')),
|
||||
'date' => new Carbon($this->get('date')),
|
||||
'budget_id' => intval($this->get('budget_id')),
|
||||
'category' => $this->get('category'),
|
||||
'tags' => explode(',', $this->get('tags')),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -56,16 +57,16 @@ class JournalFormRequest extends Request
|
||||
{
|
||||
$what = Input::get('what');
|
||||
$rules = [
|
||||
'description' => 'required|min:1,max:255',
|
||||
'what' => 'required|in:withdrawal,deposit,transfer',
|
||||
'amount' => 'numeric|required|min:0.01',
|
||||
'date' => 'required|date',
|
||||
'amount_currency_id' => 'required|exists:transaction_currencies,id',
|
||||
'description' => 'required|min:1,max:255',
|
||||
'what' => 'required|in:withdrawal,deposit,transfer',
|
||||
'amount' => 'numeric|required|min:0.01',
|
||||
'date' => 'required|date',
|
||||
'amount_currency_id_amount' => 'required|exists:transaction_currencies,id',
|
||||
|
||||
];
|
||||
|
||||
switch ($what) {
|
||||
case 'withdrawal':
|
||||
case strtolower(TransactionType::WITHDRAWAL):
|
||||
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
|
||||
$rules['expense_account'] = 'between:1,255';
|
||||
$rules['category'] = 'between:1,255';
|
||||
@@ -73,12 +74,12 @@ class JournalFormRequest extends Request
|
||||
$rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets';
|
||||
}
|
||||
break;
|
||||
case 'deposit':
|
||||
case strtolower(TransactionType::DEPOSIT):
|
||||
$rules['category'] = 'between:1,255';
|
||||
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
|
||||
$rules['revenue_account'] = 'between:1,255';
|
||||
break;
|
||||
case 'transfer':
|
||||
case strtolower(TransactionType::TRANSFER):
|
||||
$rules['account_from_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_to_id';
|
||||
$rules['account_to_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_from_id';
|
||||
$rules['category'] = 'between:1,255';
|
||||
|
@@ -27,11 +27,13 @@ class NewUserFormRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'bank_name' => 'required|between:1,200',
|
||||
'bank_balance' => 'required|numeric',
|
||||
'savings_balance' => 'numeric',
|
||||
'credit_card_limit' => 'numeric',
|
||||
'balance_currency_id' => 'exists:transaction_currencies,id',
|
||||
'bank_name' => 'required|between:1,200',
|
||||
'bank_balance' => 'required|numeric',
|
||||
'savings_balance' => 'numeric',
|
||||
'credit_card_limit' => 'numeric',
|
||||
'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 = [
|
||||
'name' => $nameRule,
|
||||
'account_id' => 'required|belongsToUser:accounts',
|
||||
'targetamount' => 'required|min:0.01',
|
||||
'amount_currency_id' => 'exists:transaction_currencies,id',
|
||||
'startdate' => 'date',
|
||||
'targetdate' => $targetDateRule,
|
||||
'order' => 'integer|min:1',
|
||||
'name' => $nameRule,
|
||||
'account_id' => 'required|belongsToUser:accounts',
|
||||
'targetamount' => 'required|min:0.01',
|
||||
'amount_currency_id_targetamount' => 'exists:transaction_currencies,id',
|
||||
'startdate' => 'date',
|
||||
'targetdate' => $targetDateRule,
|
||||
'order' => 'integer|min:1',
|
||||
|
||||
];
|
||||
|
||||
|
@@ -351,30 +351,13 @@ 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');
|
||||
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(
|
||||
'reports.month', function (Generator $breadcrumbs, Carbon $date, $shared) {
|
||||
$breadcrumbs->parent('reports.year', $date, $shared);
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
$monthFormat = trans('config.month_and_day');
|
||||
$title = trans('firefly.report_default', ['start' => $start->formatLocalized($monthFormat), 'end' => $end->formatLocalized($monthFormat)]);
|
||||
|
||||
if ($shared) {
|
||||
$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]));
|
||||
$breadcrumbs->push($title, route('reports.report', ['url' => 'abcde']));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -416,7 +399,7 @@ Breadcrumbs::register(
|
||||
Breadcrumbs::register(
|
||||
'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]));
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\Bill;
|
||||
@@ -29,6 +30,111 @@ Route::bind(
|
||||
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(
|
||||
'tj', function ($value) {
|
||||
@@ -162,7 +268,7 @@ Route::get('/cron/sendgrid', ['uses' => 'CronController@sendgrid']);
|
||||
|
||||
Route::controllers(
|
||||
[
|
||||
'auth' => 'Auth\AuthController',
|
||||
'auth' => 'Auth\AuthController',
|
||||
'password' => 'Auth\PasswordController',
|
||||
]
|
||||
);
|
||||
@@ -178,7 +284,6 @@ Route::group(
|
||||
Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']);
|
||||
Route::post('/daterange', ['uses' => 'HomeController@dateRange', 'as' => 'daterange']);
|
||||
Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']);
|
||||
Route::get('/routes', ['uses' => 'HomeController@routes']);
|
||||
/**
|
||||
* Account Controller
|
||||
*/
|
||||
@@ -284,9 +389,7 @@ Route::group(
|
||||
// accounts:
|
||||
Route::get('/chart/account/frontpage', ['uses' => 'Chart\AccountController@frontpage']);
|
||||
Route::get('/chart/account/expense', ['uses' => 'Chart\AccountController@expenseAccounts']);
|
||||
Route::get('/chart/account/month/{year}/{month}/{shared?}', ['uses' => 'Chart\AccountController@all'])->where(
|
||||
['year' => '[0-9]{4}', 'month' => '[0-9]{1,2}', 'shared' => 'shared']
|
||||
);
|
||||
Route::get('/chart/account/report/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\AccountController@report']);
|
||||
Route::get('/chart/account/{account}', ['uses' => 'Chart\AccountController@single']);
|
||||
|
||||
|
||||
@@ -296,18 +399,24 @@ Route::group(
|
||||
|
||||
// budgets:
|
||||
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}', ['uses' => 'Chart\BudgetController@budget']);
|
||||
|
||||
// categories:
|
||||
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']
|
||||
);
|
||||
Route::get('/chart/category/earned-in-year/{year}/{shared?}', ['uses' => 'Chart\CategoryController@earnedInYear'])->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/spent-in-period/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\CategoryController@spentInPeriod']);
|
||||
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/{date}', ['uses' => 'Chart\CategoryController@specificPeriod']);
|
||||
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']);
|
||||
|
||||
// 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-sum/{year}/{shared?}', ['uses' => 'Chart\ReportController@yearInOutSummarized'])->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/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\ReportController@yearInOutSummarized']);
|
||||
|
||||
|
||||
/**
|
||||
@@ -385,12 +492,7 @@ Route::group(
|
||||
* Report Controller
|
||||
*/
|
||||
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/{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:
|
||||
Route::get('/reports/report/{report_type}/{start_date}/{end_date}/{accountList}', ['uses' => 'ReportController@report', 'as' => 'reports.report']);
|
||||
|
||||
/**
|
||||
* 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 whereNameEncrypted($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereMatchEncrypted($value)
|
||||
* @property \Carbon\Carbon $nextExpectedMatch
|
||||
* @property \Carbon\Carbon $lastFoundMatch
|
||||
* @property \Carbon\Carbon $nextExpectedMatch
|
||||
* @property \Carbon\Carbon $lastFoundMatch
|
||||
*/
|
||||
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 whereEncrypted($value)
|
||||
* @property-read float $spent
|
||||
* @property \Carbon\Carbon $lastActivity
|
||||
* @property \Carbon\Carbon $lastActivity
|
||||
*/
|
||||
class Category extends Model
|
||||
{
|
||||
|
@@ -68,6 +68,7 @@ use Watson\Validating\ValidatingTrait;
|
||||
* @property-read int $account_id
|
||||
* @property string $name
|
||||
* @property-read string $symbol
|
||||
* @property-read string $type
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Attachment[] $attachments
|
||||
* @property-read mixed $amount_positive
|
||||
*/
|
||||
@@ -147,10 +148,9 @@ class TransactionJournal extends Model
|
||||
}
|
||||
|
||||
bcscale(2);
|
||||
$type = $this->transactionType->type;
|
||||
$transaction = $this->transactions->sortByDesc('amount')->first();
|
||||
$amount = $transaction->amount;
|
||||
if ($type == 'Withdrawal') {
|
||||
if ($this->isWithdrawal()) {
|
||||
$amount = $amount * -1;
|
||||
}
|
||||
$cache->store($amount);
|
||||
@@ -167,15 +167,15 @@ class TransactionJournal extends Model
|
||||
*/
|
||||
protected function amountByTagAdvancePayment(Tag $tag, $amount)
|
||||
{
|
||||
if ($this->transactionType->type == 'Withdrawal') {
|
||||
$others = $tag->transactionJournals()->transactionTypes(['Deposit'])->get();
|
||||
if ($this->isWithdrawal()) {
|
||||
$others = $tag->transactionJournals()->transactionTypes([TransactionType::DEPOSIT])->get();
|
||||
foreach ($others as $other) {
|
||||
$amount = bcsub($amount, $other->amount_positive);
|
||||
}
|
||||
|
||||
return $amount;
|
||||
}
|
||||
if ($this->transactionType->type == 'Deposit') {
|
||||
if ($this->isDeposit()) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
@@ -190,8 +190,8 @@ class TransactionJournal extends Model
|
||||
*/
|
||||
protected function amountByTagBalancingAct($tag, $amount)
|
||||
{
|
||||
if ($this->transactionType->type == 'Withdrawal') {
|
||||
$transfer = $tag->transactionJournals()->transactionTypes(['Transfer'])->first();
|
||||
if ($this->isWithdrawal()) {
|
||||
$transfer = $tag->transactionJournals()->transactionTypes([TransactionType::TRANSFER])->first();
|
||||
if ($transfer) {
|
||||
$amount = bcsub($amount, $transfer->amount_positive);
|
||||
|
||||
@@ -491,4 +491,59 @@ class TransactionJournal extends Model
|
||||
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;
|
||||
|
||||
const WITHDRAWAL = 'Withdrawal';
|
||||
const DEPOSIT = 'Deposit';
|
||||
const TRANSFER = 'Transfer';
|
||||
const OPENING_BALANCE = 'Opening balance';
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
@@ -31,6 +36,38 @@ class TransactionType extends Model
|
||||
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
|
||||
*/
|
||||
|
@@ -41,7 +41,16 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
*/
|
||||
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)
|
||||
{
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty('get-accounts');
|
||||
$cache->addProperty($types);
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
/** @var Collection $result */
|
||||
$result = Auth::user()->accounts()->with(
|
||||
['accountmeta' => function (HasMany $query) {
|
||||
@@ -82,23 +99,39 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
}
|
||||
);
|
||||
|
||||
$cache->store($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
|
||||
*/
|
||||
public function getCreditCards()
|
||||
public function getCreditCards(Carbon $date)
|
||||
{
|
||||
return Auth::user()->accounts()
|
||||
->hasMetaValue('accountRole', 'ccAsset')
|
||||
->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(
|
||||
[
|
||||
'accounts.*',
|
||||
'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)
|
||||
{
|
||||
$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)
|
||||
{
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($preference->data);
|
||||
$cache->addProperty('frontPageaccounts');
|
||||
$cache->addProperty('user-frontpage-accounts');
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
@@ -158,6 +200,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
$cache->addProperty($account->id);
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('frontpage-transactions');
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
@@ -172,6 +215,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
->before($end)
|
||||
->after($start)
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->take(10)
|
||||
->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']);
|
||||
@@ -227,14 +271,14 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($ids);
|
||||
$cache->addProperty('piggyAccounts');
|
||||
$cache->addProperty('user-piggy-bank-accounts');
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$ids = array_unique($ids);
|
||||
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);
|
||||
|
||||
@@ -273,6 +317,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')
|
||||
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
|
||||
->where('account_meta.name', 'accountRole')
|
||||
->where('accounts.active', 1)
|
||||
->where('account_meta.data', '"savingAsset"')
|
||||
->get(['accounts.*']);
|
||||
$start = clone Session::get('start', new Carbon);
|
||||
@@ -319,31 +364,23 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
*/
|
||||
public function getTransfersInRange(Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
$set = TransactionJournal::whereIn(
|
||||
$set = TransactionJournal::whereIn(
|
||||
'id', function (Builder $q) use ($account, $start, $end) {
|
||||
$q->select('transaction_journals.id')
|
||||
->from('transactions')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_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.date', '>=', $start->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();
|
||||
$filtered = $set->filter(
|
||||
function (TransactionJournal $journal) use ($account) {
|
||||
if ($journal->destination_account->id == $account->id) {
|
||||
return $journal;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
return $filtered;
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -372,12 +409,23 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
*/
|
||||
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')
|
||||
->accountIs($account)
|
||||
->transactionTypes(['Opening balance'])
|
||||
->transactionTypes([TransactionType::OPENING_BALANCE])
|
||||
->orderBy('created_at', 'ASC')
|
||||
->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)
|
||||
{
|
||||
$transactionType = TransactionType::whereType('Opening balance')->first();
|
||||
$transactionType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
|
||||
$journal = TransactionJournal::create(
|
||||
[
|
||||
'user_id' => $data['user'],
|
||||
@@ -642,4 +690,16 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* @param $accountId
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @return Account
|
||||
*/
|
||||
public function find($accountId);
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param Account $moveTo
|
||||
@@ -48,9 +57,17 @@ interface AccountRepositoryInterface
|
||||
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
|
||||
*/
|
||||
public function getCreditCards();
|
||||
public function getCreditCards(Carbon $date);
|
||||
|
||||
/**
|
||||
* Get the accounts of a user that have piggy banks connected to them.
|
||||
|
@@ -5,9 +5,11 @@ namespace FireflyIII\Repositories\Bill;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Navigation;
|
||||
@@ -21,6 +23,7 @@ use Steam;
|
||||
class BillRepository implements BillRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated
|
||||
* Returns the sum of all payments connected to this bill between the dates.
|
||||
*
|
||||
* @param Bill $bill
|
||||
@@ -83,7 +86,7 @@ class BillRepository implements BillRepositoryInterface
|
||||
public function getActiveBills()
|
||||
{
|
||||
/** @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;
|
||||
}
|
||||
@@ -108,6 +111,46 @@ class BillRepository implements BillRepositoryInterface
|
||||
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
|
||||
*
|
||||
@@ -154,7 +197,7 @@ class BillRepository implements BillRepositoryInterface
|
||||
}
|
||||
$journals = new Collection;
|
||||
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.*']
|
||||
);
|
||||
}
|
||||
@@ -276,12 +319,21 @@ class BillRepository implements BillRepositoryInterface
|
||||
*/
|
||||
public function scan(Bill $bill, TransactionJournal $journal)
|
||||
{
|
||||
|
||||
/*
|
||||
* Can only support withdrawals.
|
||||
*/
|
||||
if (false === $journal->isWithdrawal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$matches = explode(',', $bill->match);
|
||||
$description = strtolower($journal->description) . ' ' . strtolower($journal->destination_account->name);
|
||||
$wordMatch = $this->doWordMatch($matches, $description);
|
||||
$amountMatch = $this->doAmountMatch($journal->amount_positive, $bill->amount_min, $bill->amount_max);
|
||||
Log::debug('Journal #' . $journal->id . ' has description "' . $description . '"');
|
||||
|
||||
|
||||
/*
|
||||
* If both, update!
|
||||
*/
|
||||
@@ -446,22 +498,21 @@ class BillRepository implements BillRepositoryInterface
|
||||
{
|
||||
|
||||
$accounts = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
$creditCards = $accounts->getCreditCards();
|
||||
$creditCards = $accounts->getCreditCards($end);
|
||||
$paid = $set->get('paid');
|
||||
$unpaid = $set->get('unpaid');
|
||||
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, $end, true);
|
||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||
if ($balance < 0) {
|
||||
if ($creditCard->balance < 0) {
|
||||
// unpaid! create a fake bill that matches the amount.
|
||||
$description = $creditCard->name;
|
||||
$amount = $balance * -1;
|
||||
$amount = $creditCard->balance * -1;
|
||||
$fakeBill = $this->createFakeBill($description, $date, $amount);
|
||||
unset($description, $amount);
|
||||
$unpaid->push([$fakeBill, $date]);
|
||||
}
|
||||
if ($balance == 0) {
|
||||
if ($creditCard->balance == 0) {
|
||||
// find transfer(s) TO the credit card which should account for
|
||||
// anything paid. If not, the CC is not yet used.
|
||||
$journals = $accounts->getTransfersInRange($creditCard, $start, $end);
|
||||
@@ -474,4 +525,32 @@ class BillRepository implements BillRepositoryInterface
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Returns the sum of all payments connected to this bill between the dates.
|
||||
*
|
||||
* @param Bill $bill
|
||||
@@ -49,6 +50,17 @@ interface BillRepositoryInterface
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -77,6 +89,15 @@ interface BillRepositoryInterface
|
||||
*/
|
||||
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
|
||||
*
|
||||
|
@@ -7,6 +7,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Shared\ComponentRepository;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
@@ -50,10 +51,10 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function expensesOnDayCorrected(Budget $budget, Carbon $date)
|
||||
public function expensesOnDay(Budget $budget, Carbon $date)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -139,9 +140,11 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
$data = $budget->limitrepetitions()
|
||||
->where('limit_repetitions.startdate', $start)
|
||||
->where('limit_repetitions.enddate', $end)
|
||||
->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00'))
|
||||
->where('limit_repetitions.enddate', $end->format('Y-m-d 00:00:00'))
|
||||
->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);
|
||||
|
||||
return $data;
|
||||
@@ -226,6 +229,8 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Carbon
|
||||
@@ -241,6 +246,7 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
@@ -303,25 +309,23 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
|
||||
)
|
||||
->after($start)
|
||||
->before($end)
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->transactionTypes([TransactionType::WITHDRAWAL])
|
||||
->get(['transaction_journals.*'])->sum('amount');
|
||||
|
||||
bcscale(2);
|
||||
|
||||
return bcmul($noBudgetSet, -1);
|
||||
return $noBudgetSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param bool $shared
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public function expensesOnDayCorrected(Budget $budget, Carbon $date);
|
||||
public function expensesOnDay(Budget $budget, Carbon $date);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
@@ -96,6 +96,7 @@ interface BudgetRepositoryInterface
|
||||
public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50);
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Carbon
|
||||
@@ -103,6 +104,7 @@ interface BudgetRepositoryInterface
|
||||
public function getLastBudgetLimitDate(Budget $budget);
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param Budget $budget
|
||||
* @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 Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @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
|
||||
|
@@ -5,10 +5,13 @@ namespace FireflyIII\Repositories\Category;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Crypt;
|
||||
use DB;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Shared\ComponentRepository;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
@@ -47,6 +50,13 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
||||
*/
|
||||
public function getCategories()
|
||||
{
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('category-list');
|
||||
|
||||
if($cache->has()) {
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
/** @var Collection $set */
|
||||
$set = Auth::user()->categories()->orderBy('name', 'ASC')->get();
|
||||
$set = $set->sortBy(
|
||||
@@ -55,9 +65,76 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
||||
}
|
||||
);
|
||||
|
||||
$cache->store($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
|
||||
*/
|
||||
public function getCategoriesAndExpensesCorrected(Carbon $start, Carbon $end)
|
||||
public function getCategoriesAndExpenses(Carbon $start, Carbon $end)
|
||||
{
|
||||
$set = Auth::user()->transactionjournals()
|
||||
->leftJoin(
|
||||
@@ -76,7 +153,7 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
||||
->before($end)
|
||||
->where('categories.user_id', Auth::user()->id)
|
||||
->after($start)
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->transactionTypes([TransactionType::WITHDRAWAL])
|
||||
->get(['categories.id as category_id', 'categories.encrypted as category_encrypted', 'categories.name', 'transaction_journals.*']);
|
||||
|
||||
bcscale(2);
|
||||
@@ -177,17 +254,16 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @param bool $shared
|
||||
* @param Category $category
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
* limited by a start or end date.
|
||||
*
|
||||
@@ -285,9 +362,10 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$sum = $category->transactionjournals()->transactionTypes(['Withdrawal'])->before($end)->after($start)->get(['transaction_journals.*'])->sum(
|
||||
'amount'
|
||||
);
|
||||
$sum = $category->transactionjournals()->transactionTypes([TransactionType::WITHDRAWAL])->before($end)->after($start)->get(['transaction_journals.*'])
|
||||
->sum(
|
||||
'amount'
|
||||
);
|
||||
|
||||
$cache->store($sum);
|
||||
|
||||
@@ -315,9 +393,10 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$sum = $category->transactionjournals()->transactionTypes(['Deposit'])->before($end)->after($start)->get(['transaction_journals.*'])->sum(
|
||||
'amount'
|
||||
);
|
||||
$sum = $category->transactionjournals()->transactionTypes([TransactionType::DEPOSIT])->before($end)->after($start)->get(['transaction_journals.*'])
|
||||
->sum(
|
||||
'amount'
|
||||
);
|
||||
|
||||
$cache->store($sum);
|
||||
|
||||
@@ -365,8 +444,165 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -47,7 +120,7 @@ interface CategoryRepositoryInterface
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCategoriesAndExpensesCorrected(Carbon $start, Carbon $end);
|
||||
public function getCategoriesAndExpenses(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
@@ -73,12 +146,13 @@ interface CategoryRepositoryInterface
|
||||
public function getJournalsInRange(Category $category, $page, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* This method returns the sum of the journals in the category, optionally
|
||||
* limited by a start or end date.
|
||||
*
|
||||
* @param Category $category
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -100,17 +174,16 @@ interface CategoryRepositoryInterface
|
||||
public function getWithoutCategory(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* Corrected for tags.
|
||||
* Corrected for tags and list of accounts.
|
||||
*
|
||||
* @param Category $category
|
||||
* @param \Carbon\Carbon $start
|
||||
* @param \Carbon\Carbon $end
|
||||
*
|
||||
* @param bool $shared
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @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
|
||||
@@ -143,7 +216,7 @@ interface CategoryRepositoryInterface
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentOnDaySumCorrected(Category $category, Carbon $date);
|
||||
public function spentOnDaySum(Category $category, Carbon $date);
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -154,7 +227,7 @@ interface CategoryRepositoryInterface
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function earnedOnDaySumCorrected(Category $category, Carbon $date);
|
||||
public function earnedOnDaySum(Category $category, Carbon $date);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
|
@@ -13,6 +13,7 @@ use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
@@ -44,7 +45,16 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
*/
|
||||
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'],
|
||||
'transaction_type_id' => $transactionType->id,
|
||||
'transaction_currency_id' => $data['amount_currency_id'],
|
||||
'transaction_currency_id' => $data['amount_currency_id_amount'],
|
||||
'description' => $data['description'],
|
||||
'completed' => 0,
|
||||
'date' => $data['date'],
|
||||
@@ -327,15 +337,15 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
$fromAccount = null;
|
||||
$toAccount = null;
|
||||
switch ($type->type) {
|
||||
case 'Withdrawal':
|
||||
case TransactionType::WITHDRAWAL:
|
||||
list($fromAccount, $toAccount) = $this->storeWithdrawalAccounts($data);
|
||||
break;
|
||||
|
||||
case 'Deposit':
|
||||
case TransactionType::DEPOSIT:
|
||||
list($fromAccount, $toAccount) = $this->storeDepositAccounts($data);
|
||||
|
||||
break;
|
||||
case 'Transfer':
|
||||
case TransactionType::TRANSFER:
|
||||
$fromAccount = Account::find($data['account_from_id']);
|
||||
$toAccount = Account::find($data['account_to_id']);
|
||||
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;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class ComponentRepository
|
||||
@@ -14,46 +17,42 @@ use Illuminate\Database\Query\JoinClause;
|
||||
class ComponentRepository
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param $object
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @param bool $shared
|
||||
* @param $object
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @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->addProperty($object->id);
|
||||
$cache->addProperty(get_class($object));
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($shared);
|
||||
$cache->addProperty('balanceInPeriod');
|
||||
$cache->addProperty($accounts);
|
||||
$cache->addProperty('balanceInPeriodList');
|
||||
|
||||
$ids = [];
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$ids[] = $account->id;
|
||||
}
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
if ($shared === true) { // shared is true: always ignore transfers between accounts!
|
||||
$sum = $object->transactionjournals()->transactionTypes(['Withdrawal', 'Deposit', 'Opening balance'])->before($end)->after($start)
|
||||
->get(['transaction_journals.*'])->sum('amount');
|
||||
} else {
|
||||
// do something else, SEE budgets.
|
||||
// get all journals in this month where the asset account is NOT shared.
|
||||
$sum = $object->transactionjournals()->before($end)->after($start)
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->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');
|
||||
}
|
||||
$sum = $object->transactionjournals()
|
||||
->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE])
|
||||
->before($end)
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
||||
->whereIn('accounts.id', $ids)
|
||||
->after($start)
|
||||
->get(['transaction_journals.*'])->sum('amount');
|
||||
|
||||
$cache->store($sum);
|
||||
|
||||
|
@@ -9,6 +9,7 @@ use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
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
|
||||
* 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.
|
||||
@@ -77,7 +79,9 @@ class TagRepository implements TagRepositoryInterface
|
||||
|
||||
/** @var Tag $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 */
|
||||
foreach ($journals as $journal) {
|
||||
@@ -108,6 +112,13 @@ class TagRepository implements TagRepositoryInterface
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('tags-list');
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
/** @var Collection $tags */
|
||||
$tags = Auth::user()->tags()->get();
|
||||
$tags = $tags->sortBy(
|
||||
@@ -116,6 +127,8 @@ class TagRepository implements TagRepositoryInterface
|
||||
}
|
||||
);
|
||||
|
||||
$cache->store($tags);
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
@@ -158,7 +171,7 @@ class TagRepository implements TagRepositoryInterface
|
||||
|
||||
if ($tag->tagMode == 'balancingAct' || $tag->tagMode == 'nothing') {
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->transactionType->type == 'Transfer') {
|
||||
if ($journal->isTransfer()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -169,7 +182,7 @@ class TagRepository implements TagRepositoryInterface
|
||||
*/
|
||||
$count = 0;
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->transactionType->type == 'Withdrawal') {
|
||||
if ($journal->isWithdrawal()) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
@@ -201,7 +214,7 @@ class TagRepository implements TagRepositoryInterface
|
||||
* If any transaction is a deposit, cannot become a balancing act.
|
||||
*/
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->transactionType->type == 'Deposit') {
|
||||
if ($journal->isDeposit()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -239,10 +252,10 @@ class TagRepository implements TagRepositoryInterface
|
||||
protected function connectBalancingAct(TransactionJournal $journal, Tag $tag)
|
||||
{
|
||||
/** @var TransactionType $withdrawal */
|
||||
$withdrawal = TransactionType::whereType('Withdrawal')->first();
|
||||
$withdrawal = TransactionType::whereType(TransactionType::WITHDRAWAL)->first();
|
||||
$withdrawals = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->count();
|
||||
/** @var TransactionType $transfer */
|
||||
$transfer = TransactionType::whereType('Transfer')->first();
|
||||
$transfer = TransactionType::whereType(TransactionType::TRANSFER)->first();
|
||||
$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)
|
||||
{
|
||||
/** @var TransactionType $transfer */
|
||||
$transfer = TransactionType::whereType('Transfer')->first();
|
||||
$transfer = TransactionType::whereType(TransactionType::TRANSFER)->first();
|
||||
/** @var TransactionType $withdrawal */
|
||||
$withdrawal = TransactionType::whereType('Withdrawal')->first();
|
||||
$withdrawal = TransactionType::whereType(TransactionType::WITHDRAWAL)->first();
|
||||
/** @var TransactionType $deposit */
|
||||
$deposit = TransactionType::whereType('Deposit')->first();
|
||||
$deposit = TransactionType::whereType(TransactionType::DEPOSIT)->first();
|
||||
|
||||
$withdrawals = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->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) {
|
||||
// $checkAccount is the source_account for a withdrawal
|
||||
// $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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,7 @@ interface TagRepositoryInterface
|
||||
public function connect(TransactionJournal $journal, Tag $tag);
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* 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
|
||||
* transferred into the balancing act (if any) and return this amount.
|
||||
|
@@ -40,7 +40,7 @@ class Amount
|
||||
if ($cache->has()) {
|
||||
return $cache->get();
|
||||
} else {
|
||||
$currencyPreference = Prefs::get('currencyPreference', 'EUR');
|
||||
$currencyPreference = Prefs::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR'));
|
||||
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||
|
||||
$cache->store($currency->symbol);
|
||||
@@ -60,7 +60,7 @@ class Amount
|
||||
{
|
||||
$amount = floatval($amount);
|
||||
$amount = round($amount, 2);
|
||||
$string = number_format($amount, 2, ',', '.');
|
||||
$string = money_format('%!.2n', $amount);
|
||||
|
||||
if ($coloured === true) {
|
||||
if ($amount === 0.0) {
|
||||
@@ -100,13 +100,13 @@ class Amount
|
||||
$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>';
|
||||
$cache->store($txt);
|
||||
|
||||
return $txt;
|
||||
}
|
||||
if ($journal->transactionType->type == 'Transfer' && !$coloured) {
|
||||
if ($journal->isTransfer() && !$coloured) {
|
||||
$txt = $this->formatWithSymbol($symbol, $journal->amount_positive, false);
|
||||
$cache->store($txt);
|
||||
|
||||
@@ -152,7 +152,7 @@ class Amount
|
||||
if ($cache->has()) {
|
||||
return $cache->get();
|
||||
} else {
|
||||
$currencyPreference = Prefs::get('currencyPreference', 'EUR');
|
||||
$currencyPreference = Prefs::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR'));
|
||||
|
||||
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||
if ($currency) {
|
||||
@@ -161,9 +161,9 @@ class Amount
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@@ -23,10 +23,10 @@ class Budget extends Twig_Extension
|
||||
{
|
||||
$functions = [];
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'spentInRepetitionCorrected', function (LimitRepetition $repetition) {
|
||||
'spentInRepetition', function (LimitRepetition $repetition) {
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($repetition->id);
|
||||
$cache->addProperty('spentInRepetitionCorrected');
|
||||
$cache->addProperty('spentInRepetition');
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
@@ -68,19 +68,17 @@ class Journal extends Twig_Extension
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$type = $journal->transactionType->type;
|
||||
|
||||
switch ($type) {
|
||||
case 'Withdrawal':
|
||||
switch (true) {
|
||||
case $journal->isWithdrawal():
|
||||
$txt = '<i class="fa fa-long-arrow-left fa-fw" title="' . trans('firefly.withdrawal') . '"></i>';
|
||||
break;
|
||||
case 'Deposit':
|
||||
case $journal->isDeposit():
|
||||
$txt = '<i class="fa fa-long-arrow-right fa-fw" title="' . trans('firefly.deposit') . '"></i>';
|
||||
break;
|
||||
case 'Transfer':
|
||||
case $journal->isTransfer():
|
||||
$txt = '<i class="fa fa-fw fa-exchange" title="' . trans('firefly.transfer') . '"></i>';
|
||||
break;
|
||||
case 'Opening balance':
|
||||
case $journal->isOpeningBalance():
|
||||
$txt = '<i class="fa-fw fa fa-ban" title="' . trans('firefly.openingBalance') . '"></i>';
|
||||
break;
|
||||
default:
|
||||
@@ -189,7 +187,7 @@ class Journal extends Twig_Extension
|
||||
}
|
||||
|
||||
if ($tag->tagMode == 'advancePayment') {
|
||||
if ($journal->transactionType->type == 'Deposit') {
|
||||
if ($journal->isDeposit()) {
|
||||
$amount = app('amount')->formatJournal($journal, false);
|
||||
$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>';
|
||||
@@ -201,7 +199,7 @@ class Journal extends Twig_Extension
|
||||
* AdvancePayment with a withdrawal will show the amount with a link to
|
||||
* the tag. The TransactionJournal should properly calculate the amount.
|
||||
*/
|
||||
if ($journal->transactionType->type == 'Withdrawal') {
|
||||
if ($journal->isWithdrawal()) {
|
||||
$amount = app('amount')->formatJournal($journal);
|
||||
|
||||
$string = '<a href="' . route('tags.show', [$tag->id]) . '">' . $amount . '</a>';
|
||||
|
@@ -273,7 +273,7 @@ class FireflyValidator extends Validator
|
||||
|
||||
// get entries from table
|
||||
$set = DB::table($table)->where('user_id', Auth::user()->id)
|
||||
->where('id', '!=', $exclude)->get([$field]);
|
||||
->where('id', '!=', $exclude)->get([$field]);
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$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',
|
||||
|
||||
'DaveJamesMiller\Breadcrumbs\ServiceProvider',
|
||||
//'Barryvdh\Debugbar\ServiceProvider',
|
||||
//'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
|
||||
// 'Barryvdh\Debugbar\ServiceProvider',
|
||||
// 'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
|
||||
'Zizaco\Entrust\EntrustServiceProvider',
|
||||
|
||||
/*
|
||||
|
@@ -49,7 +49,7 @@ return [
|
||||
|
||||
'sqlite' => [
|
||||
'driver' => 'sqlite',
|
||||
'database' => __DIR__ . '/../storage/database/testing.db',
|
||||
'database' => storage_path('database/testing.db'),
|
||||
'prefix' => '',
|
||||
],
|
||||
|
||||
|
@@ -1,20 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'chart' => 'chartjs',
|
||||
'version' => '3.5.3',
|
||||
'index_periods' => ['1D', '1W', '1M', '3M', '6M', '1Y', 'custom'],
|
||||
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
|
||||
'csv_import_enabled' => true,
|
||||
'maxUploadSize' => 5242880,
|
||||
'allowedMimes' => ['image/png', 'image/jpeg', 'application/pdf'],
|
||||
'piggy_bank_periods' => [
|
||||
'chart' => 'chartjs',
|
||||
'version' => '3.5.5',
|
||||
'index_periods' => ['1D', '1W', '1M', '3M', '6M', '1Y', 'custom'],
|
||||
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
|
||||
'csv_import_enabled' => true,
|
||||
'maxUploadSize' => 5242880,
|
||||
'allowedMimes' => ['image/png', 'image/jpeg', 'application/pdf'],
|
||||
'piggy_bank_periods' => [
|
||||
'week' => 'Week',
|
||||
'month' => 'Month',
|
||||
'quarter' => 'Quarter',
|
||||
'year' => 'Year'
|
||||
],
|
||||
'periods_to_text' => [
|
||||
'periods_to_text' => [
|
||||
'weekly' => 'A week',
|
||||
'monthly' => 'A month',
|
||||
'quarterly' => 'A quarter',
|
||||
@@ -22,7 +22,7 @@ return [
|
||||
'yearly' => 'A year',
|
||||
],
|
||||
|
||||
'accountRoles' => [
|
||||
'accountRoles' => [
|
||||
'defaultAsset' => 'Default asset account',
|
||||
'sharedAsset' => 'Shared asset account',
|
||||
'savingAsset' => 'Savings account',
|
||||
@@ -98,13 +98,23 @@ return [
|
||||
'Revenue account' => 'revenue',
|
||||
'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' => [
|
||||
'en' => 'English',
|
||||
'nl' => 'Nederlands'
|
||||
'en_US' => 'English',
|
||||
'nl_NL' => 'Nederlands',
|
||||
'fr_FR' => 'Français',
|
||||
'pt_BR' => 'Português do Brasil',
|
||||
],
|
||||
'locales' => [
|
||||
'en' => ['en', 'English', 'en_US', 'en_US.utf8'],
|
||||
'nl' => ['nl', 'Dutch', 'nl_NL', 'nl_NL.utf8'],
|
||||
'en_US' => ['en', 'English', 'en_US', 'en_US.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' => [
|
||||
'expenses' => ['Withdrawal'],
|
||||
@@ -124,13 +134,17 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'month' => [
|
||||
'en' => '%B %Y',
|
||||
'nl' => '%B %Y',
|
||||
'month' => [
|
||||
'en_US' => '%B %Y',
|
||||
'nl_NL' => '%B %Y',
|
||||
'fr_FR' => '%B %Y',
|
||||
'pt_BR' => '%B %Y',
|
||||
],
|
||||
'monthAndDay' => [
|
||||
'en' => '%B %e, %Y',
|
||||
'nl' => '%e %B %Y',
|
||||
'monthAndDay' => [
|
||||
'en_US' => '%B %e, %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();
|
||||
|
||||
// dates:
|
||||
$start = Carbon::now()->subyear()->startOfMonth();
|
||||
$start = Carbon::now()->subYears(5)->startOfMonth();
|
||||
$end = Carbon::now()->endOfDay();
|
||||
|
||||
|
||||
|
@@ -12,10 +12,10 @@ class TransactionTypeSeeder extends Seeder
|
||||
|
||||
DB::table('transaction_types')->delete();
|
||||
|
||||
TransactionType::create(['type' => 'Withdrawal']);
|
||||
TransactionType::create(['type' => 'Deposit']);
|
||||
TransactionType::create(['type' => 'Transfer']);
|
||||
TransactionType::create(['type' => 'Opening balance']);
|
||||
TransactionType::create(['type' => TransactionType::WITHDRAWAL]);
|
||||
TransactionType::create(['type' => TransactionType::DEPOSIT]);
|
||||
TransactionType::create(['type' => TransactionType::TRANSFER]);
|
||||
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:
|
||||
@@ -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 strokePointHighColors = [];
|
||||
|
||||
@@ -45,9 +62,9 @@ var defaultAreaOptions = {
|
||||
animation: false,
|
||||
scaleFontSize: 10,
|
||||
responsive: false,
|
||||
scaleLabel: " <%= '" + currencySymbol + " ' + Number(value).toFixed(0).replace('.', ',') %>",
|
||||
scaleLabel: " <%= accounting.formatMoney(value) %>",
|
||||
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,
|
||||
responsive: false,
|
||||
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,
|
||||
responsive: false,
|
||||
animation: false,
|
||||
scaleLabel: "<%= '" + currencySymbol + " ' + Number(value).toFixed(0).replace('.', ',') %>",
|
||||
scaleLabel: "<%= accounting.formatMoney(value) %>",
|
||||
tooltipFillColor: "rgba(0,0,0,0.5)",
|
||||
tooltipTemplate: "<%if (label){%><%=label%>: <%}%>" + currencySymbol + " <%= value %>",
|
||||
multiTooltipTemplate: "<%=datasetLabel%>: " + currencySymbol + " <%= Number(value).toFixed(2).replace('.', ',') %>"
|
||||
tooltipTemplate: "<%if (label){%><%=label%>: <%}%> <%= accounting.formatMoney(value) %>",
|
||||
multiTooltipTemplate: "<%=datasetLabel%>: <%= accounting.formatMoney(value) %>"
|
||||
};
|
||||
|
||||
var defaultStackedColumnOptions = {
|
||||
@@ -105,9 +122,9 @@ var defaultStackedColumnOptions = {
|
||||
animation: false,
|
||||
scaleFontSize: 10,
|
||||
responsive: false,
|
||||
scaleLabel: "<%= '" + currencySymbol + " ' + Number(value).toFixed(0).replace('.', ',') %>",
|
||||
scaleLabel: "<%= accounting.formatMoney(value) %>",
|
||||
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, $, */
|
||||
$(function () {
|
||||
"use strict";
|
||||
$('.currencySelect').click(currencySelect);
|
||||
|
||||
// when you click on a currency, this happens:
|
||||
$('.currency-option').click(currencySelect);
|
||||
|
||||
var ranges = {};
|
||||
// range for the current month:
|
||||
@@ -62,21 +64,51 @@ $(function () {
|
||||
|
||||
function currencySelect(e) {
|
||||
"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 code = target.data('code');
|
||||
|
||||
// id of the selected currency.
|
||||
var id = target.data('id');
|
||||
var fieldType = target.data('field');
|
||||
var menu = $('.' + fieldType + 'CurrencyDropdown');
|
||||
|
||||
var symbolHolder = $('#' + fieldType + 'CurrentSymbol');
|
||||
symbolHolder.text(symbol);
|
||||
$('input[name="' + fieldType + '_currency_id"]').val(id);
|
||||
// update the hidden input:
|
||||
$('input[name="' + hiddenInputName + '"]').val(id);
|
||||
|
||||
// close dropdown (hack hack)
|
||||
menu.click();
|
||||
// update the symbol:
|
||||
$('#' + spanId).text(symbol);
|
||||
|
||||
// close the menu (hack hack)
|
||||
$('#' + menuID).click();
|
||||
|
||||
|
||||
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',
|
||||
'monthly_report' => 'Montly report for :date',
|
||||
'monthly_report_shared' => 'Montly report for :date (including shared accounts)',
|
||||
'monthly_report' => 'Monthly report for :date',
|
||||
'monthly_report_shared' => 'Monthly report for :date (including shared accounts)',
|
||||
'yearly_report' => 'Yearly report for :date',
|
||||
'yearly_report_shared' => 'Yearly report for :date (including shared accounts)',
|
||||
'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 [
|
||||
// general stuff:
|
||||
'language_incomplete' => 'This language is not yet fully translated',
|
||||
'test' => 'You have selected English.',
|
||||
'close' => 'Close',
|
||||
'pleaseHold' => 'Please hold...',
|
||||
@@ -67,8 +68,7 @@ return [
|
||||
'new_password' => 'New password',
|
||||
'new_password_again' => 'New password (again)',
|
||||
'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' .
|
||||
' into Firefly III. It\'ll be GONE.',
|
||||
'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.',
|
||||
'delete_your_account_password' => 'Enter your password to continue.',
|
||||
'password' => 'Password',
|
||||
'are_you_sure' => 'Are you sure? You cannot undo this.',
|
||||
@@ -109,23 +109,15 @@ return [
|
||||
'csv_define_column_roles' => 'Define column roles',
|
||||
'csv_map_values' => 'Map found values to existing values',
|
||||
'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' .
|
||||
' 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_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.',
|
||||
'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_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: ' . date('Ymd'),
|
||||
'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.',
|
||||
'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_upload_button' => 'Start importing CSV',
|
||||
'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. ' .
|
||||
'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_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.',
|
||||
'csv_column_roles_table' => 'Column roles',
|
||||
'csv_column' => 'CSV column',
|
||||
'csv_column_name' => 'CSV column name',
|
||||
@@ -135,15 +127,13 @@ return [
|
||||
'csv_continue' => 'Continue to the next step',
|
||||
'csv_go_back' => 'Go back to the previous step',
|
||||
'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 ' .
|
||||
'database. This ensures that accounts and other things won\'t be created twice.',
|
||||
'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.',
|
||||
'csv_field_value' => 'Field value from CSV',
|
||||
'csv_field_mapped_to' => 'Must be mapped to...',
|
||||
'csv_do_not_map' => 'Do not map this value',
|
||||
'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_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.',
|
||||
'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.',
|
||||
'csv_do_download_config' => 'Download configuration file.',
|
||||
'csv_empty_description' => '(empty description)',
|
||||
'csv_upload_form' => 'CSV upload form',
|
||||
@@ -189,11 +179,9 @@ return [
|
||||
'csv_column_tags-space' => 'Tags (space separated)',
|
||||
'csv_specifix_RabobankDescription' => 'Select this when you\'re importing Rabobank CSV export files.',
|
||||
'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'
|
||||
. ' account the transactions in the CSV belong to.',
|
||||
'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.',
|
||||
'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_withdrawal' => 'Create new withdrawal',
|
||||
'create_new_deposit' => 'Create new deposit',
|
||||
@@ -204,7 +192,6 @@ return [
|
||||
'create_new_piggy_bank' => 'Create new piggy bank',
|
||||
'create_new_bill' => 'Create new bill',
|
||||
|
||||
|
||||
// currencies:
|
||||
'create_currency' => 'Create a new currency',
|
||||
'edit_currency' => 'Edit currency ":name"',
|
||||
@@ -250,35 +237,27 @@ return [
|
||||
'details_for_expense' => 'Details for expense account ":name"',
|
||||
'details_for_revenue' => 'Details for revenue account ":name"',
|
||||
'details_for_cash' => 'Details for cash account ":name"',
|
||||
|
||||
'store_new_asset_account' => 'Store new asset account',
|
||||
'store_new_expense_account' => 'Store new expense account',
|
||||
'store_new_revenue_account' => 'Store new revenue account',
|
||||
|
||||
'edit_asset_account' => 'Edit asset account ":name"',
|
||||
'edit_expense_account' => 'Edit expense account ":name"',
|
||||
'edit_revenue_account' => 'Edit revenue account ":name"',
|
||||
|
||||
'delete_asset_account' => 'Delete asset account ":name"',
|
||||
'delete_expense_account' => 'Delete expense account ":name"',
|
||||
'delete_revenue_account' => 'Delete revenue account ":name"',
|
||||
|
||||
'asset_deleted' => 'Successfully deleted asset account ":name"',
|
||||
'expense_deleted' => 'Successfully deleted expense account ":name"',
|
||||
'revenue_deleted' => 'Successfully deleted revenue account ":name"',
|
||||
|
||||
'update_asset_account' => 'Update asset account',
|
||||
'update_expense_account' => 'Update expense account',
|
||||
'update_revenue_account' => 'Update revenue account',
|
||||
|
||||
'make_new_asset_account' => 'Create a new asset account',
|
||||
'make_new_expense_account' => 'Create a new expense account',
|
||||
'make_new_revenue_account' => 'Create a new revenue account',
|
||||
|
||||
'asset_accounts' => 'Asset accounts',
|
||||
'expense_accounts' => 'Expense accounts',
|
||||
'revenue_accounts' => 'Revenue accounts',
|
||||
|
||||
'accountExtraHelp_asset' => '',
|
||||
'accountExtraHelp_expense' => '',
|
||||
'accountExtraHelp_revenue' => '',
|
||||
@@ -341,6 +320,7 @@ return [
|
||||
'Default account' => 'Asset account',
|
||||
'Expense account' => 'Expense account',
|
||||
'Revenue account' => 'Revenue account',
|
||||
'Initial balance account' => 'Initial balance account',
|
||||
'budgets' => 'Budgets',
|
||||
'tags' => 'Tags',
|
||||
'reports' => 'Reports',
|
||||
@@ -376,10 +356,13 @@ return [
|
||||
'profile' => 'Profile',
|
||||
|
||||
// reports:
|
||||
'reportForYear' => 'Yearly report for :year',
|
||||
'reportForYearShared' => 'Yearly report for :year (including shared accounts)',
|
||||
'reportForMonth' => 'Montly report for :month',
|
||||
'reportForMonthShared' => 'Montly report for :month (including shared accounts)',
|
||||
'report_default' => 'Default financial report for :start until :end',
|
||||
'quick_link_reports' => 'Quick links',
|
||||
'quick_link_default_report' => 'Default financial report',
|
||||
'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',
|
||||
'accountBalances' => 'Account balances',
|
||||
'balanceStartOfYear' => 'Balance at start of year',
|
||||
@@ -398,6 +381,7 @@ return [
|
||||
'outsideOfBudgets' => 'Outside of budgets',
|
||||
'leftInBudget' => 'Left in budget',
|
||||
'sumOfSums' => 'Sum of sums',
|
||||
'noCategory' => '(no category)',
|
||||
'notCharged' => 'Not charged (yet)',
|
||||
'inactive' => 'Inactive',
|
||||
'difference' => 'Difference',
|
||||
@@ -407,9 +391,18 @@ return [
|
||||
'showTheRest' => 'Show everything',
|
||||
'hideTheRest' => 'Show only the top :number',
|
||||
'sum_of_year' => 'Sum of year',
|
||||
'sum_of_years' => 'Sum of years',
|
||||
'average_of_year' => 'Average of year',
|
||||
'average_of_years' => 'Average of years',
|
||||
'categories_earned_in_year' => 'Categories (by earnings)',
|
||||
'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:
|
||||
'dayOfMonth' => 'Day of the month',
|
||||
@@ -470,7 +463,6 @@ return [
|
||||
'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.',
|
||||
'advance_payment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
|
||||
|
||||
'delete_tag' => 'Delete tag ":tag"',
|
||||
'new_tag' => 'Make new tag',
|
||||
'edit_tag' => 'Edit tag ":tag"',
|
||||
@@ -479,17 +471,8 @@ return [
|
||||
'tag_title_nothing' => 'Default tags',
|
||||
'tag_title_balancingAct' => 'Balancing act tags',
|
||||
'tag_title_advancePayment' => 'Advance payment tags',
|
||||
'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.',
|
||||
'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_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.',
|
||||
'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.',
|
||||
|
||||
];
|
@@ -88,16 +88,10 @@ return [
|
||||
'tag_areYouSure' => 'Are you sure you want to delete the tag ":tag"?',
|
||||
|
||||
'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.' .
|
||||
'|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.',
|
||||
'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.' .
|
||||
'|All :count transactions connected to this bill 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.',
|
||||
'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.',
|
||||
'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.',
|
||||
'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.|All :count transactions connected to this bill 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',
|
||||
'lastMatch' => 'Last match',
|
||||
'expectedMatch' => 'Expected match',
|
||||
'automatch' => 'Automatch?',
|
||||
'automatch' => 'Auto match?',
|
||||
'repeat_freq' => 'Repeats',
|
||||
'description' => 'Description',
|
||||
'amount' => 'Amount',
|
@@ -17,5 +17,6 @@ return [
|
||||
"token" => "This password reset token is invalid.",
|
||||
"sent" => "We have e-mailed your password reset link!",
|
||||
"reset" => "Your password has been reset!",
|
||||
'blocked' => 'Nice try though.'
|
||||
|
||||
];
|
@@ -1,18 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 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.
|
||||
|
|
||||
*/
|
||||
|
||||
'invalid_domain' => 'Due to security constraints, you cannot register from this domain.',
|
||||
'file_already_attached' => 'Uploaded file ":name" is already attached to this object.',
|
||||
'file_attached' => 'Succesfully uploaded file ":name".',
|
||||
'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.",
|
||||
'unique_object_for_user' => 'This name is already in use',
|
||||
'unique_account_for_user' => 'This account name is already in use',
|
||||
"between" => [
|
||||
"numeric" => "The :attribute must be between :min and :max.",
|
||||
"file" => "The :attribute must be between :min and :max kilobytes.",
|
||||
"string" => "The :attribute must be between :min and :max characters.",
|
||||
"array" => "The :attribute must have between :min and :max items.",
|
||||
],
|
||||
"between.numeric" => "The :attribute must be between :min and :max.",
|
||||
"between.file" => "The :attribute must be between :min and :max kilobytes.",
|
||||
"between.string" => "The :attribute must be between :min and :max characters.",
|
||||
"between.array" => "The :attribute must have between :min and :max items.",
|
||||
"boolean" => "The :attribute field must be true or false.",
|
||||
"confirmed" => "The :attribute confirmation does not match.",
|
||||
"date" => "The :attribute is not a valid date.",
|
||||
@@ -48,67 +35,33 @@ return [
|
||||
"in" => "The selected :attribute is invalid.",
|
||||
"integer" => "The :attribute must be an integer.",
|
||||
"ip" => "The :attribute must be a valid IP address.",
|
||||
"max" => [
|
||||
"numeric" => "The :attribute may not be greater than :max.",
|
||||
"file" => "The :attribute may not be greater than :max kilobytes.",
|
||||
"string" => "The :attribute may not be greater than :max characters.",
|
||||
"array" => "The :attribute may not have more than :max items.",
|
||||
],
|
||||
'json' => 'The :attribute must be a valid JSON string.',
|
||||
"max.numeric" => "The :attribute may not be greater than :max.",
|
||||
"max.file" => "The :attribute may not be greater than :max kilobytes.",
|
||||
"max.string" => "The :attribute may not be greater than :max characters.",
|
||||
"max.array" => "The :attribute may not have more than :max items.",
|
||||
"mimes" => "The :attribute must be a file of type: :values.",
|
||||
"min" => [
|
||||
"numeric" => "The :attribute must be at least :min.",
|
||||
"file" => "The :attribute must be at least :min kilobytes.",
|
||||
"string" => "The :attribute must be at least :min characters.",
|
||||
"array" => "The :attribute must have at least :min items.",
|
||||
],
|
||||
"min.numeric" => "The :attribute must be at least :min.",
|
||||
"min.file" => "The :attribute must be at least :min kilobytes.",
|
||||
"min.string" => "The :attribute must be at least :min characters.",
|
||||
"min.array" => "The :attribute must have at least :min items.",
|
||||
"not_in" => "The selected :attribute is invalid.",
|
||||
"numeric" => "The :attribute must be a number.",
|
||||
"regex" => "The :attribute format is invalid.",
|
||||
"required" => "The :attribute field is required.",
|
||||
"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_all" => "The :attribute field is required when :values is 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.",
|
||||
"same" => "The :attribute and :other must match.",
|
||||
"size" => [
|
||||
"numeric" => "The :attribute must be :size.",
|
||||
"file" => "The :attribute must be :size kilobytes.",
|
||||
"string" => "The :attribute must be :size characters.",
|
||||
"array" => "The :attribute must contain :size items.",
|
||||
],
|
||||
"size.numeric" => "The :attribute must be :size.",
|
||||
"size.file" => "The :attribute must be :size kilobytes.",
|
||||
"size.string" => "The :attribute must be :size characters.",
|
||||
"size.array" => "The :attribute must contain :size items.",
|
||||
"unique" => "The :attribute has already been taken.",
|
||||
'string' => 'The :attribute must be a string.',
|
||||
"url" => "The :attribute format is invalid.",
|
||||
"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"',
|
||||
|
||||
];
|
8
resources/lang/fr_FR/config.php
Normal file
8
resources/lang/fr_FR/config.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'locale' => 'fr, French, fr_FR, fr_FR.utf8',
|
||||
'month' => '%B %Y',
|
||||
'month_and_day' => '%e %B %Y',
|
||||
|
||||
];
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user