mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-08-22 05:09:43 +00:00
Compare commits
59 Commits
5.2.0-beta
...
5.2.4
Author | SHA1 | Date | |
---|---|---|---|
|
e6442dd8af | ||
|
7905e0bd70 | ||
|
f4b1da352d | ||
|
0d33348941 | ||
|
c7c875e95f | ||
|
19d24b3e2a | ||
|
8fed6b6657 | ||
|
b5eafa1910 | ||
|
c15501937f | ||
|
4c743bd5b0 | ||
|
44289cbd95 | ||
|
b2f1642cfe | ||
|
341ef0220c | ||
|
9df88115bc | ||
|
c7273edb5e | ||
|
c398aa2b69 | ||
|
aa786eaaf3 | ||
|
e58a5e12d6 | ||
|
12b3575c5c | ||
|
3ca186dc8f | ||
|
1535f596f6 | ||
|
2cc326caa1 | ||
|
43436ae942 | ||
|
fbfd8475de | ||
|
405752f353 | ||
|
2af98b259a | ||
|
015242a666 | ||
|
54933fda2e | ||
|
852d057a47 | ||
|
1778f0b4f3 | ||
|
6daf083b3f | ||
|
4a7d9b130a | ||
|
4163efba55 | ||
|
db5847b49b | ||
|
6829003f5e | ||
|
047927718e | ||
|
91deb22a3f | ||
|
1629ca0739 | ||
|
8b87204f10 | ||
|
f920d90e3d | ||
|
1cb91282af | ||
|
a6ce294131 | ||
|
34ceb69776 | ||
|
eed68b5d95 | ||
|
79374c11ee | ||
|
404f9df6d3 | ||
|
4b716e35b9 | ||
|
166fc7a3e2 | ||
|
06afbc7a0a | ||
|
49a98de63a | ||
|
5b572c0da2 | ||
|
59014b1a87 | ||
|
4aec1f06e0 | ||
|
136af9625a | ||
|
edac26f757 | ||
|
ac54dd05bf | ||
|
7948058364 | ||
|
f13a6f7bf9 | ||
|
e1a5d143c5 |
@@ -22,6 +22,10 @@ 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
|
||||
|
12
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
12
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -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 ;)-->
|
||||
|
10
.github/ISSUE_TEMPLATE/Custom.md
vendored
10
.github/ISSUE_TEMPLATE/Custom.md
vendored
@@ -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
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
/node_modules
|
||||
/frontend/node_modules
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* CorrectOpeningBalanceCurrencies.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* FixLongDescriptions.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -65,7 +66,7 @@ class FixLongDescriptions extends Command
|
||||
$groups = TransactionGroup::get(['id', 'title']);
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($groups as $group) {
|
||||
if (strlen($group->title) > self::MAX_LENGTH) {
|
||||
if (strlen((string)$group->title) > self::MAX_LENGTH) {
|
||||
$group->title = substr($group->title, 0, self::MAX_LENGTH);
|
||||
$group->save();
|
||||
$this->line(sprintf('Truncated description of transaction group #%d', $group->id));
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* FixRecurringTransactions.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* ExportData.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* RestoreOAuthKeys.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* MigrateRecurrenceMeta.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* MigrateTagLocations.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* DuplicateTransactionException.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -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);
|
||||
|
@@ -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) {
|
||||
|
@@ -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,
|
||||
];
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* TelemetryController.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
|
@@ -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);
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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);
|
||||
|
@@ -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,
|
||||
|
@@ -450,8 +450,6 @@ class TagReportController extends Controller
|
||||
$data = $this->generator->multiCurrencyPieChart($result);
|
||||
|
||||
return response()->json($data);
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* TransactionController.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
@@ -137,6 +138,7 @@ class TransactionController extends Controller
|
||||
$collector->setTypes([TransactionType::DEPOSIT]);
|
||||
break;
|
||||
case 'transfers':
|
||||
case 'transfer':
|
||||
$collector->setTypes([TransactionType::TRANSFER]);
|
||||
break;
|
||||
}
|
||||
@@ -204,6 +206,7 @@ class TransactionController extends Controller
|
||||
$collector->setTypes([TransactionType::DEPOSIT]);
|
||||
break;
|
||||
case 'transfers':
|
||||
case 'transfer':
|
||||
$collector->setTypes([TransactionType::TRANSFER]);
|
||||
break;
|
||||
}
|
||||
@@ -270,6 +273,7 @@ class TransactionController extends Controller
|
||||
$collector->setTypes([TransactionType::DEPOSIT]);
|
||||
break;
|
||||
case 'transfers':
|
||||
case 'transfer':
|
||||
$collector->setTypes([TransactionType::TRANSFER]);
|
||||
break;
|
||||
}
|
||||
|
@@ -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());
|
||||
|
@@ -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',
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* IndexController.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -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,
|
||||
|
@@ -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)) {
|
||||
|
@@ -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]),
|
||||
|
@@ -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:
|
||||
|
@@ -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 = [
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* DataController.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -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;
|
||||
|
@@ -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'));
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -108,6 +108,7 @@ class ShowController extends Controller
|
||||
if (!Str::contains($transaction['notes'], $search)) {
|
||||
$groupArray['transactions'][$index]['notes'] = e($transaction['notes']);
|
||||
}
|
||||
$groupArray['transactions'][$index]['tags'] = $this->repository->getTagObjects($groupArray['transactions'][$index]['transaction_journal_id']);
|
||||
}
|
||||
|
||||
$events = $this->repository->getPiggyEvents($transactionGroup);
|
||||
|
@@ -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);
|
||||
|
@@ -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',
|
||||
];
|
||||
|
@@ -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',
|
||||
];
|
||||
|
@@ -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'),
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -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',
|
||||
];
|
||||
}
|
||||
|
@@ -252,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* AutoBudget.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
|
@@ -89,6 +89,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property-read int|null $attachments_count
|
||||
* @property-read int|null $notes_count
|
||||
* @property-read int|null $transaction_journals_count
|
||||
* @property bool $name_encrypted
|
||||
* @property bool $match_encrypted
|
||||
*/
|
||||
class Bill extends Model
|
||||
{
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -70,6 +70,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property-read int|null $attachments_count
|
||||
* @property-read int|null $transaction_journals_count
|
||||
* @property-read int|null $transactions_count
|
||||
* @property bool $encrypted
|
||||
*/
|
||||
class Category extends Model
|
||||
{
|
||||
|
@@ -35,8 +35,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
/**
|
||||
* Class ImportJob.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @deprecated
|
||||
* @codeCoverageIgnore
|
||||
* @deprecated
|
||||
* @property array $transactions
|
||||
* @property array $configuration
|
||||
* @property User $user
|
||||
@@ -73,6 +73,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @method static Builder|ImportJob whereUserId($value)
|
||||
* @mixin Eloquent
|
||||
* @property-read int|null $attachments_count
|
||||
* @property int $id
|
||||
* @property array|null $extended_status
|
||||
*/
|
||||
class ImportJob extends Model
|
||||
{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* Location.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -51,6 +51,10 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
* @method static Builder|PiggyBankEvent whereTransactionJournalId($value)
|
||||
* @method static Builder|PiggyBankEvent whereUpdatedAt($value)
|
||||
* @mixin Eloquent
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon $date
|
||||
* @property-read \FireflyIII\Models\TransactionJournal|null $transactionJournal
|
||||
*/
|
||||
class PiggyBankEvent extends Model
|
||||
{
|
||||
|
@@ -50,6 +50,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @method static Builder|Preference whereUpdatedAt($value)
|
||||
* @method static Builder|Preference whereUserId($value)
|
||||
* @mixin Eloquent
|
||||
* @property-read \FireflyIII\User $user
|
||||
*/
|
||||
class Preference extends Model
|
||||
{
|
||||
|
@@ -76,6 +76,7 @@ use Illuminate\Support\Collection;
|
||||
* @method static Builder|RecurrenceTransaction withoutTrashed()
|
||||
* @mixin Eloquent
|
||||
* @property-read int|null $recurrence_transaction_meta_count
|
||||
* @property int $transaction_currency_id
|
||||
*/
|
||||
class RecurrenceTransaction extends Model
|
||||
{
|
||||
|
@@ -69,6 +69,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @mixin Eloquent
|
||||
* @property-read int|null $rules_count
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|RuleGroup whereStopProcessing($value)
|
||||
* @property string|null $description
|
||||
*/
|
||||
class RuleGroup extends Model
|
||||
{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* Telemetry.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
|
@@ -132,6 +132,9 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @mixin Eloquent
|
||||
* @property-read int|null $budgets_count
|
||||
* @property-read int|null $categories_count
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property bool $reconciled
|
||||
*/
|
||||
class Transaction extends Model
|
||||
{
|
||||
|
@@ -67,6 +67,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property-read int|null $budget_limits_count
|
||||
* @property-read int|null $transaction_journals_count
|
||||
* @property-read int|null $transactions_count
|
||||
* @property string $name
|
||||
*/
|
||||
class TransactionCurrency extends Model
|
||||
{
|
||||
|
@@ -121,6 +121,18 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property-read int|null $transaction_journal_meta_count
|
||||
* @property-read int|null $transactions_count
|
||||
* @method static EloquentBuilder|TransactionJournal whereTransactionGroupId($value)
|
||||
* @property int $user_id
|
||||
* @property int|null $transaction_group_id
|
||||
* @property int|null $transaction_currency_id
|
||||
* @property \Illuminate\Support\Carbon|null $interest_date
|
||||
* @property \Illuminate\Support\Carbon|null $book_date
|
||||
* @property \Illuminate\Support\Carbon|null $process_date
|
||||
* @property int $order
|
||||
* @property bool $encrypted
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Budget[] $budgets
|
||||
* @property-read \FireflyIII\Models\TransactionGroup|null $transactionGroup
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournalMeta[] $transactionJournalMeta
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Transaction[] $transactions
|
||||
*/
|
||||
class TransactionJournal extends Model
|
||||
{
|
||||
|
@@ -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);
|
||||
|
@@ -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');
|
||||
}
|
||||
}
|
||||
|
@@ -58,6 +58,11 @@ interface BudgetRepositoryInterface
|
||||
*/
|
||||
public function destroyAutoBudget(Budget $budget): void;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxOrder(): int;
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
|
@@ -267,6 +267,7 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
{
|
||||
/** @var CategoryUpdateService $service */
|
||||
$service = app(CategoryUpdateService::class);
|
||||
$service->setUser($this->user);
|
||||
|
||||
return $service->update($category, $data);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -45,6 +45,7 @@ use FireflyIII\Services\Internal\Update\GroupUpdateService;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
@@ -468,4 +469,15 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getTagObjects(int $journalId): Collection
|
||||
{
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $this->user->transactionJournals()->find($journalId);
|
||||
|
||||
return $journal->tags()->get();
|
||||
}
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface TransactionGroupRepositoryInterface
|
||||
@@ -122,6 +123,15 @@ interface TransactionGroupRepositoryInterface
|
||||
*/
|
||||
public function getTags(int $journalId): array;
|
||||
|
||||
/**
|
||||
* Get the tags for a journal (by ID) as Tag objects.
|
||||
*
|
||||
* @param int $journalId
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getTagObjects(int $journalId): Collection;
|
||||
|
||||
/**
|
||||
* Set the user.
|
||||
*
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* IsTransferAccount.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* LessThanPiggyTarget.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* UpdateRequest.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* UpdateRequestInterface.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -237,7 +237,6 @@ trait AccountServiceTrait
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $group;
|
||||
|
@@ -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,22 +360,25 @@ 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
|
||||
if (null !== $data['bic']) {
|
||||
/** @var AccountMetaFactory $metaFactory */
|
||||
$metaFactory = app(AccountMetaFactory::class);
|
||||
$metaFactory->create(['account_id' => $result->id, 'name' => 'BIC', 'data' => $data['bic']]);
|
||||
$metaFactory->create(['account_id' => $account->id, 'name' => 'BIC', 'data' => $data['bic']]);
|
||||
}
|
||||
// store account number
|
||||
if (null !== $data['number']) {
|
||||
/** @var AccountMetaFactory $metaFactory */
|
||||
$metaFactory = app(AccountMetaFactory::class);
|
||||
$metaFactory->create(['account_id' => $result->id, 'name' => 'account_number', 'data' => $data['bic']]);
|
||||
$metaFactory->create(['account_id' => $account->id, 'name' => 'account_number', 'data' => $data['bic']]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $account;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* LocationServiceTrait.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -35,6 +35,9 @@ use Log;
|
||||
*/
|
||||
class CategoryUpdateService
|
||||
{
|
||||
private $user;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -43,6 +46,9 @@ class CategoryUpdateService
|
||||
if ('testing' === config('app.env')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
|
||||
}
|
||||
if(auth()->check()) {
|
||||
$this->user = auth()->user();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,4 +112,12 @@ class CategoryUpdateService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $user
|
||||
*/
|
||||
public function setUser($user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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');
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* AutoBudgetCronjob.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* ExportDataGenerator.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
@@ -556,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,
|
||||
@@ -659,7 +660,7 @@ class ExportDataGenerator
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user);
|
||||
$collector->setRange($this->start, $this->end)->withAccountInformation()->withCategoryInformation()->withBillInformation()
|
||||
->withBudgetInformation();
|
||||
->withBudgetInformation()->withTagInformation();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
|
||||
$records = [];
|
||||
@@ -689,8 +690,9 @@ class ExportDataGenerator
|
||||
$journal['category_name'],
|
||||
$journal['budget_name'],
|
||||
$journal['bill_name'],
|
||||
implode(',', $journal['tags']),
|
||||
$this->mergeTags($journal['tags']),
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
//load the CSV document from a string
|
||||
@@ -705,4 +707,22 @@ class ExportDataGenerator
|
||||
return $csv->getContent(); //returns the CSV document as a string
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $tags
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function mergeTags(array $tags): string
|
||||
{
|
||||
if (0 === count($tags)) {
|
||||
return '';
|
||||
}
|
||||
$smol = [];
|
||||
foreach ($tags as $tag) {
|
||||
$smol[] = $tag['name'];
|
||||
}
|
||||
|
||||
return implode(',', $smol);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -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',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@@ -171,6 +171,9 @@ class StageImportDataHandler
|
||||
$foreignCurrencyCode = $value;
|
||||
Log::debug(sprintf('Foreign currency code is now %s', $value));
|
||||
break;
|
||||
case 'time':
|
||||
// ignore time because it breaks the duplicate detector.
|
||||
break;
|
||||
default:
|
||||
$notes .= $key . ': ' . $value . ' ' . "\n"; // for newline in Markdown.
|
||||
}
|
||||
@@ -180,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,
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* AccountSearch.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* GenericSearchInterface.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* TransactionSearch.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* TransferSearch.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -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),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* OAuthKeys.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* Telemetry.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
|
@@ -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) {
|
||||
|
@@ -138,6 +138,10 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property-read int|null $transactions_count
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\User whereMfaSecret($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\User whereObjectguid($value)
|
||||
* @property string $password
|
||||
* @property bool $blocked
|
||||
* @property string|null $blocked_code
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Role[] $roles
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
|
@@ -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) {
|
||||
|
49
changelog.md
49
changelog.md
@@ -2,8 +2,47 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [5.2.4 (API 1.1.0)] - 2020-04-26
|
||||
|
||||
## [5.2.0 (API 1.1.0)] - 2020-xx-xx
|
||||
### 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).
|
||||
|
||||
This release was preceded by a number of test versions:
|
||||
|
||||
@@ -28,6 +67,7 @@ This release was preceded by a number of test versions:
|
||||
- [Issue 2997](https://github.com/firefly-iii/firefly-iii/issues/2997) The tag list has categories.
|
||||
- [Issue 3122](https://github.com/firefly-iii/firefly-iii/issues/3122) Buttons on the top of lists.
|
||||
- The Docker maximum file attachment size has been increased to 64M.
|
||||
- The CSV file importer has been disabled. Find the [new CSV importer on GitHub](https://github.com/firefly-iii/csv-importer).
|
||||
|
||||
### Fixed
|
||||
- [Issue 3154](https://github.com/firefly-iii/firefly-iii/issues/3154) `bcadd()` problems for users who were already running PHP7.4.
|
||||
@@ -36,13 +76,14 @@ This release was preceded by a number of test versions:
|
||||
- [Issue 3202](https://github.com/firefly-iii/firefly-iii/issues/3202) A bug in the frontpage budget chart is fixed.
|
||||
- [Issue 3203](https://github.com/firefly-iii/firefly-iii/issues/3203) Firefly III won't complain when using a locale that uses comma's as decimal separators.
|
||||
- [Issue 3212](https://github.com/firefly-iii/firefly-iii/issues/3212) Issue with ING imports.
|
||||
- [Issue 3210](https://github.com/firefly-iii/firefly-iii/issues/3210) Could not create rule based on a transaction from a dropdown menu.
|
||||
- [Issue 3210](https://github.com/firefly-iii/firefly-iii/issues/3210) Could not create rule based on a transaction from a dropdown menu.
|
||||
- [Issue 3234](https://github.com/firefly-iii/firefly-iii/issues/3234) Export didn't export tags.
|
||||
|
||||
### API
|
||||
- [Issue 2828](https://github.com/firefly-iii/firefly-iii/issues/2828) Appropriate endpoints for new transaction possibilities.
|
||||
- [Issue 2958](https://github.com/firefly-iii/firefly-iii/issues/2958) A new default currency endpoint.
|
||||
|
||||
## [5.1.1 (API 1.0.2)] - 2020-03-xx
|
||||
## [5.1.1 (API 1.0.2)] - 2020-03-13
|
||||
|
||||
### Added
|
||||
- [Issue 2672](https://github.com/firefly-iii/firefly-iii/issues/2672) Buttons to create transactions from the list of accounts is back.
|
||||
@@ -2214,4 +2255,4 @@ An intermediate release because something in the Twig and Twigbridge libraries i
|
||||
- Initial release.
|
||||
|
||||
### API
|
||||
- Initial release
|
||||
- Initial release
|
||||
|
528
composer.lock
generated
528
composer.lock
generated
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user