Compare commits

...

96 Commits
5.2.0 ... 5.2.5

Author SHA1 Message Date
James Cole
7f8ed7abb6 Merge branch 'release/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
192 changed files with 4924 additions and 1338 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=
@@ -270,3 +270,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

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

@@ -165,7 +165,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

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

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

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

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

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
@@ -106,7 +105,6 @@ class IndexController extends Controller
$budgeted = '0';
$spent = '0';
// new period stuff:
$periodTitle = app('navigation')->periodShow($start, $range);
$prevLoop = $this->getPreviousPeriods($start, $range);

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

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

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

@@ -138,6 +138,7 @@ class TransactionController extends Controller
$collector->setTypes([TransactionType::DEPOSIT]);
break;
case 'transfers':
case 'transfer':
$collector->setTypes([TransactionType::TRANSFER]);
break;
}

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

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,11 @@ 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:
/** @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

@@ -110,8 +110,13 @@ 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;
$array['occurrences'] = [];
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'));

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

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

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

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

@@ -79,6 +79,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 +189,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 +204,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 +229,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 +279,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) {
@@ -487,4 +491,9 @@ class BudgetRepository implements BudgetRepositoryInterface
{
return $budget->attachments()->get();
}
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

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

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

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

View File

@@ -345,6 +345,7 @@ trait JournalServiceTrait
*/
private function createAccount(?Account $account, array $data, string $preferredType): Account
{
Log::debug('Now in createAccount()', $data);
// return new account.
if (null === $account) {
$data['name'] = $data['name'] ?? '(no name)';
@@ -359,8 +360,10 @@ trait JournalServiceTrait
'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 +378,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');

View File

@@ -101,8 +101,8 @@ class CacheProperties
{
$content = '';
foreach ($this->properties as $property) {
$content .= json_encode($property);
$content .= json_encode($property, JSON_THROW_ON_ERROR, 512);
}
$this->hash = substr(sha1($content), 0, 16);
$this->hash = substr(hash('sha256', $content), 0, 16);
}
}

View File

@@ -557,7 +557,7 @@ class ExportDataGenerator
$recurrence->description,
$recurrence->first_date ? $recurrence->first_date->format('Y-m-d') : null,
$recurrence->repeat_until ? $recurrence->repeat_until->format('Y-m-d') : null,
$recurrence->latest_date ? $recurrence->repeat_until->format('Y-m-d') : null,
$recurrence->latest_date ? $recurrence->latest_date->format('Y-m-d') : null,
$recurrence->repetitions,
$recurrence->apply_rules,
$recurrence->active,

View File

@@ -61,6 +61,7 @@ trait ChartGeneration
return $cache->get(); // @codeCoverageIgnore
}
Log::debug('Regenerate chart.account.account-balance-chart from scratch.');
$locale = app('steam')->getLocale();
/** @var GeneratorInterface $generator */
$generator = app(GeneratorInterface::class);
@@ -89,7 +90,7 @@ trait ChartGeneration
$previous = array_values($range)[0];
while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d');
$label = $currentStart->formatLocalized((string)trans('config.month_and_day'));
$label = $currentStart->formatLocalized((string)trans('config.month_and_day', [], $locale));
$balance = isset($range[$format]) ? round($range[$format], 12) : $previous;
$previous = $balance;
$currentStart->addDay();

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Support\Http\Controllers;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Cronjobs\AutoBudgetCronjob;
use FireflyIII\Support\Cronjobs\RecurringCronjob;
/**
@@ -50,4 +51,23 @@ trait CronRunner
return 'The recurring transaction cron job fired successfully.';
}
/**
* @return string
*/
protected function runAutoBudget(): string
{
/** @var AutoBudgetCronjob $autoBudget */
$autoBudget = app(AutoBudgetCronjob::class);
try {
$result = $autoBudget->fire();
} catch (FireflyException $e) {
return $e->getMessage();
}
if (false === $result) {
return 'The auto budget cron job did not fire.';
}
return 'The auto budget cron job fired successfully.';
}
}

View File

@@ -119,19 +119,6 @@ trait RequestInformation
return '<p>' . trans('firefly.route_has_no_help') . '</p>'; // @codeCoverageIgnore
}
/**
* Get user's language.
*
* @return string
*/
protected function getLanguage(): string // get preference
{
/** @var string $language */
$language = app('preferences')->get('language', config('firefly.default_language', 'en_US'))->data;
return $language;
}
/**
* Get a list of triggers.
*
@@ -300,7 +287,7 @@ trait RequestInformation
$data,
[
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|secure_password|confirmed',
'password' => 'required|string|min:16|secure_password|confirmed',
]
);
}

View File

@@ -183,30 +183,30 @@ class StageImportDataHandler
// transaction data:
'transactions' => [
[
'date' => $transaction->getMadeOn()->format('Y-m-d'),
'tags' => $tags,
'user' => $this->importJob->user_id,
'notes' => $notes,
'date' => $transaction->getMadeOn()->format('Y-m-d'),
'tags' => $tags,
'user' => $this->importJob->user_id,
'notes' => trim($notes),
// all custom fields:
'external_id' => (string)$transaction->getId(),
'external_id' => (string)$transaction->getId(),
// journal data:
'description' => $transaction->getDescription(),
'piggy_bank_id' => null,
'piggy_bank_name' => null,
'bill_id' => null,
'bill_name' => null,
'original-source' => sprintf('spectre-v%s', config('firefly.version')),
'type' => $type,
'currency_id' => null,
'currency_code' => $currencyCode,
'amount' => $amount,
'budget_id' => null,
'budget_name' => null,
'category_id' => null,
'category_name' => $transaction->getCategory(),
'source_id' => $source->id,
'description' => $transaction->getDescription(),
'piggy_bank_id' => null,
'piggy_bank_name' => null,
'bill_id' => null,
'bill_name' => null,
'original-source' => sprintf('spectre-v%s', config('firefly.version')),
'type' => $type,
'currency_id' => null,
'currency_code' => $currencyCode,
'amount' => $amount,
'budget_id' => null,
'budget_name' => null,
'category_id' => null,
'category_name' => $transaction->getCategory(),
'source_id' => $source->id,
'source_name' => null,
'destination_id' => $destination->id,
'destination_name' => null,

View File

@@ -287,10 +287,11 @@ class Navigation
*/
public function listOfPeriods(Carbon $start, Carbon $end): array
{
$locale = app('steam')->getLocale();
// define period to increment
$increment = 'addDay';
$format = $this->preferredCarbonFormat($start, $end);
$displayFormat = (string)trans('config.month_and_day');
$displayFormat = (string)trans('config.month_and_day', [], $locale);
// increment by month (for year)
if ($start->diffInMonths($end) > 1) {
$increment = 'addMonth';
@@ -391,13 +392,14 @@ class Navigation
*/
public function preferredCarbonLocalizedFormat(Carbon $start, Carbon $end): string
{
$format = (string)trans('config.month_and_day');
$locale = app('steam')->getLocale();
$format = (string)trans('config.month_and_day', [], $locale);
if ($start->diffInMonths($end) > 1) {
$format = (string)trans('config.month');
$format = (string)trans('config.month', [], $locale);
}
if ($start->diffInMonths($end) > 12) {
$format = (string)trans('config.year');
$format = (string)trans('config.year', [], $locale);
}
return $format;

View File

@@ -26,7 +26,6 @@ use Cache;
use Exception;
use FireflyIII\Models\Preference;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
use Log;
use Session;
@@ -200,7 +199,7 @@ class Preferences
$lastActivity = implode(',', $lastActivity);
}
return md5($lastActivity);
return hash('sha256', $lastActivity);
}
/**

View File

@@ -70,11 +70,10 @@ class Steam
->where('transactions.transaction_currency_id', $currency->id)
->get(['transactions.amount'])->toArray();
$nativeBalance = $this->sumTransactions($transactions, 'amount');
// get all balances in foreign currency:
$transactions = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d'))
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.foreign_currency_id', $currency->id)
->where('transactions.transaction_currency_id', '!=', $currency->id)
->get(['transactions.foreign_amount'])->toArray();
@@ -585,4 +584,42 @@ class Steam
return $amount;
}
/**
* Get user's language.
*
* @return string
*/
public function getLanguage(): string // get preference
{
return app('preferences')->get('language', config('firefly.default_language', 'en_US'))->data;
}
/**
* Get user's locale.
*
* @return string
*/
public function getLocale(): string // get preference
{
/** @var string $language */
$locale = app('preferences')->get('locale', config('firefly.default_locale', 'equal'))->data;
if ('equal' === $locale) {
return $this->getLanguage();
}
return $locale;
}
/**
* @param string $locale
*
* @return array
*/
public function getLocaleArray(string $locale): array {
return [
sprintf('%s.utf8', $locale),
sprintf('%s.UTF-8', $locale),
];
}
}

View File

@@ -73,7 +73,7 @@ class SetSourceAccount implements ActionInterface
$type = $journal->transactionType->type;
// if this is a transfer or a withdrawal, the new source account must be an asset account or a default account, and it MUST exist:
if ((TransactionType::WITHDRAWAL === $type || TransactionType::TRANSFER === $type) && !$this->findAssetAccount()) {
if ((TransactionType::WITHDRAWAL === $type || TransactionType::TRANSFER === $type) && !$this->findAssetAccount($type)) {
Log::error(
sprintf(
'Cannot change source account of journal #%d because no asset account with name "%s" exists.',
@@ -119,6 +119,10 @@ class SetSourceAccount implements ActionInterface
{
// switch on type:
$allowed = config(sprintf('firefly.expected_source_types.source.%s', $type));
$allowed = is_array($allowed) ? $allowed : [];
Log::debug(sprintf('Check config for expected_source_types.source.%s, result is', $type), $allowed);
$account = $this->repository->findByName($this->action->action_value, $allowed);
if (null === $account) {

View File

@@ -73,8 +73,8 @@ trait TransactionValidation
// validate source account.
$sourceId = isset($transaction['source_id']) ? (int) $transaction['source_id'] : null;
$sourceName = $transaction['source_name'] ?? null;
$sourceIban = $transaction['source_iban'] ?? null;
$sourceName = isset($transaction['source_name']) ? (string) $transaction['source_name'] : null;
$sourceIban = isset($transaction['source_iban']) ? (string) $transaction['source_iban'] : null;
$validSource = $accountValidator->validateSource($sourceId, $sourceName, $sourceIban);
// do something with result:
@@ -86,8 +86,8 @@ trait TransactionValidation
}
// validate destination account
$destinationId = isset($transaction['destination_id']) ? (int) $transaction['destination_id'] : null;
$destinationName = $transaction['destination_name'] ?? null;
$destinationIban = $transaction['destination_iban'] ?? null;
$destinationName = isset($transaction['destination_name']) ? (string) $transaction['destination_name'] : null;
$destinationIban = isset($transaction['destination_iban']) ? (string) $transaction['destination_iban'] : null;
$validDestination = $accountValidator->validateDestination($destinationId, $destinationName, $destinationIban);
// do something with result:
if (false === $validDestination) {

View File

@@ -2,8 +2,59 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [5.2.5 (API 1.1.0)] - 2020-05-04
## [5.2.0 (API 1.1.0)] - 2020-04-11
### Added
- Some warnings that custom locales may not work on Windows or in Docker images.
### Changed
- [Issue 3305](https://github.com/firefly-iii/firefly-iii/issues/3305) User [@lguima](https://github.com/lguima) revamped the left side menu and associated icons.
### Fixed
- [Issue 3307](https://github.com/firefly-iii/firefly-iii/issues/3307) Editing or creating accounts would automatically give them a location.
- [Issue 3314](https://github.com/firefly-iii/firefly-iii/issues/3314) Future transactions would not always be visible, even when the daterange should include them.
- [Issue 3318](https://github.com/firefly-iii/firefly-iii/issues/3318) Cron called over URL would skip auto-budgets.
- [Issue 3321](https://github.com/firefly-iii/firefly-iii/issues/3321) API for piggy bank funds would create events with the wrong amount.
- [Issue 3330](https://github.com/firefly-iii/firefly-iii/issues/3330) Transactions not stored at 00:00 would be excluded from some views.
## [5.2.4 (API 1.1.0)] - 2020-04-26
### Fixed
- [Issue 3287](https://github.com/firefly-iii/firefly-iii/issues/3287) Locale issue
- [Issue 3251](https://github.com/firefly-iii/firefly-iii/issues/3251) Budget order
## [5.2.3 (API 1.1.0)] - 2020-04-22
### Added
- Support for British English! 🇬🇧
- You can set your locale *and* your language now.
### Changed
- [Issue 3270](https://github.com/firefly-iii/firefly-iii/issues/3270) Wrong average in budget table.
### Fixed
- [Issue 3264](https://github.com/firefly-iii/firefly-iii/issues/3264) Error when exporting recurring transactions
- [Issue 3272](https://github.com/firefly-iii/firefly-iii/issues/3272) Rule issue when using "set source account" action.
- [Issue 3281](https://github.com/firefly-iii/firefly-iii/issues/3281) Bad markdown parsing in piggy banks.
- [Issue 3284](https://github.com/firefly-iii/firefly-iii/issues/3284) Recurring transactions with bad info couldn't be rendered.
## [5.2.2 (API 1.1.0)] - 2020-04-14
### Fixed
- [Issue 3529](https://github.com/firefly-iii/firefly-iii/issues/3529) Issue with rule execution.
- [Issue 3263](https://github.com/firefly-iii/firefly-iii/issues/3263) Issue with new user account creation.
## [5.2.2 (API 1.1.0)] - 2020-04-13
### Fixed
- Virtual balance would always be stored as "0.0" despite the field being nullable.
- The rule action "set source account" was improperly configured.
## [5.2.1 (API 1.1.0)] - 2020-04-10
Firefly III 5.2.1 fixes an issue with charts and allows users to store budgets again.
## [5.2.0 (API 1.1.0)] - 2020-04-10
- ⚠️ This will be the last version to support PHP version 7.3. The next release will require PHP **7.4**
- ⚠️ The bunq and CSV import routines have been disabled and replaced by their stand alone variants: [bunq](https://github.com/firefly-iii/bunq-importer), [CSV](https://github.com/firefly-iii/csv-importer).

562
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -138,7 +138,7 @@ return [
],
'encryption' => null === env('USE_ENCRYPTION') || true === env('USE_ENCRYPTION'),
'version' => '5.2.0',
'version' => '5.2.5',
'api_version' => '1.1.0',
'db_version' => 13,
'maxUploadSize' => 15242880,
@@ -323,7 +323,8 @@ return [
*/
'languages' => [
// currently enabled languages
'en_US' => ['name_locale' => 'English', 'name_english' => 'English'],
'en_US' => ['name_locale' => 'English (US)', 'name_english' => 'English (US)'],
'en_GB' => ['name_locale' => 'English (GB)', 'name_english' => 'English (GB)'],
'cs_CZ' => ['name_locale' => 'Czech', 'name_english' => 'Czech'],
'el_GR' => ['name_locale' => 'Ελληνικά', 'name_english' => 'Greek'],
'es_ES' => ['name_locale' => 'Español', 'name_english' => 'Spanish'],
@@ -382,7 +383,7 @@ return [
'Opening balance' => 'opening-balance',
'Reconciliation' => 'reconciliation',
],
'transactionIconsByWhat' => [
'transactionIconsByType' => [
'expenses' => 'fa-long-arrow-left',
'withdrawal' => 'fa-long-arrow-left',
'revenue' => 'fa-long-arrow-right',
@@ -557,6 +558,7 @@ return [
],
'default_currency' => 'EUR',
'default_language' => envNonEmpty('DEFAULT_LANGUAGE', 'en_US'),
'default_locale' => envNonEmpty('DEFAULT_LOCALE', 'equal'),
'search_modifiers' => ['amount_is', 'amount', 'amount_max', 'amount_min', 'amount_less', 'amount_more', 'source', 'destination', 'category',
'budget', 'bill', 'type', 'date', 'date_before', 'date_after', 'on', 'before', 'after', 'from', 'to', 'tag', 'created_on',
'updated_on',],

View File

@@ -30,7 +30,7 @@ $factory->define(
'user_id' => 1,
'attachable_id' => 1,
'attachable_type' => TransactionJournal::class,
'md5' => md5($faker->words(6, true)),
'md5' => substr(hash('sha256', $faker->words(6, true)), 0, 32),
'mime' => 'text/plain',
'size' => 1,
'filename' => 'ok',

View File

@@ -133,7 +133,7 @@ class CreateMainTables extends Migration
$table->integer('user_id', false, true);
$table->integer('attachable_id', false, true);
$table->string('attachable_type', 255);
$table->string('md5', 32);
$table->string('md5', 128);
$table->string('filename', 1024);
$table->string('title', 1024)->nullable();
$table->text('description')->nullable();

2
public/v1/js/app.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -5,18 +5,18 @@
*/
/*!
* Sizzle CSS Selector Engine v2.3.4
* Sizzle CSS Selector Engine v2.3.5
* https://sizzlejs.com/
*
* Copyright JS Foundation and other contributors
* Released under the MIT license
* https://js.foundation/
*
* Date: 2019-04-08
* Date: 2020-03-14
*/
/*!
* jQuery JavaScript Library v3.4.1
* jQuery JavaScript Library v3.5.0
* https://jquery.com/
*
* Includes Sizzle.js
@@ -26,5 +26,5 @@
* Released under the MIT license
* https://jquery.org/license
*
* Date: 2019-05-01T21:04Z
* Date: 2020-04-10T15:07Z
*/

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -84,10 +84,10 @@ $(function () {
dragging: false
}).setView([latitude, longitude], zoomLevel);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
maxZoom: 18,
id: 'mapbox.streets',
id: 'mapbox/streets-v11',
accessToken: mapboxToken
}).addTo(mymap);
L.marker([latitude, longitude]).addTo(mymap);

View File

@@ -40,10 +40,10 @@ $(function () {
dragging: false
}).setView([latitude, longitude], zoomLevel);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
maxZoom: 18,
id: 'mapbox.streets',
id: 'mapbox/streets-v11',
accessToken: mapboxToken
}).addTo(mymap);
L.marker([latitude, longitude]).addTo(mymap);

File diff suppressed because one or more lines are too long

View File

@@ -20,17 +20,18 @@
<template>
<div>
<table class="table table-hover sortable">
<caption>Bills table</caption>
<thead>
<tr>
<th class="hidden-sm hidden-xs" data-defaultsort="disabled">&nbsp;</th>
<th>{{ 'list.name' | trans }}</th>
<th data-defaultsign="az" class="hidden-sm hidden-md hidden-xs">{{ 'list.matchesOn' | trans }}</th>
<th data-defaultsign="_19" colspan="2">{{ 'list.amount' | trans }}</th>
<th data-defaultsign="month" class="hidden-sm hidden-xs">{{ 'list.paid_current_period' | trans }}</th>
<th data-defaultsign="month" class="hidden-sm hidden-xs">{{ 'list.next_expected_match' | trans }}</th>
<th class="hidden-sm hidden-xs hidden-md">{{ 'list.active' | trans }}</th>
<th class="hidden-sm hidden-xs hidden-md">{{ 'list.automatch' | trans }}</th>
<th data-defaultsign="az" class="hidden-sm hidden-xs">{{ 'list.repeat_freq' | trans }}</th>
<th scope="col" class="hidden-sm hidden-xs" data-defaultsort="disabled">&nbsp;</th>
<th scope="col">{{ 'list.name' | trans }}</th>
<th scope="col"data-defaultsign="az" class="hidden-sm hidden-md hidden-xs">{{ 'list.matchesOn' | trans }}</th>
<th scope="col" data-defaultsign="_19" colspan="2">{{ 'list.amount' | trans }}</th>
<th scope="col" data-defaultsign="month" class="hidden-sm hidden-xs">{{ 'list.paid_current_period' | trans }}</th>
<th scope="col" data-defaultsign="month" class="hidden-sm hidden-xs">{{ 'list.next_expected_match' | trans }}</th>
<th scope="col" class="hidden-sm hidden-xs hidden-md">{{ 'list.active' | trans }}</th>
<th scope="col" class="hidden-sm hidden-xs hidden-md">{{ 'list.automatch' | trans }}</th>
<th scope="col" data-defaultsign="az" class="hidden-sm hidden-xs">{{ 'list.repeat_freq' | trans }}</th>
</tr>
</thead>
<tbody>

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