Compare commits

...

152 Commits
5.2.0 ... 5.2.6

Author SHA1 Message Date
James Cole
09990acaa2 Merge branch 'release/5.2.6' 2020-05-22 17:54:02 +02:00
James Cole
a73247ec8c Some last minute translations. 2020-05-22 17:53:09 +02:00
James Cole
e98d43dd65 New meta files for 5.2.6 2020-05-22 14:15:57 +02:00
James Cole
dbd68cedc9 Code for #3309 2020-05-22 13:52:33 +02:00
James Cole
e6e8200912 Merge pull request #3381 from bpatath/feature/add-single-sign-on
Feature/add single sign on
2020-05-22 04:27:39 +00:00
bpatath
7b1380366b Register SSO middleware if enabled in configuration 2020-05-21 21:05:03 +02:00
bpatath
1eda806c17 Fix outdated AdLdap2 configuration files 2020-05-21 21:04:17 +02:00
James Cole
782ecca6a9 Warning if people disabled update checking. Every 4 weeks. 2020-05-20 06:40:18 +02:00
James Cole
e6338705a7 Fix #3376 2020-05-19 19:37:12 +02:00
James Cole
09226e6f12 New translations. 2020-05-19 13:29:47 +02:00
James Cole
5ff1991cdc Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2020-05-19 11:19:13 +02:00
James Cole
4ebb6de520 Reset rule order on index. #3376 2020-05-19 11:18:58 +02:00
James Cole
1ba7d65582 Warning if demo user. 2020-05-18 21:21:34 +02:00
James Cole
4e6063a4f8 Demo user can't set locale 2020-05-18 21:19:45 +02:00
James Cole
85476f3549 Fix some strings. 2020-05-18 21:17:59 +02:00
James Cole
ef9714b7e0 Fix #3374 2020-05-18 14:50:07 +02:00
James Cole
8d20029557 Fix #3368 2020-05-17 19:17:19 +02:00
James Cole
0f04b44ca1 Fix # 2020-05-17 06:49:26 +02:00
James Cole
44ed45502e Change in error handling. 2020-05-16 16:57:48 +02:00
James Cole
5bcafe1311 Change in error handling. 2020-05-16 16:57:26 +02:00
James Cole
5a771ccc5f Run yarn again #3363 2020-05-16 16:56:08 +02:00
James Cole
c6145b4a3b Auto generated JSON files for new strings in other languages. #3363 2020-05-16 16:35:23 +02:00
James Cole
b20aeca849 Auto-generated translation files from crowdin #3363 2020-05-16 16:33:57 +02:00
James Cole
793918f2f3 Add new strings to global translation files. #3363 2020-05-16 16:30:17 +02:00
James Cole
5d410e577e Merge pull request #3365 from sephrat/master
Fix #3363
2020-05-16 14:27:39 +00:00
James Cole
9ec786ec3a Merge branch 'develop' into master 2020-05-16 14:27:31 +00:00
Florian Dupret
e532b4d4fc Fix #3363 2020-05-16 15:01:19 +02:00
James Cole
58585d03c6 Fix rounding thing. 2020-05-16 13:09:37 +02:00
James Cole
a4f66b3d86 Date before and after triggers 2020-05-16 12:55:54 +02:00
James Cole
c847621874 First "date is" trigger for #3049 2020-05-16 12:11:06 +02:00
James Cole
86f14885eb Added a rule action that will delete the transactions it matches. 2020-05-16 11:21:26 +02:00
James Cole
173e196bc8 Some experimental fixes for #3011 2020-05-16 10:45:40 +02:00
James Cole
7505db871f Update packages. 2020-05-16 06:59:51 +02:00
James Cole
946dde8957 Add ability to store recurring telemetry. Not enabled. 2020-05-16 06:59:41 +02:00
James Cole
9a52cfbfbe Add some debug info 2020-05-16 06:59:15 +02:00
James Cole
b248bd6d0c Remove code. 2020-05-15 19:59:23 +02:00
James Cole
3fff9ad0a2 Updated translations. 2020-05-15 19:31:19 +02:00
James Cole
a695a1bba2 Fix #3355 2020-05-12 20:40:28 +02:00
James Cole
91e384aae8 Fix #3350 2020-05-10 20:08:16 +02:00
James Cole
1ac95b6fa7 Move getCash lower, add IBAN as name when no name is submitted. Search will pick up the rest. 2020-05-09 18:03:32 +02:00
James Cole
6757b6211d https://github.com/firefly-iii/firefly-iii/issues/3348 2020-05-09 17:47:25 +02:00
James Cole
4dfb78837e Slightly smarter menu. 2020-05-09 14:51:04 +02:00
James Cole
af50ad3db4 New action 2020-05-09 14:47:47 +02:00
James Cole
01cb94aabc Room for better translation 2020-05-09 14:47:33 +02:00
James Cole
5ffc5060b9 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2020-05-07 06:44:27 +02:00
James Cole
43d7c956a4 Fix #3344 2020-05-07 06:44:01 +02:00
James Cole
863b07951a Fix #3339 2020-05-05 20:53:56 +02:00
James Cole
2101717edb Can return without split. 2020-05-05 20:32:04 +02:00
James Cole
e7ac1476c5 Merge pull request #3336 from maksimkurb/develop
WIP: Fix #3335 Reconciliation account currency is wrong when base account has non-default currency
2020-05-05 20:30:05 +02:00
Maxim Kurbatov
5d24c1fee1 #3335 Update language files for reconciliation account name 2020-05-05 22:10:11 +04:00
Maxim Kurbatov
53eb863f9d Fix #3335 Reconciliation account currency is wrong when base account has non-default currency 2020-05-05 22:07:42 +04:00
James Cole
3c3ba637b5 Make sure demo user can't upload attachments. 2020-05-05 07:44:33 +02:00
James Cole
be8286b15c Fix some things in recurring transactions. 2020-05-04 10:26:01 +02:00
James Cole
6f6087995d Add info on expired recurring transactions. 2020-05-04 10:12:38 +02:00
James Cole
2ff8a35171 Add debug. 2020-05-04 10:06:13 +02:00
James Cole
7f8ed7abb6 Merge branch 'release/5.2.5' 2020-05-04 08:59:55 +02:00
James Cole
2ff0c37c12 Merge tag '5.2.5' into develop
5.2.5
2020-05-04 08:59:55 +02:00
James Cole
c593936b32 New meta files for upcoming release. 2020-05-04 08:56:51 +02:00
James Cole
c54204ede9 Fix #3330 2020-05-03 19:38:03 +02:00
James Cole
d9132bbee3 Merge pull request #3323 from lguima/feature/page-icons-update
Update the pages and blocks icons
2020-05-02 17:11:27 +02:00
Lucas Guima
c1be98762e Update the Tags icon around the site 2020-05-01 18:55:23 -03:00
Lucas Guima
c2733e2a8f Update the Categories icon around the site 2020-05-01 18:54:08 -03:00
Lucas Guima
722cf9b4fe Update the Reports icon around the site 2020-05-01 17:39:43 -03:00
Lucas Guima
01e31e73e0 Update the Piggy Banks icon around the site 2020-05-01 17:32:35 -03:00
Lucas Guima
dba7d05296 Update the Budgets icon around the site 2020-05-01 17:29:50 -03:00
James Cole
a8709a4a45 update env. 2020-05-01 20:16:34 +02:00
James Cole
49b1435cba Fix cron controller. #3318 2020-05-01 17:51:30 +02:00
James Cole
6a25b41952 Update translations. 2020-05-01 17:50:53 +02:00
James Cole
c561f99de6 Fix #3321 2020-05-01 17:47:56 +02:00
James Cole
9d9053d828 Fix #3314 2020-05-01 06:24:24 +02:00
James Cole
c3c9a2f3c0 Slightly different icon. 2020-04-30 06:27:53 +02:00
James Cole
28465142e9 Menu changelog. 2020-04-30 06:27:10 +02:00
James Cole
5473a618c9 Warn about locale things. 2020-04-30 06:27:01 +02:00
James Cole
ac1a8d8053 Merge pull request #3305 from lguima/feature/menu-reordering
Menu reordering
2020-04-30 06:10:51 +02:00
James Cole
15ae9203b6 Fix #3307 2020-04-29 06:37:02 +02:00
Lucas Guima
9dfc2ae20b Use the translatable string for Tools 2020-04-28 20:59:22 -03:00
Lucas Guima
230de7cbdd Use the translatable string for Classification 2020-04-28 20:59:10 -03:00
Lucas Guima
feaa003a52 Use the translatable string for Others 2020-04-28 20:57:36 -03:00
Lucas Guima
295d01dc16 Use the translatable string for Automation 2020-04-28 20:57:11 -03:00
Lucas Guima
cbf1fde45e Use the translatable string for Accounting 2020-04-28 20:56:19 -03:00
Lucas Guima
6cc47287d3 Use the translatable string for Financial control 2020-04-28 20:55:52 -03:00
Lucas Guima
4bbe728376 Create translatable string for Classification 2020-04-28 20:43:02 -03:00
Lucas Guima
427a90ec85 Create translatable string for Others 2020-04-28 20:32:10 -03:00
Lucas Guima
55ddb26dac Create translatable string for Automation 2020-04-28 20:16:25 -03:00
Lucas Guima
891777f079 Create translatable string for Accounting 2020-04-28 20:14:15 -03:00
Lucas Guima
1655286b67 Create translatable string for Financial control 2020-04-28 20:10:43 -03:00
Lucas Guima
dd81636bf2 Add an icon for each sub-menu item 2020-04-28 19:29:53 -03:00
Lucas Guima
56a43a707d Update the icon of Bills menu item 2020-04-28 19:07:44 -03:00
Lucas Guima
c2f92c6e45 Update the icon of Options menu item 2020-04-28 19:07:11 -03:00
Lucas Guima
61bd2dc840 Revert "Move the menu items Profile and Logout to the user menu in the main header"
This reverts commit f6a675f2e2.
2020-04-28 18:55:49 -03:00
Lucas Guima
f6a675f2e2 Move the menu items Profile and Logout to the user menu in the main header 2020-04-27 22:29:14 -03:00
Lucas Guima
85b43055a7 Put the menu sub-items text inside a span tag 2020-04-27 21:44:23 -03:00
Lucas Guima
e63f7bcc70 Put a space between arguments 2020-04-27 21:41:00 -03:00
Lucas Guima
384dd37430 Update the menu item Logout 2020-04-27 21:37:20 -03:00
Lucas Guima
c6b336171c Update the menu item Options 2020-04-27 21:36:47 -03:00
Lucas Guima
d2f4399a1a Update the menu item Tools (Import and export) 2020-04-27 21:30:12 -03:00
Lucas Guima
02d1bc093c Update the menu item Reports 2020-04-27 21:14:38 -03:00
Lucas Guima
420e493987 Group Categories and Tags under the new menu item Classification 2020-04-27 21:12:23 -03:00
Lucas Guima
0a15479bff Update the menu item Accounts 2020-04-27 20:53:25 -03:00
Lucas Guima
a9b76a3679 Add menu header for Others 2020-04-27 20:44:39 -03:00
Lucas Guima
d1a3cd9044 Move and update the menu item Automation (Money management) 2020-04-27 20:41:40 -03:00
Lucas Guima
81735d59f8 Move and update the menu item Transactions 2020-04-27 19:59:53 -03:00
Lucas Guima
1d8da7f9f0 Add menu header for Accounting 2020-04-27 18:35:52 -03:00
Lucas Guima
c5f0684030 Place the menu item Piggy banks after Bills 2020-04-26 18:11:20 -03:00
Lucas Guima
25867adcb9 Move the menu item Piggy banks 2020-04-26 18:10:22 -03:00
Lucas Guima
d55694cd68 Move the menu item Bills 2020-04-26 18:07:08 -03:00
Lucas Guima
05f069d61e Move the menu item Budgets 2020-04-26 18:00:28 -03:00
Lucas Guima
5f6e7ad138 Add menu header for Financial Control 2020-04-26 17:50:42 -03:00
Lucas Guima
61bc38921e Update Dashboard menu item 2020-04-26 17:48:13 -03:00
Lucas Guima
94c660545d Update indentation 2020-04-26 17:44:07 -03:00
James Cole
4d3907948d Merge tag '5.2.4' into develop
5.2.4
2020-04-26 10:02:43 +02:00
James Cole
e6442dd8af Merge branch 'release/5.2.4' 2020-04-26 10:02:42 +02:00
James Cole
7905e0bd70 Bump to 5.2.4 2020-04-26 10:02:25 +02:00
James Cole
f4b1da352d no message 2020-04-26 07:08:33 +02:00
James Cole
0d33348941 Fix #3251 2020-04-26 06:57:59 +02:00
James Cole
c7c875e95f Fix #3251 2020-04-26 06:54:12 +02:00
James Cole
19d24b3e2a Clean up templates 2020-04-26 06:45:42 +02:00
James Cole
8fed6b6657 Fix #3287 2020-04-22 09:28:20 +02:00
James Cole
b5eafa1910 Merge tag '5.2.3' into develop
5.2.3
2020-04-22 06:33:23 +02:00
James Cole
c15501937f Merge branch 'release/5.2.3' 2020-04-22 06:33:22 +02:00
James Cole
4c743bd5b0 Update meta files for new release. 2020-04-22 06:29:34 +02:00
James Cole
44289cbd95 Fix #3284 2020-04-22 06:09:29 +02:00
James Cole
b2f1642cfe Fix #3281 2020-04-21 08:17:31 +02:00
James Cole
341ef0220c New translations. 2020-04-19 11:07:14 +02:00
James Cole
9df88115bc Update packages. 2020-04-19 11:05:14 +02:00
James Cole
c7273edb5e Updated language strings and meta config. 2020-04-19 06:52:12 +02:00
James Cole
c398aa2b69 Add support for British English and allow the user to set a locale. 2020-04-19 06:51:40 +02:00
James Cole
aa786eaaf3 Clean up language setting. 2020-04-19 06:11:49 +02:00
James Cole
e58a5e12d6 Fix #3270 2020-04-19 06:10:49 +02:00
James Cole
12b3575c5c Fix method reference 2020-04-19 06:09:55 +02:00
James Cole
3ca186dc8f Remove unused method. 2020-04-19 06:09:43 +02:00
James Cole
1535f596f6 Add two new support functions. 2020-04-19 06:07:43 +02:00
James Cole
2cc326caa1 Fix #3272 2020-04-19 06:05:39 +02:00
James Cole
43436ae942 Fix issue with casting. 2020-04-19 06:00:11 +02:00
James Cole
fbfd8475de Fix #3264 2020-04-15 16:17:45 +02:00
James Cole
405752f353 Merge tag '5.2.2' into develop
5.2.2
2020-04-14 21:01:03 +02:00
James Cole
2af98b259a Merge branch 'release/5.2.2' 2020-04-14 21:01:02 +02:00
James Cole
015242a666 Update meta files for new release. 2020-04-14 20:56:30 +02:00
James Cole
54933fda2e Fix #3263 2020-04-14 17:23:58 +02:00
James Cole
852d057a47 Fix #3259 2020-04-13 07:57:46 +02:00
James Cole
1778f0b4f3 Fix storing of virtual balance. 2020-04-13 07:57:32 +02:00
James Cole
6daf083b3f Clean up some code. 2020-04-12 06:24:35 +02:00
James Cole
4a7d9b130a Fix issue with multi-currency in asset accounts. 2020-04-12 06:23:35 +02:00
James Cole
4163efba55 Clean up phpdoc 2020-04-11 06:42:47 +02:00
James Cole
db5847b49b Consistent in minimum password length 2020-04-11 06:42:40 +02:00
James Cole
6829003f5e Change to safer hash methods. 2020-04-11 06:42:21 +02:00
James Cole
047927718e Merge branch 'release/5.2.1' 2020-04-10 21:23:53 +02:00
James Cole
91deb22a3f Merge tag '5.2.1' into develop
5.2.1
2020-04-10 21:23:53 +02:00
James Cole
1629ca0739 Update for some bugs. 2020-04-10 21:20:04 +02:00
James Cole
8b87204f10 User unable to store budgets without auto budget info. 2020-04-10 21:16:46 +02:00
James Cole
f920d90e3d Fix chart problem 2020-04-10 21:16:29 +02:00
James Cole
1cb91282af Merge tag '5.2.0' into develop
5.2.0
2020-04-10 13:51:23 +02:00
263 changed files with 7439 additions and 2039 deletions

View File

@@ -22,15 +22,15 @@ APP_KEY=SomeRandomStringOf32CharsExactly
# If text is still in English, remember that not everything may have been translated.
DEFAULT_LANGUAGE=en_US
# The locale defines how numbers are formatted.
# by default this value is the same as whatever the language is.
DEFAULT_LOCALE=equal
# Change this value to your preferred time zone.
# Example: Europe/Amsterdam
# For a list of supported time zones, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
TZ=Europe/Amsterdam
# This variable must match your installation's external address but keep in mind that
# it's only used on the command line as a fallback value.
APP_URL=http://localhost
# TRUSTED_PROXIES is a useful variable when using Docker and/or a reverse proxy.
# Set it to ** and reverse proxies work just fine.
TRUSTED_PROXIES=
@@ -191,6 +191,7 @@ ADLDAP_AUTH_FIELD=distinguishedname
# Will allow SSO if your server provides an AUTH_USER field.
# You can set the following variables from a file by appending them with _FILE:
WINDOWS_SSO_ENABLED=false
WINDOWS_SSO_DISCOVER=samaccountname
WINDOWS_SSO_KEY=AUTH_USER
@@ -270,3 +271,15 @@ IS_SANDSTORM=false
IS_DOCKER=false
IS_HEROKU=false
BUNQ_USE_SANDBOX=false
#
# If you have trouble configuring your Firefly III installation, DON'T BOTHER setting this variable.
# It won't work. It doesn't do ANYTHING. Don't believe the lies you read online. I'm not joking.
# This configuration value WILL NOT HELP.
#
# This variable is ONLY used in some of the emails Firefly III sends around. Nowhere else.
# So when configuring anything WEB related this variable doesn't do anything. Nothing
#
# If you're stuck I understand you get desperate but look SOMEWHERE ELSE.
#
APP_URL=http://localhost

View File

@@ -16,10 +16,10 @@ I am running Firefly III version x.x.x, and my problem is:
<!-- Please add extra info here, such as OS, browser, and the output from the /debug page of your Firefly III installation (click the version at the bottom). -->
**Bonus points**
<!-- Earn bonus points by checking the boxes -->
<!-- Before you submit, verify the following please: -->
- [ ] Nobody reported this bug before
- [ ] I have added a stack trace from my log files <!-- (see https://bit.ly/FF3-get-debug-info) -->
- [ ] I have added a screenshot.
- [ ] I was able to replicate it on the demo site https://demo.firefly-iii.org/
<!-- - [ ] I donated money (this is a joke :wink:)-->
- I searched and nobody reported this bug before
- I have added a stack trace from my log files <!-- (see https://bit.ly/FF3-get-debug-info) -->
- I have added a screenshot.
- I was able to replicate it on the demo site https://demo.firefly-iii.org/
<!-- - I donated money (this is a joke ;)-->

View File

@@ -16,8 +16,8 @@ I am running Firefly III version x.x.x.
<!-- Complete the following checklist for bonus points -->
- [ ] I have read the FAQ at https://bit.ly/FF3-FAQ
- [ ] I added a screenshot
- [ ] I added log files <!-- (see https://bit.ly/FF3-get-debug-info) -->
- [ ] I was able to replicate the issue on the demo site.
<!-- - [ ] I donated money (this is a joke :wink:)-->
- I have read the FAQ at https://bit.ly/FF3-FAQ
- I added a screenshot
- I added log files <!-- (see https://bit.ly/FF3-get-debug-info) -->
- I was able to replicate the issue on the demo site.
<!-- - I donated money (this is a joke :wink:)-->

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
/node_modules
/frontend/node_modules
/public/hot
/public/storage
/storage/*.key

View File

@@ -23,10 +23,12 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Middleware\ApiDemoUser;
use FireflyIII\Api\V1\Requests\AttachmentStoreRequest;
use FireflyIII\Api\V1\Requests\AttachmentUpdateRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Middleware\IsDemoUser;
use FireflyIII\Models\Attachment;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Transformers\AttachmentTransformer;
@@ -58,6 +60,7 @@ class AttachmentController extends Controller
public function __construct()
{
parent::__construct();
$this->middleware(ApiDemoUser::class)->except(['delete', 'download', 'show', 'index']);
$this->middleware(
function ($request, $next) {
/** @var User $user */
@@ -65,6 +68,7 @@ class AttachmentController extends Controller
$this->repository = app(AttachmentRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);

View File

@@ -269,6 +269,7 @@ class TransactionController extends Controller
*
* @param TransactionStoreRequest $request
*
* @throws FireflyException
* @return JsonResponse
*/
public function store(TransactionStoreRequest $request): JsonResponse
@@ -283,7 +284,7 @@ class TransactionController extends Controller
try {
$transactionGroup = $this->groupRepository->store($data);
} catch (DuplicateTransactionException $e) {
Log::warning('Caught a duplicate. Return error message.');
Log::warning('Caught a duplicate transaction. Return error message.');
// return bad validation message.
// TODO use Laravel's internal validation thing to do this.
$response = [
@@ -326,7 +327,7 @@ class TransactionController extends Controller
$selectedGroup = $collector->getGroups()->first();
if (null === $selectedGroup) {
throw new NotFoundHttpException(); // @codeCoverageIgnore
throw new FireflyException('Cannot find transaction. Possibly, a rule deleted this transaction after its creation.');
}
/** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class);

View File

@@ -0,0 +1,61 @@
<?php
/**
* ApiDemoUser.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Middleware;
use Closure;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\Request;
/**
* Class ApiDemoUser.
*/
class ApiDemoUser
{
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
*
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
/** @var User $user */
$user = $request->user();
if (null === $user) {
return $next($request);
}
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
if ($repository->hasRole($user, 'demo')) {
return response('', 403);
}
return $next($request);
}
}

View File

@@ -87,7 +87,7 @@ class Handler extends ExceptionHandler
);
}
return response()->json(['message' => 'Internal Firefly III Exception. See log files.', 'exception' => get_class($exception)], 500);
return response()->json(['message' => sprintf('Internal Firefly III Exception: %s', $exception->getMessage()), 'exception' => get_class($exception)], 500);
}
if ($exception instanceof NotFoundHttpException) {

View File

@@ -98,7 +98,7 @@ class AccountFactory
'user_id' => $this->user->id,
'account_type_id' => $type->id,
'name' => $data['name'],
'virtual_balance' => $data['virtual_balance'] ?? '0',
'virtual_balance' => $data['virtual_balance'] ?? null,
'active' => true === $data['active'],
'iban' => $data['iban'],
];
@@ -109,12 +109,12 @@ class AccountFactory
// remove virtual balance when not an asset account or a liability
if (!in_array($type->type, $this->canHaveVirtual, true)) {
$databaseData['virtual_balance'] = '0';
$databaseData['virtual_balance'] = null;
}
// fix virtual balance when it's empty
if ('' === $databaseData['virtual_balance']) {
$databaseData['virtual_balance'] = '0';
if ('' === (string)$databaseData['virtual_balance']) {
$databaseData['virtual_balance'] = null;
}
$return = Account::create($databaseData);

View File

@@ -280,25 +280,29 @@ class TransactionJournalFactory
/** create or get source and destination accounts */
$sourceInfo = [
'id' => (int) $row['source_id'],
'name' => $row['source_name'],
'iban' => $row['source_iban'],
'number' => $row['source_number'],
'bic' => $row['source_bic'],
'id' => (int) $row['source_id'],
'name' => $row['source_name'],
'iban' => $row['source_iban'],
'number' => $row['source_number'],
'bic' => $row['source_bic'],
'currency_id' => $currency->id,
];
$destInfo = [
'id' => (int) $row['destination_id'],
'name' => $row['destination_name'],
'iban' => $row['destination_iban'],
'number' => $row['destination_number'],
'bic' => $row['destination_bic'],
'id' => (int) $row['destination_id'],
'name' => $row['destination_name'],
'iban' => $row['destination_iban'],
'number' => $row['destination_number'],
'bic' => $row['destination_bic'],
'currency_id' => $currency->id,
];
Log::debug('Source info:', $sourceInfo);
Log::debug('Destination info:', $destInfo);
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
Log::debug('Now calling getAccount for the source.');
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
Log::debug('Now calling getAccount for the destination.');
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
Log::debug('Done with getAccount(2x)');
$currency = $this->getCurrencyByAccount($type->type, $currency, $sourceAccount, $destinationAccount);
$foreignCurrency = $this->compareCurrencies($currency, $foreignCurrency);
$foreignCurrency = $this->getForeignByAccount($type->type, $foreignCurrency, $destinationAccount);
@@ -424,7 +428,7 @@ class TransactionJournalFactory
->first();
}
if (null !== $result) {
Log::warning('Found a duplicate!');
Log::warning(sprintf('Found a duplicate in errorIfDuplicate because hash %s is not unique!', $hash));
throw new DuplicateTransactionException(sprintf('Duplicate of transaction #%d.', $result->transactionJournal->transaction_group_id));
}
}
@@ -468,6 +472,7 @@ class TransactionJournalFactory
*/
private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency
{
Log::debug('Now in getCurrency()');
$preference = $this->accountRepository->getAccountCurrency($account);
if (null === $preference && null === $currency) {
// return user's default:
@@ -489,6 +494,7 @@ class TransactionJournalFactory
*/
private function getCurrencyByAccount(string $type, ?TransactionCurrency $currency, Account $source, Account $destination): TransactionCurrency
{
Log::debug('Now ingetCurrencyByAccount()');
switch ($type) {
default:
case TransactionType::WITHDRAWAL:
@@ -538,15 +544,15 @@ class TransactionJournalFactory
$dataRow = $row->getArrayCopy();
unset($dataRow['import_hash_v2'], $dataRow['original_source']);
$json = json_encode($dataRow);
$json = json_encode($dataRow, JSON_THROW_ON_ERROR, 512);
if (false === $json) {
// @codeCoverageIgnoreStart
$json = json_encode((string) microtime());
$json = json_encode((string) microtime(), JSON_THROW_ON_ERROR, 512);
Log::error(sprintf('Could not hash the original row! %s', json_last_error_msg()), $dataRow);
// @codeCoverageIgnoreEnd
}
$hash = hash('sha256', $json);
Log::debug(sprintf('The hash is: %s', $hash));
Log::debug(sprintf('The hash is: %s', $hash), $dataRow);
return $hash;
}
@@ -601,7 +607,7 @@ class TransactionJournalFactory
// validate source account.
$sourceId = isset($data['source_id']) ? (int) $data['source_id'] : null;
$sourceName = $data['source_name'] ?? null;
$sourceName = isset($data['source_name']) ? (string) $data['source_name'] : null;
$validSource = $this->accountValidator->validateSource($sourceId, $sourceName, null);
// do something with result:
@@ -611,7 +617,7 @@ class TransactionJournalFactory
Log::debug('Source seems valid.');
// validate destination account
$destinationId = isset($data['destination_id']) ? (int) $data['destination_id'] : null;
$destinationName = (string)($data['destination_name'] ?? null);
$destinationName = isset($data['destination_name']) ? (string) $data['destination_name'] : null;
$validDestination = $this->accountValidator->validateDestination($destinationId, $destinationName, null);
// do something with result:
if (false === $validDestination) {

View File

@@ -154,14 +154,14 @@ class MonthReportGenerator implements ReportGeneratorInterface
$journals[$index]['invoice_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'invoice_date');
}
$locale = app('steam')->getLocale();
$return = [
'journals' => $journals,
'currency' => $currency,
'exists' => count($journals) > 0,
'end' => $this->end->formatLocalized((string) trans('config.month_and_day')),
'end' => $this->end->formatLocalized((string) trans('config.month_and_day', [], $locale)),
'endBalance' => app('steam')->balance($account, $this->end),
'dayBefore' => $date->formatLocalized((string) trans('config.month_and_day')),
'dayBefore' => $date->formatLocalized((string) trans('config.month_and_day', [], $locale)),
'dayBeforeBalance' => $dayBeforeBalance,
];

View File

@@ -118,6 +118,7 @@ class UserEventHandler
if ($repository->hasRole($user, 'demo')) {
// set user back to English.
app('preferences')->setForUser($user, 'language', 'en_US');
app('preferences')->setForUser($user, 'locale', 'equal');
app('preferences')->mark();
}
@@ -165,7 +166,8 @@ class UserEventHandler
$user = $event->user;
$ipAddress = $event->ipAddress;
$token = app('preferences')->getForUser($user, 'email_change_undo_token', 'invalid');
$uri = route('profile.undo-email-change', [$token->data, hash('sha256', $oldEmail)]);
$hashed = hash('sha256', sprintf('%s%s', (string) config('app.key'), $oldEmail));
$uri = route('profile.undo-email-change', [$token->data,$hashed]);
try {
Mail::to($oldEmail)->send(new UndoEmailChangeMail($newEmail, $oldEmail, $uri, $ipAddress));
// @codeCoverageIgnoreStart

View File

@@ -54,6 +54,7 @@ class VersionCheckEventHandler
$value = (int) $permission->data;
if (1 !== $value) {
Log::info('Update check is not enabled.');
$this->warnToCheckForUpdates($event);
return;
}
@@ -85,4 +86,36 @@ class VersionCheckEventHandler
session()->flash($release['level'], $release['message']);
app('fireflyconfig')->set('last_update_check', time());
}
/**
* @param RequestedVersionCheckStatus $event
*/
protected function warnToCheckForUpdates(RequestedVersionCheckStatus $event): void
{
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
/** @var User $user */
$user = $event->user;
if (!$repository->hasRole($user, 'owner')) {
Log::debug('User is not admin, done.');
return;
}
/** @var Configuration $lastCheckTime */
$lastCheckTime = app('fireflyconfig')->get('last_update_warning', time());
$now = time();
$diff = $now - $lastCheckTime->data;
Log::debug(sprintf('Last warning time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < 604800 * 4) {
Log::debug(sprintf('Warned about updates less than four weeks ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data)));
return;
}
// last check time was more than a week ago.
Log::debug('Have warned about a new version in four weeks!');
session()->flash('info', (string) trans('firefly.disabled_but_check'));
app('fireflyconfig')->set('last_update_warning', time());
}
}

View File

@@ -91,8 +91,9 @@ trait TimeCollection
if ($end < $start) {
[$start, $end] = [$end, $start];
}
$startStr = $start->format('Y-m-d H:i:s');
$endStr = $end->format('Y-m-d H:i:s');
// always got to end of day / start of day for ranges.
$startStr = $start->format('Y-m-d 00:00:00');
$endStr = $end->format('Y-m-d 23:59:59');
$this->query->where('transaction_journals.date', '>=', $startStr);
$this->query->where('transaction_journals.date', '<=', $endStr);
@@ -117,4 +118,4 @@ trait TimeCollection
return $this;
}
}
}

View File

@@ -31,16 +31,11 @@ use FireflyIII\Helpers\Collector\Extensions\AmountCollection;
use FireflyIII\Helpers\Collector\Extensions\CollectorProperties;
use FireflyIII\Helpers\Collector\Extensions\MetaCollection;
use FireflyIII\Helpers\Collector\Extensions\TimeCollection;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
@@ -526,7 +521,7 @@ class GroupCollector implements GroupCollectorInterface
}
// or parse the rest.
$journalId = (int) $augumentedJournal->transaction_journal_id;
$groups[$groupId]['count']++;
if (isset($groups[$groupId]['transactions'][$journalId])) {
// append data to existing group + journal (for multiple tags or multiple attachments)
@@ -536,6 +531,7 @@ class GroupCollector implements GroupCollectorInterface
if (!isset($groups[$groupId]['transactions'][$journalId])) {
// create second, third, fourth split:
$groups[$groupId]['count']++;
$groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedJournal($augumentedJournal);
}
}

View File

@@ -109,15 +109,13 @@ class NetWorth implements NetWorthInterface
Log::debug(sprintf('Balance is %s', $balance));
// if the account is a credit card, subtract the virtual balance from the balance,
// to better reflect that this is not money that is actually "yours".
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
// always subtract virtual balance.
$virtualBalance = (string) $account->virtual_balance;
if ('ccAsset' === $role && '' !== $virtualBalance && (float) $virtualBalance > 0) {
if ('' !== $virtualBalance) {
$balance = bcsub($balance, $virtualBalance);
}
Log::debug(sprintf('Balance corrected to %s', $balance));
Log::debug(sprintf('Balance corrected to %s because of virtual balance (%s)', $balance, $virtualBalance));
if (!isset($netWorth[$currencyId])) {
$netWorth[$currencyId] = '0';

View File

@@ -151,7 +151,12 @@ class CreateController extends Controller
// store attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($account, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($account, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore

View File

@@ -190,9 +190,13 @@ class EditController extends Controller
app('preferences')->mark();
// store new attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($account, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($account, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore

View File

@@ -101,7 +101,8 @@ class TelemetryController extends Controller
app('view')->share('subTitleIcon', 'fa-eye');
app('view')->share('subTitle', (string) trans('firefly.telemetry_admin_index'));
$version = config('firefly.version');
$enabled = config('firefly.telemetry', false);
$enabled = config('firefly.send_telemetry', false) && config('firefly.feature_flags.telemetry');
$count = $this->repository->count();
return view('admin.telemetry.index', compact('version', 'enabled', 'count'));

View File

@@ -82,14 +82,8 @@ class LoginController extends Controller
Log::channel('audit')->info(sprintf('User is trying to login using "%s"', $request->get('email')));
Log::info(sprintf('User is trying to login.'));
if ('ldap' === config('auth.providers.users.driver')) {
/**
* Temporary bug fix for something that doesn't seem to work in
* AdLdap.
*/
$schema = config('ldap.connections.default.schema');
/** @var Adldap\Connections\Provider $provider */
Adldap::getProvider('default')->setSchema(new $schema);
Adldap::getProvider('default');
}
$this->validateLogin($request);

View File

@@ -383,7 +383,12 @@ class BillController extends Controller
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($bill, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($bill, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
@@ -410,7 +415,12 @@ class BillController extends Controller
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($bill, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($bill, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
// flash messages
if (count($this->attachments->getMessages()->get('attachments')) > 0) {

View File

@@ -59,7 +59,7 @@ class AvailableBudgetController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.budgets'));
app('view')->share('mainTitleIcon', 'fa-tasks');
app('view')->share('mainTitleIcon', 'fa-pie-chart');
$this->abRepository = app(AvailableBudgetRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
@@ -157,6 +157,7 @@ class AvailableBudgetController extends Controller
*/
public function edit(AvailableBudget $availableBudget, Carbon $start, Carbon $end)
{
$availableBudget->amount = round($availableBudget->amount, $availableBudget->transactionCurrency->decimal_places);
return view('budgets.available-budgets.edit', compact('availableBudget', 'start', 'end'));
}

View File

@@ -70,7 +70,7 @@ class BudgetLimitController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.budgets'));
app('view')->share('mainTitleIcon', 'fa-tasks');
app('view')->share('mainTitleIcon', 'fa-pie-chart');
$this->repository = app(BudgetRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);

View File

@@ -58,7 +58,7 @@ class CreateController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.budgets'));
app('view')->share('mainTitleIcon', 'fa-tasks');
app('view')->share('mainTitleIcon', 'fa-pie-chart');
$this->repository = app(BudgetRepositoryInterface::class);
$this->attachments = app(AttachmentHelperInterface::class);
@@ -130,9 +130,13 @@ class CreateController extends Controller
app('preferences')->mark();
// store attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($budget, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($budget, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore

View File

@@ -54,7 +54,7 @@ class DeleteController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.budgets'));
app('view')->share('mainTitleIcon', 'fa-tasks');
app('view')->share('mainTitleIcon', 'fa-pie-chart');
$this->repository = app(BudgetRepositoryInterface::class);
return $next($request);

View File

@@ -59,7 +59,7 @@ class EditController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.budgets'));
app('view')->share('mainTitleIcon', 'fa-tasks');
app('view')->share('mainTitleIcon', 'fa-pie-chart');
$this->repository = app(BudgetRepositoryInterface::class);
$this->attachments = app(AttachmentHelperInterface::class);
@@ -137,9 +137,13 @@ class EditController extends Controller
$redirect = redirect($this->getPreviousUri('budgets.edit.uri'));
// store new attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($budget, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($budget, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore

View File

@@ -72,7 +72,7 @@ class IndexController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.budgets'));
app('view')->share('mainTitleIcon', 'fa-tasks');
app('view')->share('mainTitleIcon', 'fa-pie-chart');
$this->repository = app(BudgetRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->abRepository = app(AvailableBudgetRepositoryInterface::class);
@@ -86,7 +86,6 @@ class IndexController extends Controller
}
/**
* TODO the "budgeted" progress bar doesn't update.
* Show all budgets.
*
* @param Request $request
@@ -98,6 +97,7 @@ class IndexController extends Controller
*/
public function index(Request $request, Carbon $start = null, Carbon $end = null)
{
Log::debug('Start of IndexController::index()');
// collect some basic vars:
$range = app('preferences')->get('viewRange', '1M')->data;
$start = $start ?? session('start', Carbon::now()->startOfMonth());
@@ -105,16 +105,18 @@ class IndexController extends Controller
$defaultCurrency = app('amount')->getDefaultCurrency();
$budgeted = '0';
$spent = '0';
Log::debug(sprintf('1) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// new period stuff:
$periodTitle = app('navigation')->periodShow($start, $range);
$prevLoop = $this->getPreviousPeriods($start, $range);
$nextLoop = $this->getNextPeriods($start, $range);
Log::debug(sprintf('2) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// get all available budgets.
$ab = $this->abRepository->get($start, $end);
$availableBudgets = [];
Log::debug(sprintf('3) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// for each, complement with spent amount:
/** @var AvailableBudget $entry */
foreach ($ab as $entry) {
@@ -131,6 +133,7 @@ class IndexController extends Controller
$array['budgeted'] = $budgeted;
$availableBudgets[] = $array;
unset($spentArr);
Log::debug(sprintf('4) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
}
if (0 === count($availableBudgets)) {
@@ -139,6 +142,7 @@ class IndexController extends Controller
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $defaultCurrency);
$spent = $spentArr[$defaultCurrency->id]['sum'] ?? '0';
unset($spentArr);
Log::debug(sprintf('5) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
}
// count the number of enabled currencies. This determines if we display a "+" button.
@@ -148,11 +152,12 @@ class IndexController extends Controller
// number of days for consistent budgeting.
$activeDaysPassed = $this->activeDaysPassed($start, $end); // see method description.
$activeDaysLeft = $this->activeDaysLeft($start, $end); // see method description.
Log::debug(sprintf('Start: %s, end: %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
Log::debug(sprintf('6) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// get all budgets, and paginate them into $budgets.
$collection = $this->repository->getActiveBudgets();
$budgets = [];
Log::debug(sprintf('7) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// complement budget with budget limits in range, and expenses in currency X in range.
/** @var Budget $current */
@@ -163,18 +168,22 @@ class IndexController extends Controller
$array['attachments'] = $this->repository->getAttachments($current);
$array['auto_budget'] = $this->repository->getAutoBudget($current);
$budgetLimits = $this->blRepository->getBudgetLimits($current, $start, $end);
Log::debug(sprintf('8) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
/** @var BudgetLimit $limit */
foreach ($budgetLimits as $limit) {
$currency = $limit->transactionCurrency ?? $defaultCurrency;
$array['budgeted'][] = [
'id' => $limit->id,
'amount' => round($limit->amount, $currency->decimal_places),
'start_date' => $limit->start_date->formatLocalized($this->monthAndDayFormat),
'end_date' => $limit->end_date->formatLocalized($this->monthAndDayFormat),
'in_range' => $limit->start_date->isSameDay($start) && $limit->end_date->isSameDay($end),
'currency_id' => $currency->id,
'currency_symbol' => $currency->symbol,
'currency_name' => $currency->name,
'currency_decimal_places' => $currency->decimal_places,
];
Log::debug(sprintf('9) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
}
/** @var TransactionCurrency $currency */
@@ -185,6 +194,7 @@ class IndexController extends Controller
$array['spent'][$currency->id]['currency_id'] = $currency->id;
$array['spent'][$currency->id]['currency_symbol'] = $currency->symbol;
$array['spent'][$currency->id]['currency_decimal_places'] = $currency->decimal_places;
Log::debug(sprintf('10) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
}
}
$budgets[] = $array;
@@ -192,7 +202,7 @@ class IndexController extends Controller
// get all inactive budgets, and simply list them:
$inactive = $this->repository->getInactiveBudgets();
Log::debug(sprintf('11) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
return view(
'budgets.index',

View File

@@ -64,7 +64,7 @@ class ShowController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.budgets'));
app('view')->share('mainTitleIcon', 'fa-tasks');
app('view')->share('mainTitleIcon', 'fa-pie-chart');
$this->journalRepos = app(JournalRepositoryInterface::class);
$this->repository = app(BudgetRepositoryInterface::class);

View File

@@ -57,7 +57,7 @@ class CreateController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.categories'));
app('view')->share('mainTitleIcon', 'fa-bar-chart');
app('view')->share('mainTitleIcon', 'fa-bookmark');
$this->repository = app(CategoryRepositoryInterface::class);
$this->attachments = app(AttachmentHelperInterface::class);
@@ -102,9 +102,13 @@ class CreateController extends Controller
app('preferences')->mark();
// store attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($category, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($category, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore

View File

@@ -53,7 +53,7 @@ class DeleteController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.categories'));
app('view')->share('mainTitleIcon', 'fa-bar-chart');
app('view')->share('mainTitleIcon', 'fa-bookmark');
$this->repository = app(CategoryRepositoryInterface::class);
return $next($request);

View File

@@ -59,7 +59,7 @@ class EditController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.categories'));
app('view')->share('mainTitleIcon', 'fa-bar-chart');
app('view')->share('mainTitleIcon', 'fa-bookmark');
$this->repository = app(CategoryRepositoryInterface::class);
$this->attachments = app(AttachmentHelperInterface::class);
@@ -107,9 +107,13 @@ class EditController extends Controller
app('preferences')->mark();
// store new attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($category, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($category, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore

View File

@@ -53,7 +53,7 @@ class IndexController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.categories'));
app('view')->share('mainTitleIcon', 'fa-bar-chart');
app('view')->share('mainTitleIcon', 'fa-bookmark');
$this->repository = app(CategoryRepositoryInterface::class);
return $next($request);

View File

@@ -59,7 +59,7 @@ class NoCategoryController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.categories'));
app('view')->share('mainTitleIcon', 'fa-bar-chart');
app('view')->share('mainTitleIcon', 'fa-bookmark');
$this->journalRepos = app(JournalRepositoryInterface::class);
return $next($request);

View File

@@ -58,7 +58,7 @@ class ShowController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.categories'));
app('view')->share('mainTitleIcon', 'fa-bar-chart');
app('view')->share('mainTitleIcon', 'fa-bookmark');
$this->repository = app(CategoryRepositoryInterface::class);
return $next($request);
@@ -84,7 +84,7 @@ class ShowController extends Controller
$start = $start ?? session('start', Carbon::now()->startOfMonth());
/** @var Carbon $end */
$end = $end ?? session('end', Carbon::now()->endOfMonth());
$subTitleIcon = 'fa-bar-chart';
$subTitleIcon = 'fa-bookmark';
$page = (int) $request->get('page');
$attachments = $this->repository->getAttachments($category);
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
@@ -122,7 +122,7 @@ class ShowController extends Controller
public function showAll(Request $request, Category $category)
{
// default values:
$subTitleIcon = 'fa-bar-chart';
$subTitleIcon = 'fa-bookmark';
$page = (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$start = null;

View File

@@ -432,9 +432,15 @@ class AccountController extends Controller
$cache->addProperty($end);
$cache->addProperty($account->id);
if ($cache->has()) {
return response()->json($cache->get()); // @codeCoverageIgnore
return response()->json($cache->get()); // @codeCoverageIgnore
}
$currencies = $this->accountRepository->getUsedCurrencies($account);
// if the account is not expense or revenue, just use the account's default currency.
if (!in_array($account->accountType->type, [AccountType::REVENUE, AccountType::EXPENSE], true)) {
$currencies = [$this->accountRepository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency()];
}
/** @var TransactionCurrency $currency */
foreach ($currencies as $currency) {
$chartData[] = $this->periodByCurrency($start, $end, $account, $currency);
@@ -565,6 +571,7 @@ class AccountController extends Controller
*/
private function periodByCurrency(Carbon $start, Carbon $end, Account $account, TransactionCurrency $currency): array
{
$locale = app('steam')->getLocale();
$step = $this->calculateStep($start, $end);
$result = [
'label' => sprintf('%s (%s)', $account->name, $currency->symbol),
@@ -576,7 +583,7 @@ class AccountController extends Controller
switch ($step) {
case '1D':
// per day the entire period, balance for every day.
$format = (string) trans('config.month_and_day');
$format = (string) trans('config.month_and_day', [], $locale);
$range = app('steam')->balanceInRange($account, $start, $end, $currency);
$previous = array_values($range)[0];
while ($end >= $current) {

View File

@@ -111,6 +111,7 @@ class BillController extends Controller
if ($cache->has()) {
return response()->json($cache->get()); // @codeCoverageIgnore
}
$locale = app('steam')->getLocale();
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
@@ -131,7 +132,7 @@ class BillController extends Controller
];
foreach ($journals as $journal) {
$date = $journal['date']->formatLocalized((string) trans('config.month_and_day'));
$date = $journal['date']->formatLocalized((string) trans('config.month_and_day', [], $locale));
$chartData[0]['entries'][$date] = $bill->amount_min; // minimum amount of bill
$chartData[1]['entries'][$date] = $bill->amount_max; // maximum amount of bill

View File

@@ -179,14 +179,14 @@ class BudgetController extends Controller
if ($cache->has()) {
return response()->json($cache->get()); // @codeCoverageIgnore
}
$locale = app('steam')->getLocale();
$entries = [];
$amount = $budgetLimit->amount;
$budgetCollection = new Collection([$budget]);
while ($start <= $end) {
$spent = $this->opsRepository->spentInPeriod($budgetCollection, new Collection, $start, $start);
$amount = bcadd($amount, $spent);
$format = $start->formatLocalized((string)trans('config.month_and_day'));
$format = $start->formatLocalized((string)trans('config.month_and_day', [], $locale));
$entries[$format] = $amount;
$start->addDay();

View File

@@ -76,6 +76,7 @@ class PiggyBankController extends Controller
}
$set = $repository->getEvents($piggyBank);
$set = $set->reverse();
$locale =app('steam')->getLocale();
// get first event or start date of piggy bank or today
$startDate = $piggyBank->start_date ?? new Carbon;
@@ -99,7 +100,7 @@ class PiggyBankController extends Controller
}
);
$currentSum = $filtered->sum('amount');
$label = $oldest->formatLocalized((string) trans('config.month_and_day'));
$label = $oldest->formatLocalized((string) trans('config.month_and_day', [], $locale));
$chartData[$label] = $currentSum;
$oldest = app('navigation')->addPeriod($oldest, $step, 0);
}
@@ -110,7 +111,7 @@ class PiggyBankController extends Controller
}
);
$finalSum = $finalFiltered->sum('amount');
$finalLabel = $today->formatLocalized((string) trans('config.month_and_day'));
$finalLabel = $today->formatLocalized((string) trans('config.month_and_day', [], $locale));
$chartData[$finalLabel] = $finalSum;
$data = $this->generator->singleSet($piggyBank->name, $chartData);

View File

@@ -79,6 +79,7 @@ class ReportController extends Controller
if ($cache->has()) {
return response()->json($cache->get()); // @codeCoverageIgnore
}
$locale = app('steam')->getLocale();
$current = clone $start;
$chartData = [];
/** @var NetWorthInterface $helper */
@@ -110,7 +111,7 @@ class ReportController extends Controller
/** @var array $netWorthItem */
foreach ($result as $netWorthItem) {
$currencyId = $netWorthItem['currency']->id;
$label = $current->formatLocalized((string) trans('config.month_and_day'));
$label = $current->formatLocalized((string) trans('config.month_and_day', [], $locale));
if (!isset($chartData[$currencyId])) {
$chartData[$currencyId] = [
'label' => 'Net worth in ' . $netWorthItem['currency']->name,

View File

@@ -82,21 +82,11 @@ class TransactionController extends Controller
foreach ($result as $journal) {
$budget = $journal['budget_name'] ?? (string) trans('firefly.no_budget');
$title = sprintf('%s (%s)', $budget, $journal['currency_symbol']);
// key => [value => x, 'currency_symbol' => 'x']
$data[$title] = $data[$title] ?? [
'amount' => '0',
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']);
if (null !== $journal['foreign_amount']) {
$title = sprintf('%s (%s)', $budget, $journal['foreign_currency_symbol']);
$data[$title] = $data[$title] ?? [
'amount' => $journal['foreign_amount'],
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['foreign_amount']);
}
}
$chart = $this->generator->multiCurrencyPieChart($data);
$cache->store($chart);
@@ -138,6 +128,7 @@ class TransactionController extends Controller
$collector->setTypes([TransactionType::DEPOSIT]);
break;
case 'transfers':
case 'transfer':
$collector->setTypes([TransactionType::TRANSFER]);
break;
}
@@ -149,21 +140,12 @@ class TransactionController extends Controller
foreach ($result as $journal) {
$category = $journal['category_name'] ?? (string) trans('firefly.no_category');
$title = sprintf('%s (%s)', $category, $journal['currency_symbol']);
// key => [value => x, 'currency_symbol' => 'x']
$data[$title] = $data[$title] ?? [
'amount' => '0',
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']);
if (null !== $journal['foreign_amount']) {
$title = sprintf('%s (%s)', $category, $journal['foreign_currency_symbol']);
$data[$title] = $data[$title] ?? [
'amount' => $journal['foreign_amount'],
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['foreign_amount']);
}
}
$chart = $this->generator->multiCurrencyPieChart($data);
$cache->store($chart);
@@ -222,15 +204,6 @@ class TransactionController extends Controller
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']);
if (null !== $journal['foreign_amount']) {
$title = sprintf('%s (%s)', $name, $journal['foreign_currency_symbol']);
$data[$title] = $data[$title] ?? [
'amount' => $journal['foreign_amount'],
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['foreign_amount']);
}
}
$chart = $this->generator->multiCurrencyPieChart($data);
$cache->store($chart);
@@ -290,14 +263,6 @@ class TransactionController extends Controller
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']);
if (null !== $journal['foreign_amount']) {
$title = sprintf('%s (%s)', $name, $journal['foreign_currency_symbol']);
$data[$title] = $data[$title] ?? [
'amount' => $journal['foreign_amount'],
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['foreign_amount']);
}
}
$chart = $this->generator->multiCurrencyPieChart($data);
$cache->store($chart);

View File

@@ -85,17 +85,20 @@ class Controller extends BaseController
$this->middleware(
function ($request, $next) {
$locale = app('steam')->getLocale();
// translations for specific strings:
$this->monthFormat = (string) trans('config.month');
$this->monthAndDayFormat = (string) trans('config.month_and_day');
$this->dateTimeFormat = (string) trans('config.date_time');
$this->monthFormat = (string) trans('config.month', [], $locale);
$this->monthAndDayFormat = (string) trans('config.month_and_day', [], $locale);
$this->dateTimeFormat = (string) trans('config.date_time', [], $locale);
// get shown-intro-preference:
if (auth()->check()) {
$language = $this->getLanguage();
$language = app('steam')->getLanguage();
$locale = app('steam')->getLocale();
$page = $this->getPageName();
$shownDemo = $this->hasSeenDemo();
app('view')->share('language', $language);
app('view')->share('locale', $locale);
app('view')->share('shownDemo', $shownDemo);
app('view')->share('current_route_name', $page);
app('view')->share('original_route_name', Route::currentRouteName());

View File

@@ -126,7 +126,6 @@ class DebugController extends Controller
$phpOs = str_replace($search, $replace, PHP_OS);
$interface = PHP_SAPI;
$now = Carbon::now()->format('Y-m-d H:i:s e');
$extensions = implode(', ', get_loaded_extensions());
$drivers = implode(', ', DB::availableDrivers());
$currentDriver = DB::getDriverName();
$userAgent = $request->header('user-agent');
@@ -143,7 +142,7 @@ class DebugController extends Controller
// set languages, see what happens:
$original = setlocale(LC_ALL, 0);
$localeAttempts = [];
$parts = explode(',', (string) trans('config.locale'));
$parts = app('steam')->getLocaleArray(app('steam')->getLocale());
foreach ($parts as $code) {
$code = trim($code);
$localeAttempts[$code] = var_export(setlocale(LC_ALL, $code), true);
@@ -178,7 +177,6 @@ class DebugController extends Controller
'debug',
compact(
'phpVersion',
'extensions',
'localeAttempts',
'appEnv',
'appDebug',

View File

@@ -126,7 +126,7 @@ class JavascriptController extends Controller
/** @noinspection NullPointerExceptionInspection */
$lang = $pref->data;
$dateRange = $this->getDateRangeConfig();
$uid = substr(hash('sha256', auth()->user()->id . auth()->user()->email), 0, 12);
$uid = substr(hash('sha256', sprintf('%s-%s-%s', (string) config('app.key'), auth()->user()->id, auth()->user()->email)), 0, 12);
$data = [
'currencyCode' => $currency->code,

View File

@@ -263,7 +263,7 @@ class BoxController extends Controller
*/
public function netWorth(): JsonResponse
{
$date = Carbon::now()->startOfDay();
$date = Carbon::now()->endOfDay();
// start and end in the future? use $end
if ($this->notInSessionRange($date)) {

View File

@@ -63,7 +63,7 @@ class BudgetController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.budgets'));
app('view')->share('mainTitleIcon', 'fa-tasks');
app('view')->share('mainTitleIcon', 'fa-pie-chart');
$this->repository = app(BudgetRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->abRepository = app(AvailableBudgetRepositoryInterface::class);

View File

@@ -151,6 +151,7 @@ class RecurrenceController extends Controller
$today = Carbon::now()->startOfDay();
$date = Carbon::createFromFormat('Y-m-d', $string)->startOfDay();
$preSelected = (string) $request->get('pre_select');
$locale = app('steam')->getLocale();
Log::debug(sprintf('date = %s, today = %s. date > today? %s', $date->toAtomString(), $today->toAtomString(), var_export($date > $today, true)));
Log::debug(sprintf('past = true? %s', var_export('true' === (string) $request->get('past'), true)));
@@ -163,7 +164,7 @@ class RecurrenceController extends Controller
$dayOfWeek = (string) trans(sprintf('config.dow_%s', $date->dayOfWeekIso));
$ndom = sprintf('ndom,%s,%s', $date->weekOfMonth, $date->dayOfWeekIso);
$yearly = sprintf('yearly,%s', $date->format('Y-m-d'));
$yearlyDate = $date->formatLocalized((string) trans('config.month_and_day_no_year'));
$yearlyDate = $date->formatLocalized((string) trans('config.month_and_day_no_year', [], $locale));
$result = [
'daily' => ['label' => (string) trans('firefly.recurring_daily'), 'selected' => 0 === strpos($preSelected, 'daily')],
$weekly => ['label' => (string) trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek]),

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use FireflyIII\Http\Requests\NewUserFormRequest;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Controllers\CreateStuff;
@@ -110,6 +111,12 @@ class NewUserController extends Controller
// store currency preference:
app('preferences')->set('currencyPreference', $currency->code);
// store frontpage preferences:
$accounts = $this->repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray();
app('preferences')->set('frontPageAccounts', $accounts);
// mark.
app('preferences')->mark();
// set default optional fields:

View File

@@ -71,7 +71,7 @@ class PiggyBankController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.piggyBanks'));
app('view')->share('mainTitleIcon', 'fa-sort-amount-asc');
app('view')->share('mainTitleIcon', 'fa-bullseye');
$this->attachments = app(AttachmentHelperInterface::class);
$this->piggyRepos = app(PiggyBankRepositoryInterface::class);
@@ -456,7 +456,12 @@ class PiggyBankController extends Controller
// store attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($piggyBank, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($piggyBank, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
@@ -495,7 +500,12 @@ class PiggyBankController extends Controller
// store new attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($piggyBank, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($piggyBank, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore

View File

@@ -31,6 +31,7 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
use JsonException;
/**
* Class PreferencesController.
@@ -90,8 +91,9 @@ class PreferencesController extends Controller
$viewRange = $viewRangePref->data;
$frontPageAccounts = app('preferences')->get('frontPageAccounts', $accountIds);
$language = app('preferences')->get('language', config('firefly.default_language', 'en_US'))->data;
$language = app('steam')->getLanguage();
$languages = config('firefly.languages');
$locale = app('preferences')->get('locale', config('firefly.default_locale', 'equal'))->data;
$listPageSize = app('preferences')->get('listPageSize', 50)->data;
$customFiscalYear = app('preferences')->get('customFiscalYear', 0)->data;
$fiscalYearStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data;
@@ -100,6 +102,15 @@ class PreferencesController extends Controller
ksort($languages);
// list of locales also has "equal" which makes it equal to whatever the language is.
try {
$locales = json_decode(file_get_contents(resource_path(sprintf('lang/%s/locales.json', $language))), true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
Log::error($e->getMessage());
$locales = [];
}
$locales = ['equal' => (string) trans('firefly.equal_to_language')] + $locales;
// an important fallback is that the frontPageAccount array gets refilled automatically
// when it turns up empty.
if (0 === count($frontPageAccounts->data)) {
@@ -113,6 +124,8 @@ class PreferencesController extends Controller
'groupedAccounts',
'frontPageAccounts',
'languages',
'locales',
'locale',
'tjOptionalFields',
'viewRange',
'customFiscalYear',
@@ -172,6 +185,13 @@ class PreferencesController extends Controller
session()->flash('info', 'All translations are supplied by volunteers. There might be errors and mistakes. I appreciate your feedback.');
}
// same for locale:
if (!auth()->user()->hasRole('demo')) {
/** @var Preference $currentLocale */
$locale = $request->get('locale');
app('preferences')->set('locale', $locale);
}
// optional fields for transactions:
$setOptions = $request->get('tj');
$optionalTj = [

View File

@@ -555,7 +555,7 @@ class ProfileController extends Controller
/** @var string $match */
$match = null;
foreach ($set as $entry) {
$hashed = hash('sha256', $entry->data);
$hashed = hash('sha256', sprintf('%s%s', (string) config('app.key'), $entry->data));
if ($hashed === $hash) {
$match = $entry->data;
break;

View File

@@ -85,6 +85,8 @@ class IndexController extends Controller
$page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$collection = $this->recurring->get();
$today = new Carbon;
$year = new Carbon;
// split collection
$total = $collection->count();
@@ -98,8 +100,7 @@ class IndexController extends Controller
$recurring = [];
/** @var Recurrence $recurrence */
foreach ($recurrences as $recurrence) {
$today = new Carbon;
$year = new Carbon;
$year->addYear();
if ($recurrence->first_date > $today) {
$today = clone $recurrence->first_date;
@@ -110,15 +111,26 @@ class IndexController extends Controller
$array['first_date'] = new Carbon($array['first_date']);
$array['repeat_until'] = null === $array['repeat_until'] ? null : new Carbon($array['repeat_until']);
$array['latest_date'] = null === $array['latest_date'] ? null : new Carbon($array['latest_date']);
$array['occurrences'] = array_slice($this->recurring->getOccurrencesInRange($recurrence->recurrenceRepetitions->first(), $today, $year), 0, 1);
$recurring[] = $array;
// make carbon objects out of occurrences
foreach ($array['repetitions'] as $repIndex => $repetition) {
foreach ($repetition['occurrences'] as $occIndex => $occurrence) {
$array['repetitions'][$repIndex]['occurrences'][$occIndex] = new Carbon($occurrence);
}
}
//if (0 !== $recurrence->recurrenceRepetitions->count()) {
//$array['ocurrences'] = array_slice($this->recurring->getOccurrencesInRange($recurrence->recurrenceRepetitions->first(), $today, $year), 0, 1);
//}
$recurring[] = $array;
}
$paginator = new LengthAwarePaginator($recurring, $total, $pageSize, $page);
$paginator->setPath(route('recurring.index'));
$this->verifyRecurringCronJob();
return view('recurring.index', compact('paginator', 'page', 'pageSize', 'total'));
return view('recurring.index', compact('paginator', 'today', 'page', 'pageSize', 'total'));
}
}

View File

@@ -82,8 +82,10 @@ class ShowController extends Controller
$transformer = app(RecurrenceTransformer::class);
$transformer->setParameters(new ParameterBag);
$array = $transformer->transform($recurrence);
$groups = $this->recurring->getTransactions($recurrence);
$array = $transformer->transform($recurrence);
$groups = $this->recurring->getTransactions($recurrence);
$today = new Carbon;
$array['repeat_until'] = null !== $array['repeat_until'] ? new Carbon($array['repeat_until']) : null;
// transform dates back to Carbon objects:
foreach ($array['repetitions'] as $index => $repetition) {
@@ -94,6 +96,6 @@ class ShowController extends Controller
$subTitle = (string) trans('firefly.overview_for_recurrence', ['title' => $recurrence->title]);
return view('recurring.show', compact('recurrence', 'subTitle', 'array', 'groups'));
return view('recurring.show', compact('recurrence', 'subTitle', 'array', 'groups','today'));
}
}

View File

@@ -301,7 +301,6 @@ class BudgetController extends Controller
$report[$budgetId]['currencies'][$currencyId]['sum_pct'] = $pct;
}
}
return view('reports.budget.partials.budgets', compact('sums', 'report'));
}
@@ -317,6 +316,7 @@ class BudgetController extends Controller
*/
public function general(Collection $accounts, Carbon $start, Carbon $end)
{
$report = [
'budgets' => [],
'sums' => [],
@@ -488,6 +488,7 @@ class BudgetController extends Controller
foreach ($expenses as $currency) {
foreach ($currency['budgets'] as $budget) {
$count = 0;
$total = '0';
foreach ($budget['transaction_journals'] as $journal) {
$count++;
$key = sprintf('%d-%d', $budget['id'], $currency['currency_id']);
@@ -506,7 +507,7 @@ class BudgetController extends Controller
$report[$key]['entries'][$dateKey] = $report[$key] ['entries'][$dateKey] ?? '0';
$report[$key]['entries'][$dateKey] = bcadd($journal['amount'], $report[$key] ['entries'][$dateKey]);
$report[$key]['sum'] = bcadd($report[$key] ['sum'], $journal['amount']);
$report[$key]['avg'] = bcdiv($report[$key]['sum'], (string) $count);
$report[$key]['avg'] = bcdiv($report[$key]['sum'], (string) count($periods));
}
}
}

View File

@@ -64,7 +64,7 @@ class ReportController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.reports'));
app('view')->share('mainTitleIcon', 'fa-line-chart');
app('view')->share('mainTitleIcon', 'fa-bar-chart');
app('view')->share('subTitleIcon', 'fa-calendar');
$this->helper = app(ReportHelperInterface::class);
$this->repository = app(BudgetRepositoryInterface::class);

View File

@@ -91,6 +91,7 @@ class IndexController extends Controller
$user = auth()->user();
$this->createDefaultRuleGroup();
$this->createDefaultRule();
$this->ruleGroupRepos->resetRuleGroupOrder();
$ruleGroups = $this->ruleGroupRepos->getRuleGroupsWithRules($user);
return view('rules.index', compact('ruleGroups'));

View File

@@ -41,6 +41,7 @@ class CronController
{
$results = [];
$results[] = $this->runRecurring();
$results[] = $this->runAutoBudget();
return implode("<br>\n", $results);
}

View File

@@ -60,7 +60,7 @@ class TagController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.tags'));
app('view')->share('mainTitleIcon', 'fa-tags');
app('view')->share('mainTitleIcon', 'fa-tag');
$this->attachments = app(AttachmentHelperInterface::class);
$this->repository = app(TagRepositoryInterface::class);
@@ -321,7 +321,12 @@ class TagController extends Controller
// store attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($result, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($result, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
@@ -359,7 +364,12 @@ class TagController extends Controller
// store new attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($tag, $files);
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($tag, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore

View File

@@ -56,7 +56,7 @@ class BulkController extends Controller
function ($request, $next) {
$this->repository = app(JournalRepositoryInterface::class);
app('view')->share('title', (string) trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-repeat');
app('view')->share('mainTitleIcon', 'fa-exchange');
return $next($request);
}

View File

@@ -206,9 +206,9 @@ class ConvertController extends Controller
// double check its not an empty string.
$sourceId = '' === $sourceId || null === $sourceId ? null : (int) $sourceId;
$sourceName = '' === $sourceName ? null : $sourceName;
$sourceName = '' === $sourceName ? null : (string) $sourceName;
$destinationId = '' === $destinationId || null === $destinationId ? null : (int) $destinationId;
$destinationName = (string)('' === $destinationName ? null : $destinationName);
$destinationName = '' === $destinationName ? null : (string) $destinationName;
$validSource = $validator->validateSource($sourceId, $sourceName, null);
$validDestination = $validator->validateDestination($destinationId, $destinationName, null);

View File

@@ -49,7 +49,7 @@ class CreateController extends Controller
$this->middleware(
static function ($request, $next) {
app('view')->share('title', (string) trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-repeat');
app('view')->share('mainTitleIcon', 'fa-exchange');
return $next($request);
}

View File

@@ -56,7 +56,7 @@ class DeleteController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-repeat');
app('view')->share('mainTitleIcon', 'fa-exchange');
$this->repository = app(TransactionGroupRepositoryInterface::class);

View File

@@ -52,7 +52,7 @@ class EditController extends Controller
static function ($request, $next) {
app('view')->share('title', (string) trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-repeat');
app('view')->share('mainTitleIcon', 'fa-exchange');
return $next($request);
}

View File

@@ -56,8 +56,8 @@ class IndexController extends Controller
// translations:
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-credit-card');
app('view')->share('title', (string) trans('firefly.accounts'));
app('view')->share('mainTitleIcon', 'fa-exchange');
app('view')->share('title', (string) trans('firefly.transactions'));
$this->repository = app(JournalRepositoryInterface::class);
@@ -88,7 +88,9 @@ class IndexController extends Controller
$end = session('end');
}
if (null === $end) {
$end = session('end'); // @codeCoverageIgnore
// get last transaction ever?
$last = $this->repository->getLast();
$end = $last ? $last->date : session('end');
}
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
@@ -134,14 +136,15 @@ class IndexController extends Controller
$repository = app(JournalRepositoryInterface::class);
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $objectType);
$types = config('firefly.transactionTypesByWhat.' . $objectType);
$subTitleIcon = config('firefly.transactionIconsByType.' . $objectType);
$types = config('firefly.transactionTypesByType.' . $objectType);
$page = (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$path = route('transactions.index.all', [$objectType]);
$first = $repository->firstNull();
$start = null === $first ? new Carbon : $first->date;
$end = new Carbon;
$last = $this->repository->getLast();
$end = $last ? $last->date : new Carbon;
$subTitle = (string) trans('firefly.all_' . $objectType);
/** @var GroupCollectorInterface $collector */

View File

@@ -57,7 +57,7 @@ class LinkController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-repeat');
app('view')->share('mainTitleIcon', 'fa-exchange');
$this->journalRepository = app(JournalRepositoryInterface::class);
$this->repository = app(LinkTypeRepositoryInterface::class);

View File

@@ -62,7 +62,7 @@ class MassController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-repeat');
app('view')->share('mainTitleIcon', 'fa-exchange');
$this->repository = app(JournalRepositoryInterface::class);
return $next($request);

View File

@@ -26,6 +26,7 @@ use App;
use Carbon\Carbon;
use Closure;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Http\Controllers\RequestInformation;
use Illuminate\Http\Request;
/**
@@ -33,6 +34,7 @@ use Illuminate\Http\Request;
*/
class Range
{
use RequestInformation;
/**
* Handle an incoming request.
*
@@ -72,16 +74,16 @@ class Range
*/
private function configureView(): void
{
$pref = app('preferences')->get('language', config('firefly.default_language', 'en_US'));
/** @noinspection NullPointerExceptionInspection */
$lang = $pref->data;
App::setLocale($lang);
Carbon::setLocale(substr($lang, 0, 2));
$locale = explode(',', (string) trans('config.locale'));
$locale = array_map('trim', $locale);
// get locale preference:
$language = app('steam')->getLanguage();
$locale = app('steam')->getLocale();
App::setLocale($language);
Carbon::setLocale(substr($locale, 0, 2));
setlocale(LC_TIME, $locale);
$moneyResult = setlocale(LC_MONETARY, $locale);
$localeArray = app('steam')->getLocaleArray($locale);
setlocale(LC_TIME, $localeArray);
$moneyResult = setlocale(LC_MONETARY, $localeArray);
// send error to view if could not set money format
if (false === $moneyResult) {
@@ -89,12 +91,12 @@ class Range
}
// save some formats:
$monthAndDayFormat = (string) trans('config.month_and_day');
$dateTimeFormat = (string) trans('config.date_time');
$monthAndDayFormat = (string) trans('config.month_and_day', [], $locale);
$dateTimeFormat = (string) trans('config.date_time', [], $locale);
$defaultCurrency = app('amount')->getDefaultCurrency();
// also format for moment JS:
$madMomentJS = (string) trans('config.month_and_day_moment_js');
$madMomentJS = (string) trans('config.month_and_day_moment_js', [], $locale);
app('view')->share('madMomentJS', $madMomentJS);
app('view')->share('monthAndDayFormat', $monthAndDayFormat);

View File

@@ -58,7 +58,7 @@ class SecureHeaders
"base-uri 'self'",
"font-src 'self' data:",
"connect-src 'self'",
sprintf("img-src 'self' data: https://api.tiles.mapbox.com %s", $trackingScriptSrc),
sprintf("img-src 'self' data: https://a.tile.openstreetmap.org https://b.tile.openstreetmap.org https://c.tile.openstreetmap.org https://api.tiles.mapbox.com %s", $trackingScriptSrc),
"manifest-src 'self'",
];

View File

@@ -68,7 +68,7 @@ class BudgetFormStoreRequest extends Request
'name' => 'required|between:1,100|uniqueObjectForUser:budgets,name',
'active' => 'numeric|between:0,1',
'auto_budget_type' => 'numeric|between:0,2',
'auto_budget_currency_id' => 'required|exists:transaction_currencies,id',
'auto_budget_currency_id' => 'exists:transaction_currencies,id',
'auto_budget_amount' => 'min:0|max:1000000000',
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly',
];

View File

@@ -78,7 +78,7 @@ class BudgetFormUpdateRequest extends Request
'name' => $nameRule,
'active' => 'numeric|between:0,1',
'auto_budget_option' => 'numeric|between:0,2',
'auto_budget_currency_id' => 'required|exists:transaction_currencies,id',
'auto_budget_currency_id' => 'exists:transaction_currencies,id',
'auto_budget_amount' => 'min:0|max:1000000000',
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly',
];

View File

@@ -53,7 +53,7 @@ class PiggyBankFormRequest extends Request
'account_id' => $this->integer('account_id'),
'targetamount' => $this->string('targetamount'),
'targetdate' => $this->date('targetdate'),
'notes' => $this->string('notes'),
'notes' => $this->nlString('notes'),
];
}

View File

@@ -50,7 +50,7 @@ class ProfileFormRequest extends Request
// fixed
return [
'current_password' => 'required',
'new_password' => 'required|confirmed|secure_password',
'new_password' => 'required|confirmed|secure_password|min:16',
'new_password_confirmation' => 'required',
];
}

View File

@@ -297,8 +297,9 @@ class Request extends FormRequest
$latitudeKey = $this->getLocationKey($prefix, 'latitude');
$zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level');
$hasLocationKey = $this->getLocationKey($prefix, 'has_location');
$hasLocation = $this->boolean($hasLocationKey);
// for a POST (store, all fields must be present and accounted for:
// for a POST (store), all fields must be present and accounted for:
if (
('POST' === $this->method() && $this->routeIs('*.store'))
&& ($this->has($longitudeKey) && $this->has($latitudeKey) && $this->has($zoomLevelKey))
@@ -322,12 +323,14 @@ class Request extends FormRequest
$data['latitude'] = $this->nullableString($latitudeKey);
$data['zoom_level'] = $this->nullableString($zoomLevelKey);
}
if (null === $data['longitude'] || null === $data['latitude'] || null === $data['zoom_level']) {
Log::debug('One of the fields is NULL, wont save.');
if (false === $hasLocation || null === $data['longitude'] || null === $data['latitude'] || null === $data['zoom_level']) {
Log::debug('One of the fields is NULL or hasLocation is false, wont save.');
$data['store_location'] = false;
$data['update_location'] = false;
$data['update_location'] = true; // update is always true, but the values are null:
$data['longitude'] = null;
$data['latitude'] = null;
$data['zoom_level'] = null;
}
Log::debug(sprintf('Returning longitude: "%s", latitude: "%s", zoom level: "%s"', $data['longitude'], $data['latitude'], $data['zoom_level']));
return $data;

View File

@@ -94,12 +94,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property-read int|null $notes_count
* @property-read int|null $piggy_banks_count
* @property-read int|null $transactions_count
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property int $account_type_id
* @property bool $encrypted
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\AccountMeta[] $accountMeta
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBank[] $piggyBanks
*/
class Account extends Model
{
@@ -258,7 +252,11 @@ class Account extends Model
*/
public function setVirtualBalanceAttribute($value): void
{
$this->attributes['virtual_balance'] = (string) $value;
$value = (string)$value;
if('' === $value) {
$value = null;
}
$this->attributes['virtual_balance'] = $value;
}
/**

View File

@@ -83,7 +83,7 @@ class AccountMeta extends Model
*/
public function getDataAttribute($value)
{
return json_decode($value);
return json_decode($value, true, 512, JSON_THROW_ON_ERROR);
}
/**

View File

@@ -77,6 +77,10 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property-read int|null $budgetlimits_count
* @property-read int|null $transaction_journals_count
* @property-read int|null $transactions_count
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property bool $encrypted
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\BudgetLimit[] $budgetlimits
*/
class Budget extends Model
{

View File

@@ -78,7 +78,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property-read int|null $notes_count
* @property-read int|null $piggy_bank_events_count
* @property-read int|null $piggy_bank_repetitions_count
* @property bool $encrypted
*/
class PiggyBank extends Model
{

View File

@@ -78,13 +78,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property-read \Illuminate\Database\Eloquent\Collection|Location[] $locations
* @property-read int|null $locations_count
* @property-read int|null $transaction_journals_count
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property string $tagMode
* @property string|null $description
* @property float|null $latitude
* @property float|null $longitude
* @property int|null $zoomLevel
*/
class Tag extends Model
{

View File

@@ -26,6 +26,7 @@ use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use Laravel\Passport\Passport;
use URL;
use Adldap\Laravel\Middleware\WindowsAuthenticate;
/**
* @codeCoverageIgnore
@@ -44,6 +45,9 @@ class AppServiceProvider extends ServiceProvider
if ('heroku' === config('app.env')) {
URL::forceScheme('https');
}
if (config('ldap_auth.identifiers.windows.enabled', false)) {
$this->app['router']->pushMiddlewareToGroup('web', WindowsAuthenticate::class);
}
}
/**

View File

@@ -48,7 +48,7 @@ use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequest;
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequestInterface;
use FireflyIII\Services\IP\IpifyOrg;
use FireflyIII\Services\IP\IPRetrievalInterface;
use FireflyIII\Services\Password\PwndVerifierV3;
use FireflyIII\Services\Password\PwndVerifierV2;
use FireflyIII\Services\Password\Verifier;
use FireflyIII\Support\Amount;
use FireflyIII\Support\ExpandedForm;
@@ -189,7 +189,7 @@ class FireflyServiceProvider extends ServiceProvider
$this->app->bind(ExchangeRateInterface::class, $class);
// password verifier thing
$this->app->bind(Verifier::class, PwndVerifierV3::class);
$this->app->bind(Verifier::class, PwndVerifierV2::class);
// IP thing:
$this->app->bind(IPRetrievalInterface::class, IpifyOrg::class);

View File

@@ -28,6 +28,7 @@ use FireflyIII\Factory\AccountFactory;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Location;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup;
@@ -39,6 +40,7 @@ use FireflyIII\User;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;
use Log;
use Storage;
/**
* Class AccountRepository.
@@ -473,27 +475,34 @@ class AccountRepository implements AccountRepositoryInterface
if (AccountType::ASSET !== $account->accountType->type) {
throw new FireflyException(sprintf('%s is not an asset account.', $account->name));
}
$name = trans('firefly.reconciliation_account_name', ['name' => $account->name]);
$currency = $this->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$name = trans('firefly.reconciliation_account_name', ['name' => $account->name, 'currency' => $currency->code]);
/** @var AccountType $type */
$type = AccountType::where('type', AccountType::RECONCILIATION)->first();
$accounts = $this->user->accounts()->where('account_type_id', $type->id)->get();
// TODO no longer need to loop like this
$type = AccountType::where('type', AccountType::RECONCILIATION)->first();
$current = $this->user->accounts()->where('account_type_id', $type->id)
->where('name', $name)
->first();
/** @var Account $current */
foreach ($accounts as $current) {
if ($current->name === $name) {
return $current;
}
if (null !== $current) {
return $current;
}
$data = [
'account_type_id' => null,
'account_type' => AccountType::RECONCILIATION,
'active' => true,
'name' => $name,
'currency_id' => $currency->id,
'currency_code' => $currency->code,
];
/** @var AccountFactory $factory */
$factory = app(AccountFactory::class);
$factory->setUser($account->user);
$account = $factory->findOrCreate($name, $type->type);
return $account;
return $factory->create($data);
}
/**
@@ -651,7 +660,22 @@ class AccountRepository implements AccountRepositoryInterface
*/
public function getAttachments(Account $account): Collection
{
return $account->attachments()->get();
$set = $account->attachments()->get();
/** @var Storage $disk */
$disk = Storage::disk('upload');
$set = $set->each(
static function (Attachment $attachment) use ($disk) {
$notes = $attachment->notes()->first();
$attachment->file_exists = $disk->exists($attachment->fileName());
$attachment->notes = $notes ? $notes->text : '';
return $attachment;
}
);
return $set;
}
/**

View File

@@ -26,6 +26,7 @@ use Carbon\Carbon;
use DB;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\BillFactory;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Note;
use FireflyIII\Models\Transaction;
@@ -39,6 +40,7 @@ use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Log;
use Storage;
/**
* Class BillRepository.
@@ -164,7 +166,22 @@ class BillRepository implements BillRepositoryInterface
*/
public function getAttachments(Bill $bill): Collection
{
return $bill->attachments()->get();
$set = $bill->attachments()->get();
/** @var Storage $disk */
$disk = Storage::disk('upload');
$set = $set->each(
static function (Attachment $attachment) use ($disk) {
$notes = $attachment->notes()->first();
$attachment->file_exists = $disk->exists($attachment->fileName());
$attachment->notes = $notes ? $notes->text : '';
return $attachment;
}
);
return $set;
}
/**

View File

@@ -26,6 +26,7 @@ use Carbon\Carbon;
use DB;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\AutoBudget;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
@@ -38,6 +39,7 @@ use FireflyIII\User;
use Illuminate\Database\QueryException;
use Illuminate\Support\Collection;
use Log;
use Storage;
/**
* Class BudgetRepository.
@@ -79,6 +81,8 @@ class BudgetRepository implements BudgetRepositoryInterface
$budget->order = $index + 1;
$budget->save();
}
// other budgets, set to 0.
$this->user->budgets()->where('active', 0)->update(['order' => 0]);
return true;
}
@@ -187,12 +191,12 @@ class BudgetRepository implements BudgetRepositoryInterface
*/
public function getActiveBudgets(): Collection
{
//throw new \RuntimeException;
/** @var Collection $set */
$set = $this->user->budgets()->where('active', 1)
->orderBy('order', 'DESC')
->orderBy('order', 'ASC')
->orderBy('name', 'ASC')
->get();
return $set;
}
@@ -202,7 +206,7 @@ class BudgetRepository implements BudgetRepositoryInterface
public function getBudgets(): Collection
{
/** @var Collection $set */
$set = $this->user->budgets()->orderBy('order', 'DESC')
$set = $this->user->budgets()->orderBy('order', 'ASC')
->orderBy('name', 'ASC')->get();
return $set;
@@ -227,7 +231,7 @@ class BudgetRepository implements BudgetRepositoryInterface
{
/** @var Collection $set */
$set = $this->user->budgets()
->orderBy('order', 'DESC')
->orderBy('order', 'ASC')
->orderBy('name', 'ASC')->where('active', 0)->get();
return $set;
@@ -277,11 +281,13 @@ class BudgetRepository implements BudgetRepositoryInterface
*/
public function store(array $data): Budget
{
$order = $this->getMaxOrder();
try {
$newBudget = Budget::create(
[
'user_id' => $this->user->id,
'name' => $data['name'],
'order' => $order + 1,
]
);
} catch (QueryException $e) {
@@ -485,6 +491,26 @@ class BudgetRepository implements BudgetRepositoryInterface
*/
public function getAttachments(Budget $budget): Collection
{
return $budget->attachments()->get();
$set = $budget->attachments()->get();
/** @var Storage $disk */
$disk = Storage::disk('upload');
$set = $set->each(
static function (Attachment $attachment) use ($disk) {
$notes = $attachment->notes()->first();
$attachment->file_exists = $disk->exists($attachment->fileName());
$attachment->notes = $notes ? $notes->text : '';
return $attachment;
}
);
return $set;
}
public function getMaxOrder(): int
{
return (int)$this->user->budgets()->max('order');
}
}

View File

@@ -58,6 +58,11 @@ interface BudgetRepositoryInterface
*/
public function destroyAutoBudget(Budget $budget): void;
/**
* @return int
*/
public function getMaxOrder(): int;
/**
* @return bool

View File

@@ -26,6 +26,7 @@ use Carbon\Carbon;
use DB;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\CategoryFactory;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Category;
use FireflyIII\Models\RecurrenceTransactionMeta;
use FireflyIII\Models\RuleAction;
@@ -34,6 +35,7 @@ use FireflyIII\Services\Internal\Update\CategoryUpdateService;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
use Storage;
/**
* Class CategoryRepository.
@@ -380,6 +382,21 @@ class CategoryRepository implements CategoryRepositoryInterface
*/
public function getAttachments(Category $category): Collection
{
return $category->attachments()->get();
$set = $category->attachments()->get();
/** @var Storage $disk */
$disk = Storage::disk('upload');
$set = $set->each(
static function (Attachment $attachment) use ($disk) {
$notes = $attachment->notes()->first();
$attachment->file_exists = $disk->exists($attachment->fileName());
$attachment->notes = $notes ? $notes->text : '';
return $attachment;
}
);
return $set;
}
}

View File

@@ -384,7 +384,7 @@ class ImportJobRepository implements ImportJobRepositoryInterface
$attachment = new Attachment; // create Attachment object.
$attachment->user()->associate($job->user);
$attachment->attachable()->associate($job);
$attachment->md5 = md5($content);
$attachment->md5 = substr(hash('sha256', $content), 0, 32); // limit due to DB.
$attachment->filename = $name;
$attachment->mime = 'plain/txt';
$attachment->size = strlen($content);

View File

@@ -23,12 +23,14 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Journal;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
use Storage;
/**
* Class JournalAPIRepository
@@ -74,7 +76,22 @@ class JournalAPIRepository implements JournalAPIRepositoryInterface
*/
public function getAttachments(TransactionJournal $journal): Collection
{
return $journal->attachments;
$set = $journal->attachments;
/** @var Storage $disk */
$disk = Storage::disk('upload');
$set = $set->each(
static function (Attachment $attachment) use ($disk) {
$notes = $attachment->notes()->first();
$attachment->file_exists = $disk->exists($attachment->fileName());
$attachment->notes = $notes ? $notes->text : '';
return $attachment;
}
);
return $set;
}
/**

View File

@@ -407,4 +407,19 @@ class JournalRepository implements JournalRepositoryInterface
return $transaction->account;
}
/**
* @return TransactionJournal|null
*/
public function getLast(): ?TransactionJournal
{
/** @var TransactionJournal $entry */
$entry = $this->user->transactionJournals()->orderBy('date', 'DESC')->first(['transaction_journals.*']);
$result = null;
if (null !== $entry) {
$result = $entry;
}
return $result;
}
}

View File

@@ -37,6 +37,10 @@ use Illuminate\Support\Collection;
*/
interface JournalRepositoryInterface
{
/**
* @return TransactionJournal|null
*/
public function getLast(): ?TransactionJournal;
/**
* TODO maybe create JSON repository?
@@ -44,6 +48,7 @@ interface JournalRepositoryInterface
* Search in journal descriptions.
*
* @param string $search
*
* @return Collection
*/
public function searchJournalDescriptions(string $search): Collection;

View File

@@ -142,6 +142,9 @@ trait ModifiesPiggyBanks
*/
public function createEvent(PiggyBank $piggyBank, string $amount): PiggyBankEvent
{
if (0 === bccomp('0', $amount)) {
return new PiggyBankEvent;
}
/** @var PiggyBankEvent $event */
$event = PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
@@ -219,11 +222,12 @@ trait ModifiesPiggyBanks
if (1 === bccomp($amount, $max)) {
$amount = $max;
}
$difference = bcsub($amount, $repetition->currentamount);
$repetition->currentamount = $amount;
$repetition->save();
// create event
$this->createEvent($piggyBank, $amount);
$this->createEvent($piggyBank, $difference);
return $piggyBank;
}
@@ -343,4 +347,4 @@ trait ModifiesPiggyBanks
return true;
}
}
}

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Note;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
@@ -33,6 +34,7 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
use Storage;
/**
* Class PiggyBankRepository.
@@ -374,6 +376,21 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
*/
public function getAttachments(PiggyBank $piggyBank): Collection
{
return $piggyBank->attachments()->get();
$set = $piggyBank->attachments()->get();
/** @var Storage $disk */
$disk = Storage::disk('upload');
$set = $set->each(
static function (Attachment $attachment) use ($disk) {
$notes = $attachment->notes()->first();
$attachment->file_exists = $disk->exists($attachment->fileName());
$attachment->notes = $notes ? $notes->text : '';
return $attachment;
}
);
return $set;
}
}

View File

@@ -535,6 +535,31 @@ class RecurringRepository implements RecurringRepositoryInterface
// filter out all the weekend days:
$occurrences = $this->filterWeekends($repetition, $occurrences);
// filter out everything if "repeat_until" is set.
$repeatUntil = $repetition->recurrence->repeat_until;
$occurrences = $this->filterMaxDate($repeatUntil, $occurrences);
return $occurrences;
}
/**
* @param Carbon|null $max
* @param array $occurrences
*
* @return array
*/
private function filterMaxDate(?Carbon $max, array $occurrences): array
{
if (null === $max) {
return $occurrences;
}
$filtered = [];
foreach ($occurrences as $date) {
if ($date->lte($max)) {
$filtered[] = $date;
}
}
return $filtered;
}
}

View File

@@ -56,7 +56,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
}
/**
* @param RuleGroup $ruleGroup
* @param RuleGroup $ruleGroup
* @param RuleGroup|null $moveTo
*
* @return bool
@@ -92,12 +92,18 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
{
$this->user->ruleGroups()->whereNotNull('deleted_at')->update(['order' => 0]);
$set = $this->user->ruleGroups()->where('active', 1)->orderBy('order', 'ASC')->get();
$set = $this->user
->ruleGroups()
->orderBy('order', 'ASC')->get();
$count = 1;
/** @var RuleGroup $entry */
foreach ($set as $entry) {
$entry->order = $count;
$entry->save();
// also update rules in group.
$this->resetRulesInGroupOrder($entry);
++$count;
}
@@ -209,18 +215,16 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
public function getRuleGroupsWithRules(User $user): Collection
{
return $user->ruleGroups()
->orderBy('active', 'DESC')
->orderBy('order', 'ASC')
->with(
[
'rules' => function (HasMany $query) {
$query->orderBy('active', 'DESC');
'rules' => static function (HasMany $query) {
$query->orderBy('order', 'ASC');
},
'rules.ruleTriggers' => function (HasMany $query) {
'rules.ruleTriggers' => static function (HasMany $query) {
$query->orderBy('order', 'ASC');
},
'rules.ruleActions' => function (HasMany $query) {
'rules.ruleActions' => static function (HasMany $query) {
$query->orderBy('order', 'ASC');
},
]
@@ -328,7 +332,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
/**
* @param RuleGroup $ruleGroup
* @param array $data
* @param array $data
*
* @return RuleGroup
*/
@@ -353,4 +357,5 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
{
return $this->user->ruleGroups()->where('title', $title)->first();
}
}

View File

@@ -26,6 +26,7 @@ use Carbon\Carbon;
use DB;
use FireflyIII\Factory\TagFactory;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Location;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleTrigger;
@@ -34,6 +35,7 @@ use FireflyIII\Models\TransactionType;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
use Storage;
/**
* Class TagRepository.
@@ -549,7 +551,21 @@ class TagRepository implements TagRepositoryInterface
*/
public function getAttachments(Tag $tag): Collection
{
return $tag->attachments()->get();
$set= $tag->attachments()->get();
/** @var Storage $disk */
$disk = Storage::disk('upload');
$set = $set->each(
static function (Attachment $attachment) use ($disk) {
$notes = $attachment->notes()->first();
$attachment->file_exists = $disk->exists($attachment->fileName());
$attachment->notes = $notes ? $notes->text : '';
return $attachment;
}
);
return $set;
}
/**

View File

@@ -346,6 +346,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
Log::warning('Group repository caught group factory with a duplicate exception!');
throw new DuplicateTransactionException($e->getMessage());
} catch(FireflyException $e) {
Log::warning('Group repository caught group factory with an exception!');
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException($e->getMessage());

View File

@@ -95,8 +95,6 @@ class JournalDestroyService
// update events
$journal->piggyBankEvents()->update(['transaction_journal_id' => null]);
$journal->delete();
} catch (Exception $e) {
Log::error(sprintf('Could not delete bill: %s', $e->getMessage())); // @codeCoverageIgnore

View File

@@ -237,7 +237,6 @@ trait AccountServiceTrait
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
}
// @codeCoverageIgnoreEnd
return $group;

View File

@@ -112,8 +112,8 @@ trait JournalServiceTrait
$result = $this->findAccountById($data, $expectedTypes[$transactionType]);
$result = $this->findAccountByName($result, $data, $expectedTypes[$transactionType]);
$result = $this->findAccountByIban($result, $data, $expectedTypes[$transactionType]);
$result = $this->getCashAccount($result, $data, $expectedTypes[$transactionType]);
$result = $this->createAccount($result, $data, $expectedTypes[$transactionType][0]);
$result = $this->getCashAccount($result, $data, $expectedTypes[$transactionType]);
return $result;
}
@@ -301,7 +301,7 @@ trait JournalServiceTrait
{
// third attempt, find by IBAN
if (null === $account && null !== $data['iban']) {
Log::debug('Found nothing by account name.');
Log::debug(sprintf('Found nothing by account iban "%s".', $data['iban']));
// find by preferred type.
$source = $this->accountRepository->findByIbanNull($data['iban'], [$types[0]]);
// or any expected type.
@@ -345,22 +345,40 @@ trait JournalServiceTrait
*/
private function createAccount(?Account $account, array $data, string $preferredType): Account
{
Log::debug('Now in createAccount()', $data);
// return new account.
if (null !== $account) {
Log::debug(
sprintf(
'Was also given %s account #%d ("%s") so will simply return that.',
$account->accountType->type, $account->id, $account->name
)
);
}
if (null === $account) {
$data['name'] = $data['name'] ?? '(no name)';
// final attempt, create it.
if (AccountType::ASSET === $preferredType) {
throw new FireflyException('TransactionFactory: Cannot create asset account with these values', $data);
}
// fix name of account if only IBAN is given:
if ('' === (string) $data['name'] && '' !== (string) $data['iban']) {
Log::debug(sprintf('Account name is now IBAN ("%s")', $data['iban']));
$data['name'] = $data['iban'];
}
$data['name'] = $data['name'] ?? '(no name)';
$account = $this->accountRepository->store(
[
'account_type_id' => null,
'account_type' => $preferredType,
'name' => $data['name'],
'virtual_balance' => null,
'active' => true,
'iban' => $data['iban'],
'currency_id' => $data['currency_id'] ?? null,
]
);
// store BIC
@@ -375,6 +393,7 @@ trait JournalServiceTrait
$metaFactory = app(AccountMetaFactory::class);
$metaFactory->create(['account_id' => $account->id, 'name' => 'account_number', 'data' => $data['bic']]);
}
}
return $account;

View File

@@ -58,8 +58,11 @@ class PwndVerifierV2 implements Verifier
$rest = substr($hash, 5);
$uri = sprintf('https://api.pwnedpasswords.com/range/%s', $prefix);
$opt = [
'headers' => ['User-Agent' => 'Firefly III v' . config('firefly.version')],
'timeout' => 5];
'headers' => [
'User-Agent' => 'Firefly III v' . config('firefly.version'),
'Add-Padding' => 'true',
],
'timeout' => 3.1415];
Log::debug(sprintf('hash prefix is %s', $prefix));
Log::debug(sprintf('rest is %s', $rest));
@@ -87,7 +90,7 @@ class PwndVerifierV2 implements Verifier
return true;
}
Log::debug(sprintf('Could not find %s, return FALSE.', $rest));
Log::debug(sprintf('Found %s, return FALSE.', $rest));
return false;
}

View File

@@ -1,96 +0,0 @@
<?php
/**
* PwndVerifierV3.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Services\Password;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Log;
use RuntimeException;
/**
* Class PwndVerifierV3
* @codeCoverageIgnore
* @codeCoverageIgnore
* @deprecated
*/
class PwndVerifierV3 implements Verifier
{
/**
* Verify the given password against (some) service.
*
* @param string $password
*
* @return bool
*/
public function validPassword(string $password): bool
{
Log::debug('Now in API v3.');
$hash = strtoupper(sha1($password));
$prefix = substr($hash, 0, 5);
$rest = substr($hash, 5);
$uri = sprintf('https://api.pwnedpasswords.com/%s/%s', 'range', $prefix);
Log::debug(sprintf('URI is %s', $uri));
$headers = [
'User-Agent' => sprintf('Firefly III v%s', config('firefly.version')),
];
Log::debug('Headers', $headers);
$opts = [
'headers' => $headers,
'timeout' => 5,
];
Log::debug(sprintf('hash prefix is %s', $prefix));
Log::debug(sprintf('rest is %s', $rest));
try {
$client = new Client;
$res = $client->request('GET', $uri, $opts);
} catch (GuzzleException|Exception $e) {
Log::error(sprintf('Could not verify password security: %s', $e->getMessage()));
return true;
}
Log::debug(sprintf('Status code returned is %d', $res->getStatusCode()));
if (404 === $res->getStatusCode()) {
return true;
}
$body = $res->getBody()->getContents();
try {
$strpos = stripos($body, $rest);
} catch (RuntimeException $e) {
Log::error(sprintf('Could not get body from Pwnd result: %s', $e->getMessage()));
$strpos = false;
}
if (false === $strpos) {
Log::debug(sprintf('%s was not found in result body. Return true.', $rest));
return true;
}
Log::debug(sprintf('Found %s, so return FALSE.', $rest));
return false;
}
}

View File

@@ -325,9 +325,11 @@ class Amount
*/
public function getLocaleInfo(): array
{
$locale = explode(',', (string) trans('config.locale'));
$locale = array_map('trim', $locale);
setlocale(LC_MONETARY, $locale);
// get config from preference, not from translation:
$locale = app('steam')->getLocale();
$array = app('steam')->getLocaleArray($locale);
setlocale(LC_MONETARY, $array);
$info = localeconv();
// correct variables
$info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes');

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