mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Merge branch 'release/4.3.8'
This commit is contained in:
commit
970ce917b0
@ -9,7 +9,6 @@ cache:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
install:
|
||||
- if [[ "$(php -v | grep 'PHP 7')" ]]; then phpenv config-rm xdebug.ini; fi
|
||||
- rm composer.lock
|
||||
- composer update --no-scripts
|
||||
- cp .env.testing .env
|
||||
@ -18,9 +17,13 @@ install:
|
||||
- php artisan env
|
||||
- cp .env.testing .env
|
||||
- mv storage/database/databasecopy.sqlite storage/database/database.sqlite
|
||||
- mkdir -p build/logs
|
||||
|
||||
script:
|
||||
- phpunit
|
||||
- phpunit -c phpunit.coverage.xml
|
||||
|
||||
after_success:
|
||||
- travis_retry php vendor/bin/coveralls -x storage/build/clover.xml
|
||||
|
||||
# safelist
|
||||
branches:
|
||||
|
15
CHANGELOG.md
15
CHANGELOG.md
@ -3,6 +3,21 @@ All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
|
||||
## [4.3.8] - 2017-04-08
|
||||
|
||||
### Added
|
||||
- Better overview / show pages.
|
||||
- #628, as reported by [xzaz](https://github.com/xzaz).
|
||||
- Greatly expanded test coverage
|
||||
|
||||
### Fixed
|
||||
- #619, as reported by [dfiel](https://github.com/dfiel).
|
||||
- #620, as reported by [forcaeluz](https://github.com/forcaeluz).
|
||||
- Attempt to fix #624, as reported by [TheSerenin](https://github.com/TheSerenin).
|
||||
- Favicon link is relative now, fixed by [welbert](https://github.com/welbert).
|
||||
- Some search bugs
|
||||
|
||||
## [4.3.7] - 2017-03-06
|
||||
### Added
|
||||
- Nice user friendly views for empty lists.
|
||||
|
@ -35,4 +35,4 @@ If you like Firefly and if it helps you save lots of money, why not send me [a d
|
||||
|
||||
If you want to contact me, please open an issue or [email me](mailto:thegrumpydictator@gmail.com).
|
||||
|
||||
[](https://travis-ci.org/firefly-iii/firefly-iii) [](https://scrutinizer-ci.com/g/firefly-iii/firefly-iii/?branch=master)
|
||||
[](https://travis-ci.org/firefly-iii/firefly-iii) [](https://scrutinizer-ci.com/g/firefly-iii/firefly-iii/?branch=master) [](https://coveralls.io/github/firefly-iii/firefly-iii?branch=master)
|
||||
|
@ -17,8 +17,10 @@ namespace FireflyIII\Console\Commands;
|
||||
use DB;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
@ -60,6 +62,7 @@ class UpgradeDatabase extends Command
|
||||
{
|
||||
$this->setTransactionIdentifier();
|
||||
$this->migrateRepetitions();
|
||||
$this->repairPiggyBanks();
|
||||
}
|
||||
|
||||
private function migrateRepetitions()
|
||||
@ -69,7 +72,9 @@ class UpgradeDatabase extends Command
|
||||
}
|
||||
// get all budget limits with end_date NULL
|
||||
$set = BudgetLimit::whereNull('end_date')->get();
|
||||
if ($set->count() > 0) {
|
||||
$this->line(sprintf('Found %d budget limit(s) to update', $set->count()));
|
||||
}
|
||||
/** @var BudgetLimit $budgetLimit */
|
||||
foreach ($set as $budgetLimit) {
|
||||
// get limit repetition (should be just one):
|
||||
@ -84,6 +89,35 @@ class UpgradeDatabase extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure there are only transfers linked to piggy bank events.
|
||||
*/
|
||||
private function repairPiggyBanks()
|
||||
{
|
||||
// if table does not exist, return false
|
||||
if (!Schema::hasTable('piggy_bank_events')) {
|
||||
return;
|
||||
}
|
||||
$set = PiggyBankEvent::with(['PiggyBank', 'TransactionJournal', 'TransactionJournal.TransactionType'])->get();
|
||||
/** @var PiggyBankEvent $event */
|
||||
foreach ($set as $event) {
|
||||
|
||||
if (!is_null($event->transaction_journal_id)) {
|
||||
$type = $event->transactionJournal->transactionType->type;
|
||||
if ($type !== TransactionType::TRANSFER) {
|
||||
$event->transaction_journal_id = null;
|
||||
$event->save();
|
||||
$this->line(
|
||||
sprintf('Piggy bank #%d ("%s") was referenced by an invalid event. This has been fixed.', $event->piggy_bank_id,
|
||||
$event->piggyBank->name
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is strangely complex, because the HAVING modifier is a no-no. And subqueries in Laravel are weird.
|
||||
*/
|
||||
@ -151,7 +185,6 @@ class UpgradeDatabase extends Command
|
||||
$opposing->save();
|
||||
$processed[] = $transaction->id;
|
||||
$processed[] = $opposing->id;
|
||||
$this->line(sprintf('Database upgrade for journal #%d, transactions #%d and #%d', $journalId, $transaction->id, $opposing->id));
|
||||
}
|
||||
$identifier++;
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ class VerifyDatabase extends Command
|
||||
|
||||
// report on journals with the wrong types of accounts.
|
||||
$this->reportIncorrectJournals();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,7 +132,7 @@ class VerifyDatabase extends Command
|
||||
/** @var Budget $entry */
|
||||
foreach ($set as $entry) {
|
||||
$line = sprintf(
|
||||
'Notice: User #%d (%s) has budget #%d ("%s") which has no budget limits.',
|
||||
'User #%d (%s) has budget #%d ("%s") which has no budget limits.',
|
||||
$entry->user_id, $entry->email, $entry->id, $entry->name
|
||||
);
|
||||
$this->line($line);
|
||||
@ -277,7 +278,7 @@ class VerifyDatabase extends Command
|
||||
}
|
||||
|
||||
$line = sprintf(
|
||||
'Notice: User #%d (%s) has %s #%d ("%s") which has no transactions.',
|
||||
'User #%d (%s) has %s #%d ("%s") which has no transactions.',
|
||||
$entry->user_id, $entry->email, $name, $entry->id, $objName
|
||||
);
|
||||
$this->line($line);
|
||||
|
@ -97,6 +97,7 @@ class Handler extends ExceptionHandler
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
'code' => $exception->getCode(),
|
||||
'version' => config('firefly.version'),
|
||||
];
|
||||
|
||||
// create job that will mail.
|
||||
|
@ -20,6 +20,7 @@ use FireflyIII\Models\PiggyBankRepetition;
|
||||
use FireflyIII\Models\Rule;
|
||||
use FireflyIII\Models\RuleGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Rules\Processor;
|
||||
use FireflyIII\Support\Events\BillScanner;
|
||||
use Log;
|
||||
@ -45,6 +46,16 @@ class StoredJournalEventHandler
|
||||
$piggyBankId = $event->piggyBankId;
|
||||
Log::debug(sprintf('Trying to connect journal %d to piggy bank %d.', $journal->id, $piggyBankId));
|
||||
|
||||
/*
|
||||
* Will only continue when journal is a transfer.
|
||||
*/
|
||||
Log::debug(sprintf('Journal transaction type is %s', $journal->transactionType->type));
|
||||
if ($journal->transactionType->type !== TransactionType::TRANSFER) {
|
||||
Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify existence of piggy bank:
|
||||
*/
|
||||
|
@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Attachments;
|
||||
|
||||
use FireflyIII\Models\Attachment;
|
||||
|
@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Help;
|
||||
|
||||
use Cache;
|
||||
@ -43,12 +44,12 @@ class Help implements HelpInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $language
|
||||
* @param string $route
|
||||
* @param string $language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromGithub(string $language, string $route): string
|
||||
public function getFromGithub(string $route, string $language): string
|
||||
{
|
||||
|
||||
$uri = sprintf('https://raw.githubusercontent.com/firefly-iii/help/master/%s/%s.md', $language, $route);
|
||||
@ -123,6 +124,7 @@ class Help implements HelpInterface
|
||||
if (strlen($content) > 0) {
|
||||
Log::debug(sprintf('Will store entry in cache: %s', $key));
|
||||
Cache::put($key, $content, 10080); // a week.
|
||||
|
||||
return;
|
||||
}
|
||||
Log::info(sprintf('Will not cache %s because content is empty.', $key));
|
||||
|
@ -29,12 +29,12 @@ interface HelpInterface
|
||||
public function getFromCache(string $route, string $language): string;
|
||||
|
||||
/**
|
||||
* @param string $language
|
||||
* @param string $route
|
||||
* @param string $language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromGithub(string $language, string $route): string;
|
||||
public function getFromGithub(string $route, string $language): string;
|
||||
|
||||
/**
|
||||
* @param string $route
|
||||
|
199
app/Helpers/Report/PopupReport.php
Normal file
199
app/Helpers/Report/PopupReport.php
Normal file
@ -0,0 +1,199 @@
|
||||
<?php
|
||||
/**
|
||||
* PopupReport.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class PopupReport
|
||||
*
|
||||
* @package FireflyIII\Helpers\Report
|
||||
*/
|
||||
class PopupReport implements PopupReportInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceForBudget(Budget $budget, Account $account, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])->setBudget($budget);
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceForNoBudget(Account $account, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setTypes([TransactionType::WITHDRAWAL])
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->withoutBudget();
|
||||
|
||||
return $collector->getJournals();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byBudget(Budget $budget, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
|
||||
$collector->setAccounts($attributes['accounts'])->setRange($attributes['startDate'], $attributes['endDate']);
|
||||
|
||||
if (is_null($budget->id)) {
|
||||
$collector->setTypes([TransactionType::WITHDRAWAL])->withoutBudget();
|
||||
}
|
||||
if (!is_null($budget->id)) {
|
||||
$collector->setBudget($budget);
|
||||
}
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byCategory(Category $category, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts($attributes['accounts'])->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->setCategory($category);
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byExpenses(Account $account, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER]);
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
|
||||
|
||||
// filter for transfers and withdrawals TO the given $account
|
||||
$journals = $journals->filter(
|
||||
function (Transaction $transaction) use ($report) {
|
||||
// get the destinations:
|
||||
$sources = $transaction->transactionJournal->sourceAccountList()->pluck('id')->toArray();
|
||||
|
||||
// do these intersect with the current list?
|
||||
return !empty(array_intersect($report, $sources));
|
||||
}
|
||||
);
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byIncome(Account $account, array $attributes): Collection
|
||||
{
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER]);
|
||||
$journals = $collector->getJournals();
|
||||
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
|
||||
|
||||
// filter the set so the destinations outside of $attributes['accounts'] are not included.
|
||||
$journals = $journals->filter(
|
||||
function (Transaction $transaction) use ($report) {
|
||||
// get the destinations:
|
||||
$destinations = $transaction->destinationAccountList($transaction->transactionJournal)->pluck('id')->toArray();
|
||||
|
||||
// do these intersect with the current list?
|
||||
return !empty(array_intersect($report, $destinations));
|
||||
}
|
||||
);
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $account
|
||||
* @param $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceDifference($account, $attributes): Collection
|
||||
{
|
||||
// row that displays difference
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setTypes([TransactionType::WITHDRAWAL])
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->withoutBudget();
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
|
||||
return $journals->filter(
|
||||
function (Transaction $transaction) {
|
||||
$tags = $transaction->transactionJournal->tags()->where('tagMode', 'balancingAct')->count();
|
||||
if ($tags === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
83
app/Helpers/Report/PopupReportInterface.php
Normal file
83
app/Helpers/Report/PopupReportInterface.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* PopupReportInterface.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface PopupReportInterface
|
||||
*
|
||||
* @package FireflyIII\Helpers\Report
|
||||
*/
|
||||
interface PopupReportInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $account
|
||||
* @param $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceDifference($account, $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceForBudget(Budget $budget, Account $account, array $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceForNoBudget(Account $account, array $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byBudget(Budget $budget, array $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byCategory(Category $category, array $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byExpenses(Account $account, array $attributes): Collection;
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function byIncome(Account $account, array $attributes): Collection;
|
||||
}
|
@ -25,6 +25,7 @@ use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Account\AccountTaskerInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -230,15 +231,17 @@ class AccountController extends Controller
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
* @param string $moment
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||
*/
|
||||
public function show(Request $request, Account $account, string $moment = '')
|
||||
public function show(Request $request, JournalRepositoryInterface $repository, Account $account, string $moment = '')
|
||||
{
|
||||
if ($account->accountType->type === AccountType::INITIAL_BALANCE) {
|
||||
return $this->redirectToOriginalAccount($account);
|
||||
}
|
||||
$subTitle = $account->name;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
@ -250,29 +253,34 @@ class AccountController extends Controller
|
||||
|
||||
// prep for "all" view.
|
||||
if ($moment === 'all') {
|
||||
$subTitle = $account->name . ' (' . strtolower(strval(trans('firefly.everything'))) . ')';
|
||||
$subTitle = trans('firefly.all_journals_for_account', ['name' => $account->name]);
|
||||
$chartUri = route('chart.account.all', [$account->id]);
|
||||
$first = $repository->first();
|
||||
$start = $first->date ?? new Carbon;
|
||||
$end = new Carbon;
|
||||
}
|
||||
|
||||
// prep for "specific date" view.
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$start = new Carbon($moment);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
$subTitle = $account->name . ' (' . strval(
|
||||
trans(
|
||||
'firefly.from_to_breadcrumb',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
)
|
||||
) . ')';
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d')]);
|
||||
$periods = $this->periodEntries($account);
|
||||
$periods = $this->getPeriodOverview($account);
|
||||
}
|
||||
|
||||
// prep for current period
|
||||
if (strlen($moment) === 0) {
|
||||
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||
$periods = $this->periodEntries($account);
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getPeriodOverview($account);
|
||||
}
|
||||
|
||||
$accountType = $account->accountType->type;
|
||||
@ -289,7 +297,7 @@ class AccountController extends Controller
|
||||
$collector->setRange($start, $end);
|
||||
}
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('accounts/show/' . $account->id);
|
||||
$journals->setPath('accounts/show/' . $account->id . '/' . $moment);
|
||||
$count = $journals->getCollection()->count();
|
||||
if ($count === 0) {
|
||||
$start->subDay();
|
||||
@ -299,8 +307,17 @@ class AccountController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
if ($moment != 'all' && $loop > 1) {
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
|
||||
return view('accounts.show', compact('account', 'accountType', 'periods', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri'));
|
||||
|
||||
return view(
|
||||
'accounts.show', compact('account', 'moment', 'accountType', 'periods', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,7 +405,7 @@ class AccountController extends Controller
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function periodEntries(Account $account): Collection
|
||||
private function getPeriodOverview(Account $account): Collection
|
||||
{
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
@ -425,7 +442,14 @@ class AccountController extends Controller
|
||||
$earned = $tasker->amountInInPeriod(new Collection([$account]), $assets, $end, $currentEnd);
|
||||
$dateStr = $end->format('Y-m-d');
|
||||
$dateName = Navigation::periodShow($end, $range);
|
||||
$entries->push([$dateStr, $dateName, $spent, $earned, clone $end]);
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'date' => clone $end]
|
||||
);
|
||||
$end = Navigation::subtractPeriod($end, $range, 1);
|
||||
|
||||
}
|
||||
@ -453,7 +477,7 @@ class AccountController extends Controller
|
||||
$opposingTransaction = $journal->transactions()->where('transactions.id', '!=', $transaction->id)->first();
|
||||
|
||||
if (is_null($opposingTransaction)) {
|
||||
throw new FireflyException('Expected an opposing transaction. This account has none. BEEP, error.');
|
||||
throw new FireflyException('Expected an opposing transaction. This account has none. BEEP, error.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return redirect(route('accounts.show', [$opposingTransaction->account_id]));
|
||||
|
@ -18,6 +18,7 @@ use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\UserFormRequest;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Session;
|
||||
use View;
|
||||
@ -129,29 +130,27 @@ class UserController extends Controller
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function update(UserFormRequest $request, User $user)
|
||||
public function update(UserFormRequest $request, User $user, UserRepositoryInterface $repository)
|
||||
{
|
||||
Log::debug('Actually here');
|
||||
$data = $request->getUserData();
|
||||
|
||||
// update password
|
||||
if (strlen($data['password']) > 0) {
|
||||
$user->password = bcrypt($data['password']);
|
||||
$user->save();
|
||||
$repository->changePassword($user, $data['password']);
|
||||
}
|
||||
|
||||
// change blocked status and code:
|
||||
$user->blocked = $data['blocked'];
|
||||
$user->blocked_code = $data['blocked_code'];
|
||||
$user->save();
|
||||
$repository->changeStatus($user, $data['blocked'], $data['blocked_code']);
|
||||
|
||||
Session::flash('success', strval(trans('firefly.updated_user', ['email' => $user->email])));
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('users.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('admin.users.edit', [$user->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
|
@ -176,10 +176,11 @@ class AttachmentController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('attachments.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('attachments.edit', [$attachment->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
|
@ -13,6 +13,7 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Http\Controllers\Auth;
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||
use Illuminate\Http\Request;
|
||||
@ -44,21 +45,18 @@ class ForgotPasswordController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function sendResetLinkEmail(Request $request)
|
||||
public function sendResetLinkEmail(Request $request, UserRepositoryInterface $repository)
|
||||
{
|
||||
$this->validate($request, ['email' => 'required|email']);
|
||||
|
||||
// verify if the user is not a demo user. If so, we give him back an error.
|
||||
$user = User::where('email', $request->get('email'))->first();
|
||||
if (!is_null($user) && $user->hasRole('demo')) {
|
||||
return back()->withErrors(
|
||||
['email' => trans('firefly.cannot_reset_demo_user')]
|
||||
);
|
||||
|
||||
if (!is_null($user) && $repository->hasRole($user, 'demo')) {
|
||||
return back()->withErrors(['email' => trans('firefly.cannot_reset_demo_user')]);
|
||||
}
|
||||
|
||||
$response = $this->broker()->sendResetLink(
|
||||
$request->only('email')
|
||||
);
|
||||
$response = $this->broker()->sendResetLink($request->only('email'));
|
||||
|
||||
if ($response === Password::RESET_LINK_SENT) {
|
||||
return back()->with('status', trans($response));
|
||||
@ -67,8 +65,6 @@ class ForgotPasswordController extends Controller
|
||||
// If an error was returned by the password broker, we will get this message
|
||||
// translated so we can notify a user of the problem. We'll redirect back
|
||||
// to where the users came from so they can attempt this process again.
|
||||
return back()->withErrors(
|
||||
['email' => trans($response)]
|
||||
);
|
||||
return back()->withErrors(['email' => trans($response)]); // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ use Illuminate\Http\Request;
|
||||
use Lang;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class LoginController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers\Auth
|
||||
@ -112,8 +114,10 @@ class LoginController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function showLoginForm(Request $request)
|
||||
public function showLoginForm(Request $request, CookieJar $cookieJar)
|
||||
{
|
||||
// forget 2fa cookie:
|
||||
$cookie = $cookieJar->forever('twoFactorAuthenticated', 'false');
|
||||
// is allowed to?
|
||||
$singleUserMode = FireflyConfig::get('single_user_mode', Config::get('firefly.configuration.single_user_mode'))->data;
|
||||
$userCount = User::count();
|
||||
@ -125,7 +129,7 @@ class LoginController extends Controller
|
||||
$email = $request->old('email');
|
||||
$remember = $request->old('remember');
|
||||
|
||||
return view('auth.login', compact('allowRegistration', 'email', 'remember'));
|
||||
return view('auth.login', compact('allowRegistration', 'email', 'remember'))->withCookie($cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,6 +22,8 @@ use Illuminate\Support\Facades\Password;
|
||||
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class PasswordController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers\Auth
|
||||
|
@ -24,6 +24,8 @@ use Session;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class RegisterController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers\Auth
|
||||
|
@ -16,6 +16,8 @@ use FireflyIII\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class ResetPasswordController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers\Auth
|
||||
|
@ -41,11 +41,12 @@ class TwoFactorController extends Controller
|
||||
$user = auth()->user();
|
||||
|
||||
// to make sure the validator in the next step gets the secret, we push it in session
|
||||
$secret = Preferences::get('twoFactorAuthSecret', null)->data;
|
||||
$secretPreference = Preferences::get('twoFactorAuthSecret', null);
|
||||
$secret = is_null($secretPreference) ? null : $secretPreference->data;
|
||||
$title = strval(trans('firefly.two_factor_title'));
|
||||
|
||||
// make sure the user has two factor configured:
|
||||
$has2FA = Preferences::get('twoFactorAuthEnabled', null)->data;
|
||||
$has2FA = Preferences::get('twoFactorAuthEnabled', false)->data;
|
||||
if (is_null($has2FA) || $has2FA === false) {
|
||||
return redirect(route('index'));
|
||||
}
|
||||
|
@ -240,10 +240,11 @@ class BillController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('bills.create.fromStore', true);
|
||||
|
||||
return redirect(route('bills.create'))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
@ -267,10 +268,11 @@ class BillController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('bills.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('bills.edit', [$bill->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('bills.edit.uri'));
|
||||
|
@ -22,11 +22,15 @@ use FireflyIII\Http\Requests\BudgetIncomeRequest;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use View;
|
||||
@ -188,30 +192,81 @@ class BudgetController extends Controller
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param string $moment
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function noBudget(Request $request)
|
||||
public function noBudget(Request $request, JournalRepositoryInterface $repository, string $moment = '')
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = session('start', Carbon::now()->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = session('end', Carbon::now()->endOfMonth());
|
||||
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
// default values:
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
|
||||
// prep for "all" view.
|
||||
if ($moment === 'all') {
|
||||
$subTitle = trans('firefly.all_journals_without_budget');
|
||||
$first = $repository->first();
|
||||
$start = $first->date ?? new Carbon;
|
||||
$end = new Carbon;
|
||||
}
|
||||
|
||||
// prep for "specific date" view.
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$start = new Carbon($moment);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
$subTitle = trans(
|
||||
'firefly.without_budget_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getPeriodOverview();
|
||||
}
|
||||
|
||||
// collector
|
||||
// prep for current period
|
||||
if (strlen($moment) === 0) {
|
||||
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||
$periods = $this->getPeriodOverview();
|
||||
$subTitle = trans(
|
||||
'firefly.without_budget_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
|
||||
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
|
||||
$count = 0;
|
||||
$loop = 0;
|
||||
// grab journals, but be prepared to jump a period back to get the right ones:
|
||||
Log::info('Now at no-budget loop start.');
|
||||
while ($count === 0 && $loop < 3) {
|
||||
$loop++;
|
||||
Log::info('Count is zero, search for journals.');
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withoutBudget();
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setLimit($pageSize)->setPage($page)
|
||||
->withoutBudget()->withOpposingAccount();
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('/budgets/list/noBudget');
|
||||
$journals->setPath('/budgets/list/no-budget');
|
||||
$count = $journals->getCollection()->count();
|
||||
if ($count === 0) {
|
||||
$start->subDay();
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
}
|
||||
}
|
||||
|
||||
return view('budgets.no-budget', compact('journals', 'subTitle'));
|
||||
if ($moment != 'all' && $loop > 1) {
|
||||
$subTitle = trans(
|
||||
'firefly.without_budget_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
|
||||
return view('budgets.no-budget', compact('journals', 'subTitle', 'moment', 'periods', 'start', 'end'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -315,10 +370,11 @@ class BudgetController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('budgets.create.fromStore', true);
|
||||
|
||||
return redirect(route('budgets.create'))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('budgets.create.uri'));
|
||||
@ -339,10 +395,11 @@ class BudgetController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('budgets.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('budgets.edit', [$budget->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('budgets.edit.uri'));
|
||||
@ -405,7 +462,6 @@ class BudgetController extends Controller
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
@ -442,4 +498,57 @@ class BudgetController extends Controller
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getPeriodOverview(): Collection
|
||||
{
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$first = $repository->first();
|
||||
$start = $first->date ?? new Carbon;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfX(new Carbon, $range);
|
||||
$entries = new Collection;
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('no-budget-period-entries');
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
Log::debug('Going to get period expenses and incomes.');
|
||||
while ($end >= $start) {
|
||||
$end = Navigation::startOfPeriod($end, $range);
|
||||
$currentEnd = Navigation::endOfPeriod($end, $range);
|
||||
|
||||
// count journals without budget in this period:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutBudget()->withOpposingAccount()->setTypes([TransactionType::WITHDRAWAL]);
|
||||
$set = $collector->getJournals();
|
||||
$sum = $set->sum('transaction_amount');
|
||||
$journals = $set->count();
|
||||
$dateStr = $end->format('Y-m-d');
|
||||
$dateName = Navigation::periodShow($end, $range);
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'count' => $journals,
|
||||
'sum' => $sum,
|
||||
'date' => clone $end,
|
||||
]
|
||||
);
|
||||
$end = Navigation::subtractPeriod($end, $range, 1);
|
||||
}
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,13 +18,17 @@ use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Http\Requests\CategoryFormRequest;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
use Steam;
|
||||
use View;
|
||||
|
||||
/**
|
||||
@ -152,116 +156,164 @@ class CategoryController extends Controller
|
||||
/**
|
||||
* @return View
|
||||
*/
|
||||
public function noCategory()
|
||||
public function noCategory(Request $request, JournalRepositoryInterface $repository, string $moment = '')
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = session('start', Carbon::now()->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = session('end', Carbon::now()->startOfMonth());
|
||||
// default values:
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
|
||||
// new collector:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->withoutCategory();//->groupJournals();
|
||||
$journals = $collector->getJournals();
|
||||
// prep for "all" view.
|
||||
if ($moment === 'all') {
|
||||
$subTitle = trans('firefly.all_journals_without_category');
|
||||
$first = $repository->first();
|
||||
$start = $first->date ?? new Carbon;
|
||||
$end = new Carbon;
|
||||
}
|
||||
|
||||
// prep for "specific date" view.
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$start = new Carbon($moment);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
$subTitle = trans(
|
||||
'firefly.without_category_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
|
||||
return view('categories.no-category', compact('journals', 'subTitle'));
|
||||
$periods = $this->getNoCategoryPeriodOverview();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param JournalCollectorInterface $collector
|
||||
* @param Category $category
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function show(Request $request, JournalCollectorInterface $collector, Category $category)
|
||||
{
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||
$end = session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||
$hideCategory = true; // used in list.
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
// prep for current period
|
||||
if (strlen($moment) === 0) {
|
||||
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||
$periods = $this->getNoCategoryPeriodOverview();
|
||||
$subTitle = trans(
|
||||
'firefly.without_category_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
|
||||
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$subTitle = $category->name;
|
||||
$subTitleIcon = 'fa-bar-chart';
|
||||
$entries = $this->getGroupedEntries($category);
|
||||
$method = 'default';
|
||||
|
||||
// get journals
|
||||
$collector->setLimit($pageSize)->setPage($page)->setAllAssetAccounts()->setRange($start, $end)->setCategory($category)->withBudgetInformation();
|
||||
$count = 0;
|
||||
$loop = 0;
|
||||
// grab journals, but be prepared to jump a period back to get the right ones:
|
||||
Log::info('Now at no-cat loop start.');
|
||||
while ($count === 0 && $loop < 3) {
|
||||
$loop++;
|
||||
Log::info('Count is zero, search for journals.');
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withoutCategory()->withOpposingAccount();
|
||||
$collector->disableInternalFilter();
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('categories/show/' . $category->id);
|
||||
$journals->setPath('/categories/list/no-category');
|
||||
$count = $journals->getCollection()->count();
|
||||
if ($count === 0) {
|
||||
$start->subDay();
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
}
|
||||
}
|
||||
|
||||
if ($moment != 'all' && $loop > 1) {
|
||||
$subTitle = trans(
|
||||
'firefly.without_category_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
|
||||
return view('categories.show', compact('category', 'method', 'journals', 'entries', 'hideCategory', 'subTitle', 'subTitleIcon', 'start', 'end'));
|
||||
return view('categories.no-category', compact('journals', 'subTitle', 'moment', 'periods', 'start', 'end'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
* @param Category $category
|
||||
* @param string $moment
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function showAll(Request $request, CategoryRepositoryInterface $repository, Category $category)
|
||||
public function show(Request $request, CategoryRepositoryInterface $repository, Category $category, string $moment = '')
|
||||
{
|
||||
// default values:
|
||||
$subTitle = $category->name;
|
||||
$subTitleIcon = 'fa-bar-chart';
|
||||
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$count = 0;
|
||||
$loop = 0;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
|
||||
|
||||
// prep for "all" view.
|
||||
if ($moment === 'all') {
|
||||
$subTitle = trans('firefly.all_journals_for_category', ['name' => $category->name]);
|
||||
$start = $repository->firstUseDate($category);
|
||||
if ($start->year == 1900) {
|
||||
$start = new Carbon;
|
||||
$end = new Carbon;
|
||||
}
|
||||
$end = Navigation::endOfPeriod(new Carbon, $range);
|
||||
$subTitle = $category->name;
|
||||
$subTitleIcon = 'fa-bar-chart';
|
||||
$hideCategory = true; // used in list.
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$method = 'all';
|
||||
|
||||
// prep for "specific date" view.
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$start = new Carbon($moment);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_category',
|
||||
['name' => $category->name,
|
||||
'start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getPeriodOverview($category);
|
||||
}
|
||||
|
||||
// prep for current period
|
||||
if (strlen($moment) === 0) {
|
||||
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||
$periods = $this->getPeriodOverview($category);
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_category',
|
||||
['name' => $category->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
// grab journals, but be prepared to jump a period back to get the right ones:
|
||||
Log::info('Now at category loop start.');
|
||||
while ($count === 0 && $loop < 3) {
|
||||
$loop++;
|
||||
Log::info('Count is zero, search for journals.');
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setLimit($pageSize)->setPage($page)->setAllAssetAccounts()->setCategory($category)->withBudgetInformation();
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
|
||||
->setCategory($category)->withBudgetInformation()->withCategoryInformation()->disableInternalFilter();
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('categories/show/' . $category->id . '/all');
|
||||
|
||||
return view('categories.show', compact('category', 'method', 'journals', 'hideCategory', 'subTitle', 'subTitleIcon', 'start', 'end'));
|
||||
$journals->setPath('categories/show/' . $category->id);
|
||||
$count = $journals->getCollection()->count();
|
||||
if ($count === 0) {
|
||||
$start->subDay();
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Category $category
|
||||
* @param string $date
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function showByDate(Request $request, Category $category, string $date)
|
||||
{
|
||||
$carbon = new Carbon($date);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($carbon, $range);
|
||||
$end = Navigation::endOfPeriod($carbon, $range);
|
||||
$subTitle = $category->name;
|
||||
$subTitleIcon = 'fa-bar-chart';
|
||||
$hideCategory = true; // used in list.
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$entries = $this->getGroupedEntries($category);
|
||||
$method = 'date';
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setLimit($pageSize)->setPage($page)->setAllAssetAccounts()->setRange($start, $end)->setCategory($category)->withBudgetInformation();
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('categories/show/' . $category->id . '/' . $date);
|
||||
|
||||
return view('categories.show', compact('category', 'method', 'entries', 'journals', 'hideCategory', 'subTitle', 'subTitleIcon', 'start', 'end'));
|
||||
if ($moment != 'all' && $loop > 1) {
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_category',
|
||||
['name' => $category->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
|
||||
return view('categories.show', compact('category', 'moment', 'journals', 'periods', 'subTitle', 'subTitleIcon', 'start', 'end'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param CategoryFormRequest $request
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
@ -277,9 +329,11 @@ class CategoryController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('create_another')) === 1) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('categories.create.fromStore', true);
|
||||
|
||||
return redirect(route('categories.create'))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect(route('categories.index'));
|
||||
@ -302,20 +356,97 @@ class CategoryController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('categories.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('categories.edit', [$category->id]));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('categories.edit.uri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getNoCategoryPeriodOverview(): Collection
|
||||
{
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$first = $repository->first();
|
||||
$start = $first->date ?? new Carbon;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfX(new Carbon, $range);
|
||||
$entries = new Collection;
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('no-budget-period-entries');
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Going to get period expenses and incomes between %s and %s.', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
while ($end >= $start) {
|
||||
Log::debug('Loop!');
|
||||
$end = Navigation::startOfPeriod($end, $range);
|
||||
$currentEnd = Navigation::endOfPeriod($end, $range);
|
||||
|
||||
// count journals without budget in this period:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()->withOpposingAccount();
|
||||
$count = $collector->getJournals()->count();
|
||||
|
||||
// amount transferred
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()
|
||||
->withOpposingAccount()->setTypes([TransactionType::TRANSFER])->disableInternalFilter();
|
||||
$transferred = Steam::positive($collector->getJournals()->sum('transaction_amount'));
|
||||
|
||||
// amount spent
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()->withOpposingAccount()->setTypes([TransactionType::WITHDRAWAL]);
|
||||
$spent = $collector->getJournals()->sum('transaction_amount');
|
||||
|
||||
// amount earned
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()->withOpposingAccount()->setTypes([TransactionType::DEPOSIT]);
|
||||
$earned = $collector->getJournals()->sum('transaction_amount');
|
||||
|
||||
$dateStr = $end->format('Y-m-d');
|
||||
$dateName = Navigation::periodShow($end, $range);
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'count' => $count,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'transferred' => $transferred,
|
||||
'date' => clone $end,
|
||||
]
|
||||
);
|
||||
$end = Navigation::subtractPeriod($end, $range, 1);
|
||||
}
|
||||
Log::debug('End of loops');
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function getGroupedEntries(Category $category): Collection
|
||||
private function getPeriodOverview(Category $category): Collection
|
||||
{
|
||||
/** @var CategoryRepositoryInterface $repository */
|
||||
$repository = app(CategoryRepositoryInterface::class);
|
||||
@ -348,7 +479,25 @@ class CategoryController extends Controller
|
||||
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $end, $currentEnd);
|
||||
$dateStr = $end->format('Y-m-d');
|
||||
$dateName = Navigation::periodShow($end, $range);
|
||||
$entries->push([$dateStr, $dateName, $spent, $earned, clone $end]);
|
||||
|
||||
// amount transferred
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->setCategory($category)
|
||||
->withOpposingAccount()->setTypes([TransactionType::TRANSFER])->disableInternalFilter();
|
||||
$transferred = Steam::positive($collector->getJournals()->sum('transaction_amount'));
|
||||
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'sum' => bcadd($earned, $spent),
|
||||
'transferred' => $transferred,
|
||||
'date' => clone $end,
|
||||
]
|
||||
);
|
||||
$end = Navigation::subtractPeriod($end, $range, 1);
|
||||
}
|
||||
$cache->store($entries);
|
||||
|
@ -61,15 +61,12 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function all(Account $account)
|
||||
{
|
||||
$cache = new CacheProperties();
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('chart.account.all');
|
||||
$cache->addProperty($account->id);
|
||||
if ($cache->has()) {
|
||||
Log::debug('Return chart.account.all from cache.');
|
||||
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
Log::debug('Regenerate chart.account.all from scratch.');
|
||||
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
@ -500,8 +497,6 @@ class AccountController extends Controller
|
||||
$cache->addProperty('chart.account.account-balance-chart');
|
||||
$cache->addProperty($accounts);
|
||||
if ($cache->has()) {
|
||||
Log::debug('Return chart.account.account-balance-chart from cache.');
|
||||
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
Log::debug('Regenerate chart.account.account-balance-chart from scratch.');
|
||||
|
@ -16,7 +16,7 @@ namespace FireflyIII\Http\Controllers\Chart;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
||||
use FireflyIII\Generator\Report\Category\MonthReportGenerator;
|
||||
use FireflyIII\Generator\Report\Support;
|
||||
use FireflyIII\Helpers\Chart\MetaPieChartInterface;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
@ -24,7 +24,6 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -41,8 +40,6 @@ use Response;
|
||||
class BudgetReportController extends Controller
|
||||
{
|
||||
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $accountRepository;
|
||||
/** @var BudgetRepositoryInterface */
|
||||
private $budgetRepository;
|
||||
/** @var GeneratorInterface */
|
||||
@ -58,7 +55,6 @@ class BudgetReportController extends Controller
|
||||
function ($request, $next) {
|
||||
$this->generator = app(GeneratorInterface::class);
|
||||
$this->budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
@ -133,8 +129,6 @@ class BudgetReportController extends Controller
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
/** @var BudgetRepositoryInterface $repository */
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
$format = Navigation::preferredCarbonLocalizedFormat($start, $end);
|
||||
$function = Navigation::preferredEndOfPeriod($start, $end);
|
||||
$chartData = [];
|
||||
@ -163,7 +157,7 @@ class BudgetReportController extends Controller
|
||||
'entries' => [],
|
||||
];
|
||||
}
|
||||
$allBudgetLimits = $repository->getAllBudgetLimits($start, $end);
|
||||
$allBudgetLimits = $this->budgetRepository->getAllBudgetLimits($start, $end);
|
||||
$sumOfExpenses = [];
|
||||
$leftOfLimits = [];
|
||||
while ($currentStart < $end) {
|
||||
@ -243,7 +237,7 @@ class BudgetReportController extends Controller
|
||||
->setBudgets($budgets)->withOpposingAccount()->disableFilter();
|
||||
$accountIds = $accounts->pluck('id')->toArray();
|
||||
$transactions = $collector->getJournals();
|
||||
$set = MonthReportGenerator::filterExpenses($transactions, $accountIds);
|
||||
$set = Support::filterExpenses($transactions, $accountIds);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
@ -86,15 +86,23 @@ class CategoryController extends Controller
|
||||
'entries' => [],
|
||||
'type' => 'bar',
|
||||
],
|
||||
[
|
||||
'label' => strval(trans('firefly.sum')),
|
||||
'entries' => [],
|
||||
'type' => 'line',
|
||||
'fill' => false,
|
||||
],
|
||||
];
|
||||
|
||||
while ($start <= $end) {
|
||||
$currentEnd = Navigation::endOfPeriod($start, $range);
|
||||
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $currentEnd);
|
||||
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $start, $currentEnd);
|
||||
$sum = bcadd($spent, $earned);
|
||||
$label = Navigation::periodShow($start, $range);
|
||||
$chartData[0]['entries'][$label] = bcmul($spent, '-1');
|
||||
$chartData[1]['entries'][$label] = $earned;
|
||||
$chartData[2]['entries'][$label] = $sum;
|
||||
$start = Navigation::addPeriod($start, $range, 0);
|
||||
}
|
||||
|
||||
@ -194,13 +202,22 @@ class CategoryController extends Controller
|
||||
'entries' => [],
|
||||
'type' => 'bar',
|
||||
],
|
||||
[
|
||||
'label' => strval(trans('firefly.sum')),
|
||||
'entries' => [],
|
||||
'type' => 'line',
|
||||
'fill' => false,
|
||||
],
|
||||
];
|
||||
|
||||
foreach (array_keys($periods) as $period) {
|
||||
$label = $periods[$period];
|
||||
$spent = $expenses[$category->id]['entries'][$period] ?? '0';
|
||||
$earned = $income[$category->id]['entries'][$period] ?? '0';
|
||||
$sum = bcadd($spent, $earned);
|
||||
$chartData[0]['entries'][$label] = bcmul($spent, '-1');
|
||||
$chartData[1]['entries'][$label] = $income[$category->id]['entries'][$period] ?? '0';
|
||||
$chartData[1]['entries'][$label] = $earned;
|
||||
$chartData[2]['entries'][$label] = $sum;
|
||||
}
|
||||
|
||||
$data = $this->generator->multiSet($chartData);
|
||||
@ -241,13 +258,22 @@ class CategoryController extends Controller
|
||||
'entries' => [],
|
||||
'type' => 'bar',
|
||||
],
|
||||
[
|
||||
'label' => strval(trans('firefly.sum')),
|
||||
'entries' => [],
|
||||
'type' => 'line',
|
||||
'fill' => false,
|
||||
],
|
||||
];
|
||||
|
||||
foreach (array_keys($periods) as $period) {
|
||||
$label = $periods[$period];
|
||||
$spent = $expenses['entries'][$period] ?? '0';
|
||||
$earned = $income['entries'][$period] ?? '0';
|
||||
$sum = bcadd($spent, $earned);
|
||||
$chartData[0]['entries'][$label] = bcmul($spent, '-1');
|
||||
$chartData[1]['entries'][$label] = $income['entries'][$period] ?? '0';
|
||||
$chartData[1]['entries'][$label] = $earned;
|
||||
$chartData[2]['entries'][$label] = $sum;
|
||||
|
||||
}
|
||||
$data = $this->generator->multiSet($chartData);
|
||||
@ -312,15 +338,23 @@ class CategoryController extends Controller
|
||||
'entries' => [],
|
||||
'type' => 'bar',
|
||||
],
|
||||
[
|
||||
'label' => strval(trans('firefly.sum')),
|
||||
'entries' => [],
|
||||
'type' => 'line',
|
||||
'fill' => false,
|
||||
],
|
||||
];
|
||||
|
||||
while ($start <= $end) {
|
||||
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $start);
|
||||
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $start, $start);
|
||||
$sum = bcadd($spent, $earned);
|
||||
$label = Navigation::periodShow($start, '1D');
|
||||
|
||||
$chartData[0]['entries'][$label] = bcmul($spent, '-1');
|
||||
$chartData[1]['entries'][$label] = $earned;
|
||||
$chartData[2]['entries'][$label] = $sum;
|
||||
|
||||
|
||||
$start->addDay();
|
||||
|
@ -23,8 +23,6 @@ use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
use Navigation;
|
||||
@ -41,10 +39,6 @@ use Response;
|
||||
class CategoryReportController extends Controller
|
||||
{
|
||||
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $accountRepository;
|
||||
/** @var CategoryRepositoryInterface */
|
||||
private $categoryRepository;
|
||||
/** @var GeneratorInterface */
|
||||
private $generator;
|
||||
|
||||
@ -57,8 +51,6 @@ class CategoryReportController extends Controller
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->generator = app(GeneratorInterface::class);
|
||||
$this->categoryRepository = app(CategoryRepositoryInterface::class);
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
@ -78,11 +70,8 @@ class CategoryReportController extends Controller
|
||||
{
|
||||
/** @var MetaPieChartInterface $helper */
|
||||
$helper = app(MetaPieChartInterface::class);
|
||||
$helper->setAccounts($accounts);
|
||||
$helper->setCategories($categories);
|
||||
$helper->setStart($start);
|
||||
$helper->setEnd($end);
|
||||
$helper->setCollectOtherObjects(intval($others) === 1);
|
||||
$helper->setAccounts($accounts)->setCategories($categories)->setStart($start)->setEnd($end)->setCollectOtherObjects(intval($others) === 1);
|
||||
|
||||
$chartData = $helper->generate('expense', 'account');
|
||||
$data = $this->generator->pieChart($chartData);
|
||||
|
||||
|
@ -120,9 +120,11 @@ class Controller extends BaseController
|
||||
}
|
||||
|
||||
}
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::flash('error', strval(trans('firefly.cannot_redirect_to_account')));
|
||||
|
||||
return redirect(route('index'));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,6 +17,7 @@ use Cache;
|
||||
use FireflyIII\Http\Requests\CurrencyFormRequest;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
use Preferences;
|
||||
@ -30,6 +31,11 @@ use View;
|
||||
class CurrencyController extends Controller
|
||||
{
|
||||
|
||||
/** @var CurrencyRepositoryInterface */
|
||||
protected $repository;
|
||||
|
||||
/** @var UserRepositoryInterface */
|
||||
protected $userRepository;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -43,6 +49,8 @@ class CurrencyController extends Controller
|
||||
function ($request, $next) {
|
||||
View::share('title', trans('firefly.currencies'));
|
||||
View::share('mainTitleIcon', 'fa-usd');
|
||||
$this->repository = app(CurrencyRepositoryInterface::class);
|
||||
$this->userRepository = app(UserRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
@ -52,10 +60,16 @@ class CurrencyController extends Controller
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return View
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||
*/
|
||||
public function create(Request $request)
|
||||
{
|
||||
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
|
||||
$request->session()->flash('error', trans('firefly.ask_site_owner', ['owner' => env('SITE_OWNER')]));
|
||||
|
||||
return redirect(route('currencies.index'));
|
||||
}
|
||||
|
||||
$subTitleIcon = 'fa-plus';
|
||||
$subTitle = trans('firefly.create_currency');
|
||||
|
||||
@ -93,14 +107,21 @@ class CurrencyController extends Controller
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||
*/
|
||||
public function delete(Request $request, CurrencyRepositoryInterface $repository, TransactionCurrency $currency)
|
||||
public function delete(Request $request, TransactionCurrency $currency)
|
||||
{
|
||||
if (!$repository->canDeleteCurrency($currency)) {
|
||||
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->flash('error', trans('firefly.ask_site_owner', ['owner' => env('SITE_OWNER')]));
|
||||
|
||||
return redirect(route('currencies.index'));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if (!$this->repository->canDeleteCurrency($currency)) {
|
||||
$request->session()->flash('error', trans('firefly.cannot_delete_currency', ['name' => $currency->name]));
|
||||
|
||||
return redirect(route('currencies.index'));
|
||||
@ -119,20 +140,27 @@ class CurrencyController extends Controller
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function destroy(Request $request, CurrencyRepositoryInterface $repository, TransactionCurrency $currency)
|
||||
public function destroy(Request $request, TransactionCurrency $currency)
|
||||
{
|
||||
if (!$repository->canDeleteCurrency($currency)) {
|
||||
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->flash('error', trans('firefly.ask_site_owner', ['owner' => env('SITE_OWNER')]));
|
||||
|
||||
return redirect(route('currencies.index'));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if (!$this->repository->canDeleteCurrency($currency)) {
|
||||
$request->session()->flash('error', trans('firefly.cannot_delete_currency', ['name' => $currency->name]));
|
||||
|
||||
return redirect(route('currencies.index'));
|
||||
}
|
||||
|
||||
$repository->destroy($currency);
|
||||
$this->repository->destroy($currency);
|
||||
$request->session()->flash('success', trans('firefly.deleted_currency', ['name' => $currency->name]));
|
||||
|
||||
return redirect($this->getPreviousUri('currencies.delete.uri'));
|
||||
@ -142,10 +170,18 @@ class CurrencyController extends Controller
|
||||
* @param Request $request
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return View
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||
*/
|
||||
public function edit(Request $request, TransactionCurrency $currency)
|
||||
{
|
||||
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->flash('error', trans('firefly.ask_site_owner', ['owner' => env('SITE_OWNER')]));
|
||||
|
||||
return redirect(route('currencies.index'));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$subTitleIcon = 'fa-pencil';
|
||||
$subTitle = trans('breadcrumbs.edit_currency', ['name' => $currency->name]);
|
||||
$currency->symbol = htmlentities($currency->symbol);
|
||||
@ -164,47 +200,45 @@ class CurrencyController extends Controller
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function index(Request $request, CurrencyRepositoryInterface $repository)
|
||||
public function index(Request $request)
|
||||
{
|
||||
$currencies = $repository->get();
|
||||
$defaultCurrency = $repository->getCurrencyByPreference(Preferences::get('currencyPreference', config('firefly.default_currency', 'EUR')));
|
||||
|
||||
|
||||
if (!auth()->user()->hasRole('owner')) {
|
||||
$currencies = $this->repository->get();
|
||||
$defaultCurrency = $this->repository->getCurrencyByPreference(Preferences::get('currencyPreference', config('firefly.default_currency', 'EUR')));
|
||||
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
|
||||
$request->session()->flash('info', trans('firefly.ask_site_owner', ['owner' => env('SITE_OWNER')]));
|
||||
}
|
||||
|
||||
|
||||
return view('currencies.index', compact('currencies', 'defaultCurrency'));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param CurrencyFormRequest $request
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function store(CurrencyFormRequest $request, CurrencyRepositoryInterface $repository)
|
||||
public function store(CurrencyFormRequest $request)
|
||||
{
|
||||
if (!auth()->user()->hasRole('owner')) {
|
||||
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
Log::error('User ' . auth()->user()->id . ' is not admin, but tried to store a currency.');
|
||||
|
||||
return redirect($this->getPreviousUri('currencies.create.uri'));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$data = $request->getCurrencyData();
|
||||
$currency = $repository->store($data);
|
||||
$currency = $this->repository->store($data);
|
||||
$request->session()->flash('success', trans('firefly.created_currency', ['name' => $currency->name]));
|
||||
|
||||
if (intval($request->get('create_another')) === 1) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('currencies.create.fromStore', true);
|
||||
|
||||
return redirect(route('currencies.create'))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('currencies.create.uri'));
|
||||
@ -212,25 +246,32 @@ class CurrencyController extends Controller
|
||||
|
||||
/**
|
||||
* @param CurrencyFormRequest $request
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function update(CurrencyFormRequest $request, CurrencyRepositoryInterface $repository, TransactionCurrency $currency)
|
||||
public function update(CurrencyFormRequest $request, TransactionCurrency $currency)
|
||||
{
|
||||
$data = $request->getCurrencyData();
|
||||
if (auth()->user()->hasRole('owner')) {
|
||||
$currency = $repository->update($currency, $data);
|
||||
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->flash('error', trans('firefly.ask_site_owner', ['owner' => env('SITE_OWNER')]));
|
||||
|
||||
return redirect(route('currencies.index'));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$data = $request->getCurrencyData();
|
||||
$currency = $this->repository->update($currency, $data);
|
||||
$request->session()->flash('success', trans('firefly.updated_currency', ['name' => $currency->name]));
|
||||
Preferences::mark();
|
||||
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('currencies.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('currencies.edit', [$currency->id]));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('currencies.edit.uri'));
|
||||
|
@ -58,7 +58,7 @@ class HelpController extends Controller
|
||||
return Response::json($content);
|
||||
}
|
||||
|
||||
$content = $help->getFromGithub($language, $route);
|
||||
$content = $help->getFromGithub($route, $language);
|
||||
$notYourLanguage = '<p><em>' . strval(trans('firefly.help_may_not_be_your_language')) . '</em></p>';
|
||||
|
||||
// get backup language content (try English):
|
||||
@ -66,10 +66,10 @@ class HelpController extends Controller
|
||||
$language = 'en_US';
|
||||
if ($help->inCache($route, $language)) {
|
||||
Log::debug(sprintf('Help text %s was in cache.', $language));
|
||||
$content = $help->getFromCache($route, $language);
|
||||
$content = $notYourLanguage . $help->getFromCache($route, $language);
|
||||
}
|
||||
if (!$help->inCache($route, $language)) {
|
||||
$content = trim($notYourLanguage . $help->getFromGithub($language, $route));
|
||||
$content = trim($notYourLanguage . $help->getFromGithub($route, $language));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ use FireflyIII\Import\Setup\SetupInterface;
|
||||
use FireflyIII\Models\ImportJob;
|
||||
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response as LaravelResponse;
|
||||
use Log;
|
||||
@ -87,8 +88,6 @@ class ImportController extends Controller
|
||||
{
|
||||
Log::debug('Now at start of configure()');
|
||||
if (!$this->jobInCorrectStep($job, 'configure')) {
|
||||
Log::debug('Job is not in correct state for configure()', ['status' => $job->status]);
|
||||
|
||||
return $this->redirectToCorrectStep($job);
|
||||
}
|
||||
|
||||
@ -100,8 +99,6 @@ class ImportController extends Controller
|
||||
$subTitleIcon = 'fa-wrench';
|
||||
|
||||
return view('import.' . $job->file_type . '.configure', compact('data', 'job', 'subTitle', 'subTitleIcon'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,8 +142,6 @@ class ImportController extends Controller
|
||||
public function finished(ImportJob $job)
|
||||
{
|
||||
if (!$this->jobInCorrectStep($job, 'finished')) {
|
||||
Log::debug('Job is not in correct state for finished()', ['status' => $job->status]);
|
||||
|
||||
return $this->redirectToCorrectStep($job);
|
||||
}
|
||||
|
||||
@ -225,12 +220,12 @@ class ImportController extends Controller
|
||||
* Step 4. Save the configuration.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param ImportJobRepositoryInterface $repository
|
||||
* @param ImportJob $job
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function postConfigure(Request $request, ImportJob $job)
|
||||
public function postConfigure(Request $request, ImportJobRepositoryInterface $repository, ImportJob $job)
|
||||
{
|
||||
Log::debug('Now in postConfigure()', ['job' => $job->key]);
|
||||
if (!$this->jobInCorrectStep($job, 'process')) {
|
||||
@ -245,8 +240,7 @@ class ImportController extends Controller
|
||||
$importer->saveImportConfiguration($data, $files);
|
||||
|
||||
// update job:
|
||||
$job->status = 'import_configuration_saved';
|
||||
$job->save();
|
||||
$repository->updateStatus($job, 'import_configuration_saved');
|
||||
|
||||
// return redirect to settings.
|
||||
// this could loop until the user is done.
|
||||
@ -285,12 +279,10 @@ class ImportController extends Controller
|
||||
* @return View
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function settings(ImportJob $job)
|
||||
public function settings(ImportJobRepositoryInterface $repository, ImportJob $job)
|
||||
{
|
||||
Log::debug('Now in settings()', ['job' => $job->key]);
|
||||
if (!$this->jobInCorrectStep($job, 'settings')) {
|
||||
Log::debug('Job should not be in settings()');
|
||||
|
||||
return $this->redirectToCorrectStep($job);
|
||||
}
|
||||
Log::debug('Continue in settings()');
|
||||
@ -308,8 +300,7 @@ class ImportController extends Controller
|
||||
}
|
||||
Log::debug('Job does NOT require user config.');
|
||||
|
||||
$job->status = 'settings_complete';
|
||||
$job->save();
|
||||
$repository->updateStatus($job, 'settings_complete');
|
||||
|
||||
// if no more settings, save job and continue to process thing.
|
||||
return redirect(route('import.complete', [$job->key]));
|
||||
@ -350,15 +341,17 @@ class ImportController extends Controller
|
||||
return view('import.status', compact('job', 'subTitle', 'subTitleIcon'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is step 2. It creates an Import Job. Stores the import.
|
||||
*
|
||||
* @param ImportUploadRequest $request
|
||||
* @param ImportJobRepositoryInterface $repository
|
||||
* @param UserRepositoryInterface $userRepository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function upload(ImportUploadRequest $request, ImportJobRepositoryInterface $repository)
|
||||
public function upload(ImportUploadRequest $request, ImportJobRepositoryInterface $repository, UserRepositoryInterface $userRepository)
|
||||
{
|
||||
Log::debug('Now in upload()');
|
||||
// create import job:
|
||||
@ -375,7 +368,7 @@ class ImportController extends Controller
|
||||
$disk = Storage::disk('upload');
|
||||
|
||||
// user is demo user, replace upload with prepared file.
|
||||
if (auth()->user()->hasRole('demo')) {
|
||||
if ($userRepository->hasRole(auth()->user(), 'demo')) {
|
||||
$stubsDisk = Storage::disk('stubs');
|
||||
$content = $stubsDisk->get('demo-import.csv');
|
||||
$contentEncrypted = Crypt::encrypt($content);
|
||||
@ -384,14 +377,13 @@ class ImportController extends Controller
|
||||
|
||||
// also set up prepared configuration.
|
||||
$configuration = json_decode($stubsDisk->get('demo-configuration.json'), true);
|
||||
$job->configuration = $configuration;
|
||||
$job->save();
|
||||
$repository->setConfiguration($job, $configuration);
|
||||
Log::debug('Set configuration for demo user', $configuration);
|
||||
|
||||
// also flash info
|
||||
Session::flash('info', trans('demo.import-configure-security'));
|
||||
}
|
||||
if (!auth()->user()->hasRole('demo')) {
|
||||
if (!$userRepository->hasRole(auth()->user(), 'demo')) {
|
||||
// user is not demo, process original upload:
|
||||
$disk->put($newName, $contentEncrypted);
|
||||
Log::debug('Uploaded file', ['name' => $upload->getClientOriginalName(), 'size' => $upload->getSize(), 'mime' => $upload->getClientMimeType()]);
|
||||
@ -411,18 +403,15 @@ class ImportController extends Controller
|
||||
$configRaw = $configFileObject->fread($configFileObject->getSize());
|
||||
$configuration = json_decode($configRaw, true);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if (!is_null($configuration) && is_array($configuration)) {
|
||||
Log::debug('Found configuration', $configuration);
|
||||
$job->configuration = $configuration;
|
||||
$job->save();
|
||||
$repository->setConfiguration($job, $configuration);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// if user is demo user, replace config with prepared config:
|
||||
|
||||
|
||||
return redirect(route('import.configure', [$job->key]));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -440,6 +429,8 @@ class ImportController extends Controller
|
||||
return $job->status === 'import_status_never_started';
|
||||
case 'settings':
|
||||
case 'store-settings':
|
||||
Log::debug(sprintf('Job %d with key %s has status %s', $job->id, $job->key, $job->status));
|
||||
|
||||
return $job->status === 'import_configuration_saved';
|
||||
case 'finished':
|
||||
return $job->status === 'import_complete';
|
||||
@ -449,7 +440,7 @@ class ImportController extends Controller
|
||||
return ($job->status === 'settings_complete') || ($job->status === 'import_running');
|
||||
}
|
||||
|
||||
return false;
|
||||
return false; // @codeCoverageIgnore
|
||||
|
||||
}
|
||||
|
||||
@ -475,7 +466,7 @@ class ImportController extends Controller
|
||||
|
||||
return $importer;
|
||||
}
|
||||
throw new FireflyException(sprintf('"%s" is not a valid file type', $type));
|
||||
throw new FireflyException(sprintf('"%s" is not a valid file type', $type)); // @codeCoverageIgnore
|
||||
|
||||
}
|
||||
|
||||
@ -507,7 +498,7 @@ class ImportController extends Controller
|
||||
return redirect(route('import.finished', [$job->key]));
|
||||
}
|
||||
|
||||
throw new FireflyException('Cannot redirect for job state ' . $job->status);
|
||||
throw new FireflyException('Cannot redirect for job state ' . $job->status); // @codeCoverageIgnore
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ class JavascriptController extends Controller
|
||||
|
||||
switch ($viewRange) {
|
||||
default:
|
||||
throw new FireflyException('The date picker does not yet support "' . $viewRange . '".');
|
||||
throw new FireflyException('The date picker does not yet support "' . $viewRange . '".'); // @codeCoverageIgnore
|
||||
case '1D':
|
||||
case 'custom':
|
||||
$format = (string)trans('config.month_and_day');
|
||||
|
@ -287,7 +287,7 @@ class JsonController extends Controller
|
||||
{
|
||||
$pref = Preferences::get('tour', true);
|
||||
if (!$pref) {
|
||||
throw new FireflyException('Cannot find preference for tour. Exit.');
|
||||
throw new FireflyException('Cannot find preference for tour. Exit.'); // @codeCoverageIgnore
|
||||
}
|
||||
$headers = ['main-content', 'sidebar-toggle', 'account-menu', 'budget-menu', 'report-menu', 'transaction-menu', 'option-menu', 'main-content-end'];
|
||||
$steps = [];
|
||||
|
@ -229,7 +229,8 @@ class PiggyBankController extends Controller
|
||||
'sumOfTargets' => $piggyBank->targetamount,
|
||||
'leftToSave' => $piggyBank->leftToSave,
|
||||
];
|
||||
} else {
|
||||
}
|
||||
if (isset($accounts[$account->id])) {
|
||||
$accounts[$account->id]['sumOfSaved'] = bcadd($accounts[$account->id]['sumOfSaved'], strval($piggyBank->savedSoFar));
|
||||
$accounts[$account->id]['sumOfTargets'] = bcadd($accounts[$account->id]['sumOfTargets'], $piggyBank->targetamount);
|
||||
$accounts[$account->id]['leftToSave'] = bcadd($accounts[$account->id]['leftToSave'], $piggyBank->leftToSave);
|
||||
@ -272,32 +273,16 @@ class PiggyBankController extends Controller
|
||||
public function postAdd(Request $request, PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
|
||||
{
|
||||
$amount = $request->get('amount');
|
||||
Log::debug(sprintf('Found amount is %s', $amount));
|
||||
/** @var Carbon $date */
|
||||
$date = session('end', Carbon::now()->endOfMonth());
|
||||
$leftOnAccount = $piggyBank->leftOnAccount($date);
|
||||
$savedSoFar = strval($piggyBank->currentRelevantRep()->currentamount);
|
||||
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
|
||||
$maxAmount = strval(min(round($leftOnAccount, 12), round($leftToSave, 12)));
|
||||
|
||||
if (bccomp($amount, $maxAmount) <= 0) {
|
||||
$repetition = $piggyBank->currentRelevantRep();
|
||||
$currentAmount = $repetition->currentamount ?? '0';
|
||||
$repetition->currentamount = bcadd($currentAmount, $amount);
|
||||
$repetition->save();
|
||||
|
||||
// create event
|
||||
$repository->createEvent($piggyBank, $amount);
|
||||
|
||||
Session::flash(
|
||||
'success', strval(trans('firefly.added_amount_to_piggy', ['amount' => Amount::format($amount, false), 'name' => $piggyBank->name]))
|
||||
);
|
||||
if ($repository->canAddAmount($piggyBank, $amount)) {
|
||||
$repository->addAmount($piggyBank, $amount);
|
||||
Session::flash('success', strval(trans('firefly.added_amount_to_piggy', ['amount' => Amount::format($amount, false), 'name' => $piggyBank->name])));
|
||||
Preferences::mark();
|
||||
|
||||
return redirect(route('piggy-banks.index'));
|
||||
}
|
||||
|
||||
Log::error('Cannot add ' . $amount . ' because max amount is ' . $maxAmount . ' (left on account is ' . $leftOnAccount . ')');
|
||||
Log::error('Cannot add ' . $amount . ' because canAddAmount returned false.');
|
||||
Session::flash('error', strval(trans('firefly.cannot_add_amount_piggy', ['amount' => Amount::format($amount, false), 'name' => e($piggyBank->name)])));
|
||||
|
||||
return redirect(route('piggy-banks.index'));
|
||||
@ -312,26 +297,24 @@ class PiggyBankController extends Controller
|
||||
*/
|
||||
public function postRemove(Request $request, PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
|
||||
{
|
||||
$amount = strval(round($request->get('amount'), 12));
|
||||
|
||||
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
|
||||
|
||||
if (bccomp($amount, $savedSoFar) <= 0) {
|
||||
$repetition = $piggyBank->currentRelevantRep();
|
||||
$repetition->currentamount = bcsub($repetition->currentamount, $amount);
|
||||
$repetition->save();
|
||||
|
||||
// create event
|
||||
$repository->createEvent($piggyBank, bcmul($amount, '-1'));
|
||||
|
||||
$amount = $request->get('amount');
|
||||
if ($repository->canRemoveAmount($piggyBank, $amount)) {
|
||||
$repository->removeAmount($piggyBank, $amount);
|
||||
Session::flash(
|
||||
'success', strval(trans('firefly.removed_amount_from_piggy', ['amount' => Amount::format($amount, false), 'name' => e($piggyBank->name)]))
|
||||
'success', strval(trans('firefly.removed_amount_from_piggy', ['amount' => Amount::format($amount, false), 'name' => $piggyBank->name]))
|
||||
);
|
||||
Preferences::mark();
|
||||
|
||||
return redirect(route('piggy-banks.index'));
|
||||
}
|
||||
|
||||
|
||||
$amount = strval(round($request->get('amount'), 12));
|
||||
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
|
||||
|
||||
if (bccomp($amount, $savedSoFar) <= 0) {
|
||||
}
|
||||
|
||||
Session::flash('error', strval(trans('firefly.cannot_remove_from_piggy', ['amount' => Amount::format($amount, false), 'name' => e($piggyBank->name)])));
|
||||
|
||||
return redirect(route('piggy-banks.index'));
|
||||
@ -391,9 +374,11 @@ class PiggyBankController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('create_another')) === 1) {
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('piggy-banks.create.fromStore', true);
|
||||
|
||||
return redirect(route('piggy-banks.create'))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('piggy-banks.edit.uri'));
|
||||
@ -415,9 +400,11 @@ class PiggyBankController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('piggy-banks.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('piggy-banks.edit', [$piggyBank->id]));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('piggy-banks.edit.uri'));
|
||||
|
@ -17,17 +17,14 @@ namespace FireflyIII\Http\Controllers\Popup;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collection\BalanceLine;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Report\PopupReportInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Support\Binder\AccountList;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use InvalidArgumentException;
|
||||
use Response;
|
||||
use View;
|
||||
@ -40,6 +37,44 @@ use View;
|
||||
class ReportController extends Controller
|
||||
{
|
||||
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $accountRepository;
|
||||
/** @var BudgetRepositoryInterface */
|
||||
private $budgetRepository;
|
||||
/** @var CategoryRepositoryInterface */
|
||||
private $categoryRepository;
|
||||
/** @var PopupReportInterface */
|
||||
private $popupHelper;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
|
||||
/** @var BudgetRepositoryInterface $repository */
|
||||
$this->budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
/** @var CategoryRepositoryInterface categoryRepository */
|
||||
$this->categoryRepository = app(CategoryRepositoryInterface::class);
|
||||
|
||||
/** @var PopupReportInterface popupHelper */
|
||||
$this->popupHelper = app(PopupReportInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
@ -59,7 +94,6 @@ class ReportController extends Controller
|
||||
throw new FireflyException('Firefly cannot handle "' . e($attributes['location']) . '" ');
|
||||
case 'budget-spent-amount':
|
||||
$html = $this->budgetSpentAmount($attributes);
|
||||
|
||||
break;
|
||||
case 'expense-entry':
|
||||
$html = $this->expenseEntry($attributes);
|
||||
@ -89,62 +123,25 @@ class ReportController extends Controller
|
||||
private function balanceAmount(array $attributes): string
|
||||
{
|
||||
$role = intval($attributes['role']);
|
||||
|
||||
/** @var BudgetRepositoryInterface $budgetRepository */
|
||||
$budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$budget = $budgetRepository->find(intval($attributes['budgetId']));
|
||||
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
$account = $repository->find(intval($attributes['accountId']));
|
||||
$types = [TransactionType::WITHDRAWAL];
|
||||
$budget = $this->budgetRepository->find(intval($attributes['budgetId']));
|
||||
$account = $this->accountRepository->find(intval($attributes['accountId']));
|
||||
|
||||
switch (true) {
|
||||
case ($role === BalanceLine::ROLE_DEFAULTROLE && !is_null($budget->id)):
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->setBudget($budget);
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
// normal row with a budget:
|
||||
$journals = $this->popupHelper->balanceForBudget($budget, $account, $attributes);
|
||||
break;
|
||||
case ($role === BalanceLine::ROLE_DEFAULTROLE && is_null($budget->id)):
|
||||
// normal row without a budget:
|
||||
$journals = $this->popupHelper->balanceForNoBudget($account, $attributes);
|
||||
$budget->name = strval(trans('firefly.no_budget'));
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setTypes($types)
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->withoutBudget();
|
||||
$journals = $collector->getJournals();
|
||||
break;
|
||||
case ($role === BalanceLine::ROLE_DIFFROLE):
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setTypes($types)
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->withoutBudget();
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
$journals = $this->popupHelper->balanceDifference($account, $attributes);
|
||||
$budget->name = strval(trans('firefly.leftUnbalanced'));
|
||||
$journals = $journals->filter(
|
||||
function (Transaction $transaction) {
|
||||
$tags = $transaction->transactionJournal->tags()->where('tagMode', 'balancingAct')->count();
|
||||
if ($tags === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
break;
|
||||
case ($role === BalanceLine::ROLE_TAGROLE):
|
||||
// row with tag info.
|
||||
throw new FireflyException('Firefly cannot handle this type of info-button (BalanceLine::TagRole)');
|
||||
}
|
||||
$view = view('popup.report.balance-amount', compact('journals', 'budget', 'account'))->render();
|
||||
@ -162,27 +159,8 @@ class ReportController extends Controller
|
||||
*/
|
||||
private function budgetSpentAmount(array $attributes): string
|
||||
{
|
||||
// need to find the budget
|
||||
// then search for expenses in the given period
|
||||
// list them in some table format.
|
||||
/** @var BudgetRepositoryInterface $repository */
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
$budget = $repository->find(intval($attributes['budgetId']));
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
|
||||
$collector
|
||||
->setAccounts($attributes['accounts'])
|
||||
->setRange($attributes['startDate'], $attributes['endDate']);
|
||||
|
||||
if (is_null($budget->id)) {
|
||||
$collector->setTypes([TransactionType::WITHDRAWAL])->withoutBudget();
|
||||
}
|
||||
if (!is_null($budget->id)) {
|
||||
// get all expenses in budget in period:
|
||||
$collector->setBudget($budget);
|
||||
}
|
||||
$journals = $collector->getJournals();
|
||||
$budget = $this->budgetRepository->find(intval($attributes['budgetId']));
|
||||
$journals = $this->popupHelper->byBudget($budget, $attributes);
|
||||
$view = view('popup.report.budget-spent-amount', compact('journals', 'budget'))->render();
|
||||
|
||||
return $view;
|
||||
@ -198,17 +176,8 @@ class ReportController extends Controller
|
||||
*/
|
||||
private function categoryEntry(array $attributes): string
|
||||
{
|
||||
/** @var CategoryRepositoryInterface $repository */
|
||||
$repository = app(CategoryRepositoryInterface::class);
|
||||
$category = $repository->find(intval($attributes['categoryId']));
|
||||
$types = [TransactionType::WITHDRAWAL, TransactionType::TRANSFER];
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts($attributes['accounts'])->setTypes($types)
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->setCategory($category);
|
||||
$journals = $collector->getJournals(); // 7193
|
||||
|
||||
$category = $this->categoryRepository->find(intval($attributes['categoryId']));
|
||||
$journals = $this->popupHelper->byCategory($category, $attributes);
|
||||
$view = view('popup.report.category-entry', compact('journals', 'category'))->render();
|
||||
|
||||
return $view;
|
||||
@ -224,28 +193,8 @@ class ReportController extends Controller
|
||||
*/
|
||||
private function expenseEntry(array $attributes): string
|
||||
{
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
$account = $repository->find(intval($attributes['accountId']));
|
||||
$types = [TransactionType::WITHDRAWAL, TransactionType::TRANSFER];
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])->setTypes($types);
|
||||
$journals = $collector->getJournals();
|
||||
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
|
||||
|
||||
// filter for transfers and withdrawals TO the given $account
|
||||
$journals = $journals->filter(
|
||||
function (Transaction $transaction) use ($report) {
|
||||
// get the destinations:
|
||||
$sources = $transaction->transactionJournal->sourceAccountList()->pluck('id')->toArray();
|
||||
|
||||
// do these intersect with the current list?
|
||||
return !empty(array_intersect($report, $sources));
|
||||
}
|
||||
);
|
||||
|
||||
$account = $this->accountRepository->find(intval($attributes['accountId']));
|
||||
$journals = $this->popupHelper->byExpenses($account, $attributes);
|
||||
$view = view('popup.report.expense-entry', compact('journals', 'account'))->render();
|
||||
|
||||
return $view;
|
||||
@ -261,27 +210,8 @@ class ReportController extends Controller
|
||||
*/
|
||||
private function incomeEntry(array $attributes): string
|
||||
{
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$account = $repository->find(intval($attributes['accountId']));
|
||||
$types = [TransactionType::DEPOSIT, TransactionType::TRANSFER];
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])->setTypes($types);
|
||||
$journals = $collector->getJournals();
|
||||
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
|
||||
|
||||
// filter the set so the destinations outside of $attributes['accounts'] are not included.
|
||||
$journals = $journals->filter(
|
||||
function (Transaction $transaction) use ($report) {
|
||||
// get the destinations:
|
||||
$destinations = $transaction->destinationAccountList($transaction->transactionJournal)->pluck('id')->toArray();
|
||||
|
||||
// do these intersect with the current list?
|
||||
return !empty(array_intersect($report, $destinations));
|
||||
}
|
||||
);
|
||||
|
||||
$account = $this->accountRepository->find(intval($attributes['accountId']));
|
||||
$journals = $this->popupHelper->byIncome($account, $attributes);
|
||||
$view = view('popup.report.income-entry', compact('journals', 'account'))->render();
|
||||
|
||||
return $view;
|
||||
|
@ -10,11 +10,13 @@
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use FireflyIII\Http\Requests\TokenFormRequest;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
use PragmaRX\Google2FA\Contracts\Google2FA;
|
||||
use Preferences;
|
||||
@ -55,8 +57,11 @@ class PreferencesController extends Controller
|
||||
public function code(Google2FA $google2fa)
|
||||
{
|
||||
$domain = $this->getDomain();
|
||||
$secretKey = 'FIREFLYIII';
|
||||
$secretKey = str_pad($secretKey, intval(pow(2, ceil(log(strlen($secretKey), 2)))), 'X');
|
||||
|
||||
/** @noinspection PhpMethodParametersCountMismatchInspection */
|
||||
$secret = $google2fa->generateSecretKey(32, auth()->user()->id);
|
||||
$secret = $google2fa->generateSecretKey(16, $secretKey);
|
||||
Session::flash('two-factor-secret', $secret);
|
||||
$image = $google2fa->getQRCodeInline('Firefly III at ' . $domain, auth()->user()->email, $secret, 150);
|
||||
|
||||
@ -131,7 +136,7 @@ class PreferencesController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function postIndex(Request $request)
|
||||
public function postIndex(Request $request, UserRepositoryInterface $repository)
|
||||
{
|
||||
// front page accounts
|
||||
$frontPageAccounts = [];
|
||||
@ -160,16 +165,15 @@ class PreferencesController extends Controller
|
||||
Preferences::set('showDepositsFrontpage', $showDepositsFrontpage);
|
||||
|
||||
// save page size:
|
||||
Preferences::set('transactionPageSize', 50);
|
||||
$transactionPageSize = intval($request->get('transactionPageSize'));
|
||||
if ($transactionPageSize > 0 && $transactionPageSize < 1337) {
|
||||
Preferences::set('transactionPageSize', $transactionPageSize);
|
||||
} else {
|
||||
Preferences::set('transactionPageSize', 50);
|
||||
}
|
||||
|
||||
$twoFactorAuthEnabled = false;
|
||||
$hasTwoFactorAuthSecret = false;
|
||||
if (!auth()->user()->hasRole('demo')) {
|
||||
if (!$repository->hasRole(auth()->user(), 'demo')) {
|
||||
// two factor auth
|
||||
$twoFactorAuthEnabled = intval($request->get('twoFactorAuthEnabled'));
|
||||
$hasTwoFactorAuthSecret = !is_null(Preferences::get('twoFactorAuthSecret'));
|
||||
|
@ -14,9 +14,11 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use FireflyIII\Exceptions\ValidationException;
|
||||
use FireflyIII\Http\Middleware\IsLimitedUser;
|
||||
use FireflyIII\Http\Requests\DeleteAccountFormRequest;
|
||||
use FireflyIII\Http\Requests\ProfileFormRequest;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Hash;
|
||||
use Log;
|
||||
use Session;
|
||||
@ -45,6 +47,8 @@ class ProfileController extends Controller
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
$this->middleware(IsLimitedUser::class);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,16 +56,6 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function changePassword()
|
||||
{
|
||||
if (intval(getenv('SANDSTORM')) === 1) {
|
||||
return view('error')->with('message', strval(trans('firefly.sandstorm_not_available')));
|
||||
}
|
||||
|
||||
if (auth()->user()->hasRole('demo')) {
|
||||
Session::flash('info', strval(trans('firefly.cannot_change_demo')));
|
||||
|
||||
return redirect(route('profile.index'));
|
||||
}
|
||||
|
||||
$title = auth()->user()->email;
|
||||
$subTitle = strval(trans('firefly.change_your_password'));
|
||||
$subTitleIcon = 'fa-key';
|
||||
@ -74,16 +68,6 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function deleteAccount()
|
||||
{
|
||||
if (intval(getenv('SANDSTORM')) === 1) {
|
||||
return view('error')->with('message', strval(trans('firefly.sandstorm_not_available')));
|
||||
}
|
||||
|
||||
if (auth()->user()->hasRole('demo')) {
|
||||
Session::flash('info', strval(trans('firefly.cannot_delete_demo')));
|
||||
|
||||
return redirect(route('profile.index'));
|
||||
}
|
||||
|
||||
$title = auth()->user()->email;
|
||||
$subTitle = strval(trans('firefly.delete_account'));
|
||||
$subTitleIcon = 'fa-trash';
|
||||
@ -111,32 +95,18 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function postChangePassword(ProfileFormRequest $request, UserRepositoryInterface $repository)
|
||||
{
|
||||
if (intval(getenv('SANDSTORM')) === 1) {
|
||||
return view('error')->with('message', strval(trans('firefly.sandstorm_not_available')));
|
||||
}
|
||||
|
||||
if (auth()->user()->hasRole('demo')) {
|
||||
Session::flash('info', strval(trans('firefly.cannot_change_demo')));
|
||||
|
||||
return redirect(route('profile.index'));
|
||||
}
|
||||
|
||||
// old, new1, new2
|
||||
if (!Hash::check($request->get('current_password'), auth()->user()->password)) {
|
||||
Session::flash('error', strval(trans('firefly.invalid_current_password')));
|
||||
|
||||
return redirect(route('profile.change-password'));
|
||||
}
|
||||
// the request has already validated both new passwords must be equal.
|
||||
$current = $request->get('current_password');
|
||||
$new = $request->get('new_password');
|
||||
|
||||
try {
|
||||
$this->validatePassword($request->get('current_password'), $request->get('new_password'));
|
||||
$this->validatePassword(auth()->user(), $current, $new);
|
||||
} catch (ValidationException $e) {
|
||||
Session::flash('error', $e->getMessage());
|
||||
|
||||
return redirect(route('profile.change-password'));
|
||||
}
|
||||
|
||||
// update the user with the new password.
|
||||
$repository->changePassword(auth()->user(), $request->get('new_password'));
|
||||
Session::flash('success', strval(trans('firefly.password_changed')));
|
||||
|
||||
@ -151,17 +121,6 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function postDeleteAccount(UserRepositoryInterface $repository, DeleteAccountFormRequest $request)
|
||||
{
|
||||
if (intval(getenv('SANDSTORM')) === 1) {
|
||||
return view('error')->with('message', strval(trans('firefly.sandstorm_not_available')));
|
||||
}
|
||||
|
||||
if (auth()->user()->hasRole('demo')) {
|
||||
Session::flash('info', strval(trans('firefly.cannot_delete_demo')));
|
||||
|
||||
return redirect(route('profile.index'));
|
||||
}
|
||||
|
||||
// old, new1, new2
|
||||
if (!Hash::check($request->get('password'), auth()->user()->password)) {
|
||||
Session::flash('error', strval(trans('firefly.invalid_password')));
|
||||
|
||||
@ -182,15 +141,21 @@ class ProfileController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $old
|
||||
* @param User $user
|
||||
* @param string $current
|
||||
* @param string $new
|
||||
* @param string $newConfirmation
|
||||
*
|
||||
* @return bool
|
||||
* @throws ValidationException
|
||||
*/
|
||||
protected function validatePassword(string $old, string $new): bool
|
||||
protected function validatePassword(User $user, string $current, string $new): bool
|
||||
{
|
||||
if ($new === $old) {
|
||||
if (!Hash::check($current, auth()->user()->password)) {
|
||||
throw new ValidationException(strval(trans('firefly.invalid_current_password')));
|
||||
}
|
||||
|
||||
if ($current === $new) {
|
||||
throw new ValidationException(strval(trans('firefly.should_change')));
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,6 @@ class CategoryController extends Controller
|
||||
$cache->addProperty('category-period-expenses-report');
|
||||
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||
if ($cache->has()) {
|
||||
Log::debug('Return report from cache');
|
||||
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
/** @var CategoryRepositoryInterface $repository */
|
||||
@ -79,8 +77,6 @@ class CategoryController extends Controller
|
||||
$cache->addProperty('category-period-income-report');
|
||||
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||
if ($cache->has()) {
|
||||
Log::debug('Return report from cache');
|
||||
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
/** @var CategoryRepositoryInterface $repository */
|
||||
|
@ -14,7 +14,6 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Generator\Report\ReportGeneratorFactory;
|
||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
||||
use FireflyIII\Http\Requests\ReportFormRequest;
|
||||
@ -26,6 +25,7 @@ use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use Session;
|
||||
@ -48,6 +48,7 @@ class ReportController extends Controller
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->helper = app(ReportHelperInterface::class);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
@ -55,8 +56,6 @@ class ReportController extends Controller
|
||||
View::share('mainTitleIcon', 'fa-line-chart');
|
||||
View::share('subTitleIcon', 'fa-calendar');
|
||||
|
||||
$this->helper = app(ReportHelperInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
@ -73,7 +72,7 @@ class ReportController extends Controller
|
||||
public function auditReport(Collection $accounts, Carbon $start, Carbon $end)
|
||||
{
|
||||
if ($end < $start) {
|
||||
return view('error')->with('message', trans('firefly.end_after_start_date'));
|
||||
return view('error')->with('message', trans('firefly.end_after_start_date')); // @codeCoverageIgnore
|
||||
}
|
||||
if ($start < session('first')) {
|
||||
$start = session('first');
|
||||
@ -109,7 +108,7 @@ class ReportController extends Controller
|
||||
public function budgetReport(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end)
|
||||
{
|
||||
if ($end < $start) {
|
||||
return view('error')->with('message', trans('firefly.end_after_start_date'));
|
||||
return view('error')->with('message', trans('firefly.end_after_start_date')); // @codeCoverageIgnore
|
||||
}
|
||||
if ($start < session('first')) {
|
||||
$start = session('first');
|
||||
@ -145,7 +144,7 @@ class ReportController extends Controller
|
||||
public function categoryReport(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
|
||||
{
|
||||
if ($end < $start) {
|
||||
return view('error')->with('message', trans('firefly.end_after_start_date'));
|
||||
return view('error')->with('message', trans('firefly.end_after_start_date')); // @codeCoverageIgnore
|
||||
}
|
||||
if ($start < session('first')) {
|
||||
$start = session('first');
|
||||
@ -251,10 +250,9 @@ class ReportController extends Controller
|
||||
/**
|
||||
* @param ReportFormRequest $request
|
||||
*
|
||||
* @return RedirectResponse
|
||||
* @throws FireflyException
|
||||
* @return RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function postIndex(ReportFormRequest $request): RedirectResponse
|
||||
public function postIndex(ReportFormRequest $request)
|
||||
{
|
||||
// report type:
|
||||
$reportType = $request->get('report_type');
|
||||
@ -266,6 +264,7 @@ class ReportController extends Controller
|
||||
$tags = join(',', $request->getTagList()->pluck('tag')->toArray());
|
||||
|
||||
if ($request->getAccountList()->count() === 0) {
|
||||
Log::debug('Account count is zero');
|
||||
Session::flash('error', trans('firefly.select_more_than_one_account'));
|
||||
|
||||
return redirect(route('reports.index'));
|
||||
@ -293,14 +292,7 @@ class ReportController extends Controller
|
||||
return view('error')->with('message', trans('firefly.end_after_start_date'));
|
||||
}
|
||||
|
||||
// lower threshold
|
||||
if ($start < session('first')) {
|
||||
$start = session('first');
|
||||
}
|
||||
|
||||
switch ($reportType) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Firefly does not support the "%s"-report yet.', $reportType));
|
||||
case 'category':
|
||||
$uri = route('reports.report.category', [$accounts, $categories, $start, $end]);
|
||||
break;
|
||||
@ -332,7 +324,7 @@ class ReportController extends Controller
|
||||
public function tagReport(Collection $accounts, Collection $tags, Carbon $start, Carbon $end)
|
||||
{
|
||||
if ($end < $start) {
|
||||
return view('error')->with('message', trans('firefly.end_after_start_date'));
|
||||
return view('error')->with('message', trans('firefly.end_after_start_date')); // @codeCoverageIgnore
|
||||
}
|
||||
if ($start < session('first')) {
|
||||
$start = session('first');
|
||||
|
@ -255,10 +255,11 @@ class RuleController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('rules.create.fromStore', true);
|
||||
|
||||
return redirect(route('rules.create', [$ruleGroup]))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('rules.create.uri'));
|
||||
@ -340,10 +341,11 @@ class RuleController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('rules.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('rules.edit', [$rule->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('rules.edit.uri'));
|
||||
@ -473,7 +475,7 @@ class RuleController extends Controller
|
||||
$actions[] = view(
|
||||
'rules.partials.action',
|
||||
[
|
||||
'oldTrigger' => $entry,
|
||||
'oldAction' => $entry,
|
||||
'oldValue' => $request->old('rule-action-value')[$index],
|
||||
'oldChecked' => $checked,
|
||||
'count' => $count,
|
||||
|
@ -217,10 +217,11 @@ class RuleGroupController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('rule-groups.create.fromStore', true);
|
||||
|
||||
return redirect(route('rule-groups.create'))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('rule-groups.create.uri'));
|
||||
@ -261,10 +262,11 @@ class RuleGroupController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('rule-groups.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('rule-groups.edit', [$ruleGroup->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
|
@ -14,15 +14,14 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Http\Requests\TagFormRequest;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
use Session;
|
||||
@ -145,7 +144,7 @@ class TagController extends Controller
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function edit(Tag $tag)
|
||||
public function edit(Tag $tag, TagRepositoryInterface $repository)
|
||||
{
|
||||
$subTitle = trans('firefly.edit_tag', ['tag' => $tag->tag]);
|
||||
$subTitleIcon = 'fa-tag';
|
||||
@ -159,8 +158,8 @@ class TagController extends Controller
|
||||
/*
|
||||
* Can this tag become another type?
|
||||
*/
|
||||
$allowAdvance = $tag->tagAllowAdvance();
|
||||
$allowToBalancingAct = $tag->tagAllowBalancing();
|
||||
$allowAdvance = $repository->tagAllowAdvance($tag);
|
||||
$allowToBalancingAct = $repository->tagAllowBalancing($tag);
|
||||
|
||||
// edit tag options:
|
||||
if ($allowAdvance === false) {
|
||||
@ -223,99 +222,87 @@ class TagController extends Controller
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param JournalCollectorInterface $collector
|
||||
* @param TagRepositoryInterface $repository
|
||||
* @param Tag $tag
|
||||
* @param string $moment
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function show(Request $request, JournalCollectorInterface $collector, Tag $tag)
|
||||
public function show(Request $request, TagRepositoryInterface $repository, Tag $tag, string $moment = '')
|
||||
{
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
// default values:
|
||||
$subTitle = $tag->tag;
|
||||
$subTitleIcon = 'fa-tag';
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$periods = $this->getPeriodOverview($tag);
|
||||
|
||||
// use collector:
|
||||
$collector->setAllAssetAccounts()
|
||||
->setLimit($pageSize)->setPage($page)->setTag($tag)->withOpposingAccount()->disableInternalFilter()
|
||||
->withBudgetInformation()->withCategoryInformation()->setRange($start, $end);
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('tags/show/' . $tag->id);
|
||||
|
||||
$sum = $journals->sum(
|
||||
function (Transaction $transaction) {
|
||||
return $transaction->transaction_amount;
|
||||
}
|
||||
);
|
||||
|
||||
return view('tags.show', compact('tag', 'periods', 'subTitle', 'subTitleIcon', 'journals', 'sum', 'start', 'end'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param JournalCollectorInterface $collector
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function showAll(Request $request, JournalCollectorInterface $collector, Tag $tag)
|
||||
{
|
||||
$subTitle = $tag->tag;
|
||||
$subTitleIcon = 'fa-tag';
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$collector->setAllAssetAccounts()->setLimit($pageSize)->setPage($page)->setTag($tag)
|
||||
->withOpposingAccount()->disableInternalFilter()
|
||||
->withBudgetInformation()->withCategoryInformation();
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('tags/show/' . $tag->id . '/all');
|
||||
|
||||
$sum = $journals->sum(
|
||||
function (Transaction $transaction) {
|
||||
return $transaction->transaction_amount;
|
||||
}
|
||||
);
|
||||
|
||||
return view('tags.show', compact('tag', 'subTitle', 'subTitleIcon', 'journals', 'sum', 'start', 'end'));
|
||||
|
||||
}
|
||||
|
||||
public function showByDate(Request $request, JournalCollectorInterface $collector, Tag $tag, string $date)
|
||||
{
|
||||
$count = 0;
|
||||
$loop = 0;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
|
||||
try {
|
||||
$start = new Carbon($date);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
} catch (Exception $e) {
|
||||
$start = Navigation::startOfPeriod($this->repository->firstUseDate($tag), $range);
|
||||
$end = Navigation::startOfPeriod($this->repository->lastUseDate($tag), $range);
|
||||
|
||||
// prep for "all" view.
|
||||
if ($moment === 'all') {
|
||||
$subTitle = trans('firefly.all_journals_for_tag', ['tag' => $tag->tag]);
|
||||
$start = $repository->firstUseDate($tag);
|
||||
$end = new Carbon;
|
||||
}
|
||||
|
||||
$subTitle = $tag->tag;
|
||||
$subTitleIcon = 'fa-tag';
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
// prep for "specific date" view.
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$start = new Carbon($moment);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_tag',
|
||||
['tag' => $tag->tag,
|
||||
'start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getPeriodOverview($tag);
|
||||
}
|
||||
|
||||
// use collector:
|
||||
$collector->setAllAssetAccounts()
|
||||
->setLimit($pageSize)->setPage($page)->setTag($tag)->withOpposingAccount()->disableInternalFilter()
|
||||
->withBudgetInformation()->withCategoryInformation()->setRange($start, $end);
|
||||
// prep for current period
|
||||
if (strlen($moment) === 0) {
|
||||
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||
$periods = $this->getPeriodOverview($tag);
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_tag',
|
||||
['tag' => $tag->tag, 'start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
// grab journals, but be prepared to jump a period back to get the right ones:
|
||||
Log::info('Now at tag loop start.');
|
||||
while ($count === 0 && $loop < 3) {
|
||||
$loop++;
|
||||
Log::info('Count is zero, search for journals.');
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
|
||||
->setTag($tag)->withBudgetInformation()->withCategoryInformation();
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('tags/show/' . $tag->id);
|
||||
|
||||
$sum = $journals->sum(
|
||||
function (Transaction $transaction) {
|
||||
return $transaction->transaction_amount;
|
||||
$count = $journals->getCollection()->count();
|
||||
if ($count === 0) {
|
||||
$start->subDay();
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
}
|
||||
}
|
||||
|
||||
if ($moment != 'all' && $loop > 1) {
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_tag',
|
||||
['tag' => $tag->tag, 'start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
|
||||
return view('tags.show', compact('tag', 'periods', 'subTitle', 'subTitleIcon', 'journals', 'sum', 'start', 'end'));
|
||||
}
|
||||
$sum = '0';
|
||||
|
||||
return view('tags.show', compact('tag', 'periods', 'subTitle', 'subTitleIcon', 'journals', 'sum', 'start', 'end', 'moment'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param TagFormRequest $request
|
||||
@ -331,10 +318,11 @@ class TagController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('tags.create.fromStore', true);
|
||||
|
||||
return redirect(route('tags.create'))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return redirect($this->getPreviousUri('tags.create.uri'));
|
||||
@ -356,10 +344,11 @@ class TagController extends Controller
|
||||
Preferences::mark();
|
||||
|
||||
if (intval($request->get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('tags.edit.fromUpdate', true);
|
||||
|
||||
return redirect(route('tags.edit', [$tag->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
@ -396,9 +385,9 @@ class TagController extends Controller
|
||||
|
||||
// get expenses and what-not in this period and this tag.
|
||||
$arr = [
|
||||
'date_string' => $end->format('Y-m-d'),
|
||||
'date_name' => Navigation::periodShow($end, $range),
|
||||
'date' => $end,
|
||||
'string' => $end->format('Y-m-d'),
|
||||
'name' => Navigation::periodShow($end, $range),
|
||||
'date' => clone $end,
|
||||
'spent' => $this->repository->spentInperiod($tag, $end, $currentEnd),
|
||||
'earned' => $this->repository->earnedInperiod($tag, $end, $currentEnd),
|
||||
];
|
||||
|
@ -173,7 +173,6 @@ class ConvertController extends Controller
|
||||
$joined = $sourceType->type . '-' . $destinationType->type;
|
||||
switch ($joined) {
|
||||
default:
|
||||
|
||||
throw new FireflyException('Cannot handle ' . $joined); // @codeCoverageIgnore
|
||||
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT: // one
|
||||
$destination = $sourceAccount;
|
||||
|
@ -14,13 +14,13 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Http\Controllers\Transaction;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use ExpandedForm;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\MassDeleteJournalRequest;
|
||||
use FireflyIII\Http\Requests\MassEditJournalRequest;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
@ -119,7 +119,12 @@ class MassController extends Controller
|
||||
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$accountList = ExpandedForm::makeSelectList($repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]));
|
||||
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||
|
||||
// get budgets
|
||||
/** @var BudgetRepositoryInterface $budgetRepository */
|
||||
$budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$budgets = $budgetRepository->getBudgets();
|
||||
|
||||
// skip transactions that have multiple destinations
|
||||
// or multiple sources:
|
||||
@ -177,7 +182,7 @@ class MassController extends Controller
|
||||
|
||||
$journals = $filtered;
|
||||
|
||||
return view('transactions.mass.edit', compact('journals', 'subTitle', 'accountList'));
|
||||
return view('transactions.mass.edit', compact('journals', 'subTitle', 'accounts', 'budgets'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,7 +205,7 @@ class MassController extends Controller
|
||||
$sourceAccountName = $request->get('source_account_name')[$journal->id] ?? '';
|
||||
$destAccountId = $request->get('destination_account_id')[$journal->id] ?? 0;
|
||||
$destAccountName = $request->get('destination_account_name')[$journal->id] ?? '';
|
||||
$budgetId = $journal->budgets->first() ? $journal->budgets->first()->id : 0;
|
||||
$budgetId = $request->get('budget_id')[$journal->id] ?? 0;
|
||||
$category = $request->get('category')[$journal->id];
|
||||
$tags = $journal->tags->pluck('tag')->toArray();
|
||||
|
||||
@ -214,12 +219,12 @@ class MassController extends Controller
|
||||
'destination_account_id' => intval($destAccountId),
|
||||
'destination_account_name' => $destAccountName,
|
||||
'amount' => round($request->get('amount')[$journal->id], 12),
|
||||
'currency_id' => intval($request->get('amount_currency_id_amount_' . $journal->id)),
|
||||
'currency_id' => $journal->transaction_currency_id,
|
||||
'date' => new Carbon($request->get('date')[$journal->id]),
|
||||
'interest_date' => $journal->interest_date,
|
||||
'book_date' => $journal->book_date,
|
||||
'process_date' => $journal->process_date,
|
||||
'budget_id' => $budgetId,
|
||||
'budget_id' => intval($budgetId),
|
||||
'category' => $category,
|
||||
'tags' => $tags,
|
||||
|
||||
|
@ -14,16 +14,19 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalTaskerInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use Steam;
|
||||
use View;
|
||||
|
||||
/**
|
||||
@ -59,109 +62,77 @@ class TransactionController extends Controller
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function index(Request $request, JournalRepositoryInterface $repository, string $what)
|
||||
public function index(Request $request, JournalRepositoryInterface $repository, string $what, string $moment = '')
|
||||
{
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
// default values:
|
||||
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $what);
|
||||
$types = config('firefly.transactionTypesByWhat.' . $what);
|
||||
$subTitle = trans('firefly.title_' . $what);
|
||||
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$count = 0;
|
||||
$loop = 0;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
// to make sure we only grab a subset, based on the current date (in session):
|
||||
$start = session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||
$end = session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setTypes($types)->setLimit($pageSize)->setPage($page)->setAllAssetAccounts()->setRange($start, $end)->withBudgetInformation()
|
||||
->withCategoryInformation();
|
||||
$collector->withOpposingAccount();
|
||||
$collector->disableInternalFilter();
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('transactions/' . $what);
|
||||
|
||||
unset($start, $end);
|
||||
|
||||
// then also show a list of periods where the user can click on, based on the
|
||||
// user's range and the oldest journal the user has:
|
||||
// prep for "all" view.
|
||||
if ($moment === 'all') {
|
||||
$subTitle = trans('firefly.all_' . $what);
|
||||
$first = $repository->first();
|
||||
$blockStart = is_null($first->id) ? new Carbon : $first->date;
|
||||
$blockStart = Navigation::startOfPeriod($blockStart, $range);
|
||||
$blockEnd = Navigation::endOfX(new Carbon, $range);
|
||||
$entries = new Collection;
|
||||
|
||||
while ($blockEnd >= $blockStart) {
|
||||
Log::debug(sprintf('Now at blockEnd: %s', $blockEnd->format('Y-m-d')));
|
||||
$blockEnd = Navigation::startOfPeriod($blockEnd, $range);
|
||||
$dateStr = $blockEnd->format('Y-m-d');
|
||||
$dateName = Navigation::periodShow($blockEnd, $range);
|
||||
$entries->push([$dateStr, $dateName]);
|
||||
$blockEnd = Navigation::subtractPeriod($blockEnd, $range, 1);
|
||||
$start = $first->date ?? new Carbon;
|
||||
$end = new Carbon;
|
||||
}
|
||||
|
||||
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals', 'entries'));
|
||||
|
||||
// prep for "specific date" view.
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$start = new Carbon($moment);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
$subTitle = trans(
|
||||
'firefly.title_' . $what . '_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getPeriodOverview($what);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param string $what
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function indexAll(Request $request, string $what)
|
||||
{
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $what);
|
||||
$types = config('firefly.transactionTypesByWhat.' . $what);
|
||||
$subTitle = sprintf('%s (%s)', trans('firefly.title_' . $what), strtolower(trans('firefly.everything')));
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
|
||||
// prep for current period
|
||||
if (strlen($moment) === 0) {
|
||||
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||
$periods = $this->getPeriodOverview($what);
|
||||
$subTitle = trans(
|
||||
'firefly.title_' . $what . '_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
// grab journals, but be prepared to jump a period back to get the right ones:
|
||||
Log::info('Now at transaction loop start.');
|
||||
while ($count === 0 && $loop < 3) {
|
||||
$loop++;
|
||||
Log::info('Count is zero, search for journals.');
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setTypes($types)->setLimit($pageSize)->setPage($page)->setAllAssetAccounts()->withBudgetInformation()->withCategoryInformation();
|
||||
$collector->withOpposingAccount();
|
||||
$collector->disableInternalFilter();
|
||||
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes($types)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
|
||||
->disableInternalFilter();
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('transactions/' . $what . '/all');
|
||||
|
||||
return view('transactions.index-all', compact('subTitle', 'what', 'subTitleIcon', 'journals'));
|
||||
|
||||
$journals->setPath('/budgets/list/no-budget');
|
||||
$count = $journals->getCollection()->count();
|
||||
if ($count === 0) {
|
||||
$start->subDay();
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfPeriod($start, $range);
|
||||
Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param string $what
|
||||
*
|
||||
* @param string $date
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function indexByDate(Request $request, string $what, string $date)
|
||||
{
|
||||
$carbon = new Carbon($date);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($carbon, $range);
|
||||
$end = Navigation::endOfPeriod($carbon, $range);
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $what);
|
||||
$types = config('firefly.transactionTypesByWhat.' . $what);
|
||||
$subTitle = trans('firefly.title_' . $what) . ' (' . Navigation::periodShow($carbon, $range) . ')';
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
if ($moment != 'all' && $loop > 1) {
|
||||
$subTitle = trans(
|
||||
'firefly.title_' . $what . '_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Transaction index by date will show between %s and %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setTypes($types)->setLimit($pageSize)->setPage($page)->setAllAssetAccounts();
|
||||
$collector->setRange($start, $end)->withBudgetInformation()->withCategoryInformation();
|
||||
$collector->withOpposingAccount();
|
||||
$collector->disableInternalFilter();
|
||||
$journals = $collector->getPaginatedJournals();
|
||||
$journals->setPath('transactions/' . $what . '/' . $date);
|
||||
|
||||
return view('transactions.index-date', compact('subTitle', 'what', 'subTitleIcon', 'journals', 'carbon'));
|
||||
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals', 'periods', 'start', 'end', 'moment'));
|
||||
|
||||
}
|
||||
|
||||
@ -180,10 +151,9 @@ class TransactionController extends Controller
|
||||
$ids = array_unique($ids);
|
||||
foreach ($ids as $id) {
|
||||
$journal = $repository->find(intval($id));
|
||||
if ($journal && $journal->date->format('Y-m-d') == $date->format('Y-m-d')) {
|
||||
$journal->order = $order;
|
||||
if ($journal && $journal->date->isSameDay($date)) {
|
||||
$repository->setOrder($journal, $order);
|
||||
$order++;
|
||||
$journal->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -215,4 +185,79 @@ class TransactionController extends Controller
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $what
|
||||
*
|
||||
* @return Collection
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getPeriodOverview(string $what): Collection
|
||||
{
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$first = $repository->first();
|
||||
$start = $first->date ?? new Carbon;
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfX(new Carbon, $range);
|
||||
$entries = new Collection;
|
||||
$types = config('firefly.transactionTypesByWhat.' . $what);
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($what);
|
||||
$cache->addProperty('transaction-list-entries');
|
||||
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Going to get period expenses and incomes between %s and %s.', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
while ($end >= $start) {
|
||||
Log::debug('Loop start!');
|
||||
$end = Navigation::startOfPeriod($end, $range);
|
||||
$currentEnd = Navigation::endOfPeriod($end, $range);
|
||||
|
||||
// count journals without budget in this period:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withOpposingAccount()->setTypes($types)->disableInternalFilter();
|
||||
$set = $collector->getJournals();
|
||||
$sum = $set->sum('transaction_amount');
|
||||
$journals = $set->count();
|
||||
$dateStr = $end->format('Y-m-d');
|
||||
$dateName = Navigation::periodShow($end, $range);
|
||||
$array = [
|
||||
'string' => $dateStr,
|
||||
'name' => $dateName,
|
||||
'count' => $journals,
|
||||
'spent' => 0,
|
||||
'earned' => 0,
|
||||
'transferred' => 0,
|
||||
'date' => clone $end,
|
||||
];
|
||||
Log::debug(sprintf('What is %s', $what));
|
||||
switch ($what) {
|
||||
case 'withdrawal':
|
||||
$array['spent'] = $sum;
|
||||
break;
|
||||
case 'deposit':
|
||||
$array['earned'] = $sum;
|
||||
break;
|
||||
case 'transfers':
|
||||
case 'transfer':
|
||||
$array['transferred'] = Steam::positive($sum);
|
||||
break;
|
||||
|
||||
}
|
||||
$entries->push($array);
|
||||
$end = Navigation::subtractPeriod($end, $range, 1);
|
||||
}
|
||||
Log::debug('End of loop');
|
||||
$cache->store($entries);
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
}
|
||||
|
61
app/Http/Middleware/IsLimitedUser.php
Normal file
61
app/Http/Middleware/IsLimitedUser.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* IsLimitedUser.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Session;
|
||||
|
||||
/**
|
||||
* Class IsAdmin
|
||||
*
|
||||
* @package FireflyIII\Http\Middleware
|
||||
*/
|
||||
class IsLimitedUser
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request. May not be a limited user (ie. Sandstorm env. or demo user).
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, $guard = null)
|
||||
{
|
||||
if (Auth::guard($guard)->guest()) {
|
||||
if ($request->ajax()) {
|
||||
return response('Unauthorized.', 401);
|
||||
}
|
||||
|
||||
return redirect()->guest('login');
|
||||
}
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
if ($user->hasRole('demo')) {
|
||||
Session::flash('warning', strval(trans('firefly.not_available_demo_user')));
|
||||
|
||||
return redirect(route('index'));
|
||||
}
|
||||
|
||||
if (intval(getenv('SANDSTORM')) === 1) {
|
||||
Session::flash('warning', strval(trans('firefly.sandstorm_not_available')));
|
||||
|
||||
return redirect(route('index'));
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ class UserFormRequest extends Request
|
||||
{
|
||||
return [
|
||||
'email' => $this->string('email'),
|
||||
'blocked' => $this->integer('blocked'),
|
||||
'blocked' => $this->integer('blocked') === 1,
|
||||
'blocked_code' => $this->string('blocked_code'),
|
||||
'password' => $this->string('password'),
|
||||
];
|
||||
@ -50,7 +50,7 @@ class UserFormRequest extends Request
|
||||
{
|
||||
return [
|
||||
'id' => 'required|exists:users,id',
|
||||
'email' => 'required',
|
||||
'email' => 'email|required',
|
||||
'password' => 'confirmed',
|
||||
'blocked_code' => 'between:0,30',
|
||||
'blocked' => 'between:0,1|numeric',
|
||||
|
@ -67,38 +67,31 @@ Breadcrumbs::register(
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'accounts.show', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
|
||||
'accounts.show', function (BreadCrumbGenerator $breadcrumbs, Account $account, string $moment, Carbon $start, Carbon $end) {
|
||||
$what = config('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
|
||||
$breadcrumbs->parent('accounts.index', $what);
|
||||
$breadcrumbs->push($account->name, route('accounts.show', [$account->id]));
|
||||
|
||||
// push when is all:
|
||||
if ($moment === 'all') {
|
||||
$breadcrumbs->push(trans('firefly.everything'), route('accounts.show', [$account->id, 'all']));
|
||||
}
|
||||
// when is specific period:
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$title = trans(
|
||||
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
|
||||
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'accounts.show.date', function (BreadCrumbGenerator $breadcrumbs, Account $account, Carbon $start = null, Carbon $end = null) {
|
||||
|
||||
$title = '';
|
||||
$route = '';
|
||||
if (!is_null($start) && !is_null($end)) {
|
||||
$startString = $start->formatLocalized(strval(trans('config.month_and_day')));
|
||||
$endString = $end->formatLocalized(strval(trans('config.month_and_day')));
|
||||
$title = sprintf('%s (%s)', $account->name, trans('firefly.from_to_breadcrumb', ['start' => $startString, 'end' => $endString]));
|
||||
$route = route('accounts.show.date', [$account->id, $start->format('Y-m-d')]);
|
||||
}
|
||||
if (is_null($start) && is_null($end)) {
|
||||
$title = $title = $account->name . ' (' . strtolower(strval(trans('firefly.everything'))) . ')';
|
||||
$route = route('accounts.show.date', [$account->id, 'all']);
|
||||
$breadcrumbs->push($title, route('accounts.show', [$account->id, $moment]));
|
||||
}
|
||||
|
||||
$breadcrumbs->parent('accounts.show', $account);
|
||||
$breadcrumbs->push($title, $route);
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'accounts.delete', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
|
||||
$breadcrumbs->parent('accounts.show', $account);
|
||||
$breadcrumbs->parent('accounts.show', $account, '', new Carbon, new Carbon);
|
||||
$breadcrumbs->push(trans('firefly.delete_account', ['name' => e($account->name)]), route('accounts.delete', [$account->id]));
|
||||
}
|
||||
);
|
||||
@ -106,7 +99,7 @@ Breadcrumbs::register(
|
||||
|
||||
Breadcrumbs::register(
|
||||
'accounts.edit', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
|
||||
$breadcrumbs->parent('accounts.show', $account);
|
||||
$breadcrumbs->parent('accounts.show', $account, '', new Carbon, new Carbon);
|
||||
$what = config('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
|
||||
$breadcrumbs->push(trans('firefly.edit_' . $what . '_account', ['name' => e($account->name)]), route('accounts.edit', [$account->id]));
|
||||
@ -256,9 +249,24 @@ Breadcrumbs::register(
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'budgets.no-budget', function (BreadCrumbGenerator $breadcrumbs, $subTitle) {
|
||||
'budgets.no-budget', function (BreadCrumbGenerator $breadcrumbs, string $moment, Carbon $start, Carbon $end) {
|
||||
$breadcrumbs->parent('budgets.index');
|
||||
$breadcrumbs->push($subTitle, route('budgets.no-budget'));
|
||||
$breadcrumbs->push(trans('firefly.journals_without_budget'), route('budgets.no-budget'));
|
||||
|
||||
// push when is all:
|
||||
if ($moment === 'all') {
|
||||
$breadcrumbs->push(trans('firefly.everything'), route('budgets.no-budget', ['all']));
|
||||
}
|
||||
// when is specific period:
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$title = trans(
|
||||
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
|
||||
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
|
||||
);
|
||||
$breadcrumbs->push($title, route('budgets.no-budget', [$moment]));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
@ -275,11 +283,8 @@ Breadcrumbs::register(
|
||||
$breadcrumbs->push(e($budget->name), route('budgets.show', [$budget->id]));
|
||||
|
||||
$title = trans(
|
||||
'firefly.budget_in_period_breadcrumb', [
|
||||
'name' => $budget->name,
|
||||
'start' => $budgetLimit->start_date->formatLocalized(strval(trans('config.month_and_day'))),
|
||||
'end' => $budgetLimit->end_date->formatLocalized(strval(trans('config.month_and_day'))),
|
||||
]
|
||||
'firefly.between_dates_breadcrumb', ['start' => $budgetLimit->start_date->formatLocalized(strval(trans('config.month_and_day'))),
|
||||
'end' => $budgetLimit->end_date->formatLocalized(strval(trans('config.month_and_day'))),]
|
||||
);
|
||||
|
||||
$breadcrumbs->push(
|
||||
@ -306,52 +311,61 @@ Breadcrumbs::register(
|
||||
|
||||
Breadcrumbs::register(
|
||||
'categories.edit', function (BreadCrumbGenerator $breadcrumbs, Category $category) {
|
||||
$breadcrumbs->parent('categories.show', $category);
|
||||
$breadcrumbs->parent('categories.show', $category, '', new Carbon, new Carbon);
|
||||
$breadcrumbs->push(trans('firefly.edit_category', ['name' => e($category->name)]), route('categories.edit', [$category->id]));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'categories.delete', function (BreadCrumbGenerator $breadcrumbs, Category $category) {
|
||||
$breadcrumbs->parent('categories.show', $category);
|
||||
$breadcrumbs->parent('categories.show', $category, '', new Carbon, new Carbon);
|
||||
$breadcrumbs->push(trans('firefly.delete_category', ['name' => e($category->name)]), route('categories.delete', [$category->id]));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'categories.show', function (BreadCrumbGenerator $breadcrumbs, Category $category) {
|
||||
$breadcrumbs->parent('categories.index');
|
||||
$breadcrumbs->push(e($category->name), route('categories.show', [$category->id]));
|
||||
'categories.show', function (BreadCrumbGenerator $breadcrumbs, Category $category, string $moment, Carbon $start, Carbon $end) {
|
||||
|
||||
$breadcrumbs->parent('categories.index');
|
||||
$breadcrumbs->push($category->name, route('categories.show', [$category->id]));
|
||||
|
||||
// push when is all:
|
||||
if ($moment === 'all') {
|
||||
$breadcrumbs->push(trans('firefly.everything'), route('categories.show', [$category->id, 'all']));
|
||||
}
|
||||
// when is specific period:
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$title = trans(
|
||||
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
|
||||
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
|
||||
);
|
||||
$breadcrumbs->push($title, route('categories.show', [$category->id, $moment]));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Breadcrumbs::register(
|
||||
'categories.show.all', function (BreadCrumbGenerator $breadcrumbs, Category $category) {
|
||||
'categories.no-category', function (BreadCrumbGenerator $breadcrumbs, string $moment, Carbon $start, Carbon $end) {
|
||||
$breadcrumbs->parent('categories.index');
|
||||
$breadcrumbs->push(e($category->name) . '(' . strtolower(trans('firefly.all_periods')) . ')', route('categories.show.all', [$category->id]));
|
||||
$breadcrumbs->push(trans('firefly.journals_without_category'), route('categories.no-category'));
|
||||
|
||||
// push when is all:
|
||||
if ($moment === 'all') {
|
||||
$breadcrumbs->push(trans('firefly.everything'), route('categories.no-category', ['all']));
|
||||
}
|
||||
// when is specific period:
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$title = trans(
|
||||
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
|
||||
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
|
||||
);
|
||||
$breadcrumbs->push($title, route('categories.no-category', [$moment]));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'categories.show.date', function (BreadCrumbGenerator $breadcrumbs, Category $category, Carbon $date) {
|
||||
|
||||
// get current period preference.
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
|
||||
$breadcrumbs->parent('categories.index');
|
||||
$breadcrumbs->push(e($category->name), route('categories.show', [$category->id]));
|
||||
$breadcrumbs->push(Navigation::periodShow($date, $range), route('categories.show.date', [$category->id, $date->format('Y-m-d')]));
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'categories.no-category', function (BreadCrumbGenerator $breadcrumbs, $subTitle) {
|
||||
$breadcrumbs->parent('categories.index');
|
||||
$breadcrumbs->push($subTitle, route('categories.no-category'));
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* CURRENCIES
|
||||
@ -719,36 +733,30 @@ Breadcrumbs::register(
|
||||
* TRANSACTIONS
|
||||
*/
|
||||
Breadcrumbs::register(
|
||||
'transactions.index', function (BreadCrumbGenerator $breadcrumbs, string $what) {
|
||||
'transactions.index', function (BreadCrumbGenerator $breadcrumbs, string $what, string $moment = '', Carbon $start, Carbon $end) {
|
||||
|
||||
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push(trans('breadcrumbs.' . $what . '_list'), route('transactions.index', [$what]));
|
||||
if ($moment === 'all') {
|
||||
$breadcrumbs->push(trans('firefly.everything'), route('transactions.index', [$what, 'all']));
|
||||
}
|
||||
|
||||
// when is specific period:
|
||||
if (strlen($moment) > 0 && $moment !== 'all') {
|
||||
$title = trans(
|
||||
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
|
||||
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'transactions.index.all', function (BreadCrumbGenerator $breadcrumbs, string $what) {
|
||||
$breadcrumbs->parent('transactions.index', $what);
|
||||
|
||||
$title = sprintf('%s (%s)', trans('breadcrumbs.' . $what . '_list'), strtolower(trans('firefly.everything')));
|
||||
|
||||
$breadcrumbs->push($title, route('transactions.index.all', [$what]));
|
||||
$breadcrumbs->push($title, route('transactions.index', [$what, $moment]));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'transactions.index.date', function (BreadCrumbGenerator $breadcrumbs, string $what, Carbon $date) {
|
||||
$breadcrumbs->parent('transactions.index', $what);
|
||||
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$title = trans('breadcrumbs.' . $what . '_list') . ' (' . Navigation::periodShow($date, $range) . ')';
|
||||
|
||||
$breadcrumbs->push($title, route('transactions.index.date', [$what, $date->format('Y-m-d')]));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'transactions.create', function (BreadCrumbGenerator $breadcrumbs, string $what) {
|
||||
$breadcrumbs->parent('transactions.index', $what);
|
||||
$breadcrumbs->parent('transactions.index', $what, '', new Carbon, new Carbon);
|
||||
$breadcrumbs->push(trans('breadcrumbs.create_' . e($what)), route('transactions.create', [$what]));
|
||||
}
|
||||
);
|
||||
@ -770,7 +778,7 @@ Breadcrumbs::register(
|
||||
'transactions.show', function (BreadCrumbGenerator $breadcrumbs, TransactionJournal $journal) {
|
||||
|
||||
$what = strtolower($journal->transactionType->type);
|
||||
$breadcrumbs->parent('transactions.index', $what);
|
||||
$breadcrumbs->parent('transactions.index', $what, '', new Carbon, new Carbon);
|
||||
$breadcrumbs->push($journal->description, route('transactions.show', [$journal->id]));
|
||||
}
|
||||
);
|
||||
@ -795,8 +803,9 @@ Breadcrumbs::register(
|
||||
if ($journals->count() > 0) {
|
||||
$journalIds = $journals->pluck('id')->toArray();
|
||||
$what = strtolower($journals->first()->transactionType->type);
|
||||
$breadcrumbs->parent('transactions.index', $what);
|
||||
$breadcrumbs->parent('transactions.index', $what, '', new Carbon, new Carbon);
|
||||
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.edit', $journalIds));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -809,7 +818,7 @@ Breadcrumbs::register(
|
||||
|
||||
$journalIds = $journals->pluck('id')->toArray();
|
||||
$what = strtolower($journals->first()->transactionType->type);
|
||||
$breadcrumbs->parent('transactions.index', $what);
|
||||
$breadcrumbs->parent('transactions.index', $what, '', new Carbon, new Carbon);
|
||||
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.delete', $journalIds));
|
||||
}
|
||||
);
|
||||
|
@ -48,6 +48,7 @@ class AccountType extends Model
|
||||
protected $dates = ['created_at', 'updated_at'];
|
||||
|
||||
//
|
||||
|
||||
/**
|
||||
* @return HasMany
|
||||
*/
|
||||
|
@ -14,7 +14,6 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use Crypt;
|
||||
use FireflyIII\Support\Models\TagTrait;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
@ -27,7 +26,7 @@ use Watson\Validating\ValidatingTrait;
|
||||
*/
|
||||
class Tag extends Model
|
||||
{
|
||||
use ValidatingTrait, SoftDeletes, TagTrait;
|
||||
use ValidatingTrait, SoftDeletes;
|
||||
|
||||
/**
|
||||
* The attributes that should be casted to native types.
|
||||
|
@ -29,6 +29,8 @@ use FireflyIII\Helpers\Report\BalanceReportHelper;
|
||||
use FireflyIII\Helpers\Report\BalanceReportHelperInterface;
|
||||
use FireflyIII\Helpers\Report\BudgetReportHelper;
|
||||
use FireflyIII\Helpers\Report\BudgetReportHelperInterface;
|
||||
use FireflyIII\Helpers\Report\PopupReport;
|
||||
use FireflyIII\Helpers\Report\PopupReportInterface;
|
||||
use FireflyIII\Helpers\Report\ReportHelper;
|
||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
||||
use FireflyIII\Import\ImportProcedure;
|
||||
@ -127,6 +129,8 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
|
||||
$this->app->bind(AttachmentHelperInterface::class, AttachmentHelper::class);
|
||||
|
||||
// more generators:
|
||||
$this->app->bind(PopupReportInterface::class, PopupReport::class);
|
||||
$this->app->bind(HelpInterface::class, Help::class);
|
||||
$this->app->bind(ReportHelperInterface::class, ReportHelper::class);
|
||||
$this->app->bind(FiscalHelperInterface::class, FiscalHelper::class);
|
||||
|
@ -113,7 +113,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
|
||||
*/
|
||||
public function findByCode(string $currencyCode): TransactionCurrency
|
||||
{
|
||||
$currency = TransactionCurrency::whereCode($currencyCode)->first();
|
||||
$currency = TransactionCurrency::where('code', $currencyCode)->first();
|
||||
if (is_null($currency)) {
|
||||
$currency = new TransactionCurrency;
|
||||
}
|
||||
@ -170,7 +170,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
|
||||
*/
|
||||
public function getCurrencyByPreference(Preference $preference): TransactionCurrency
|
||||
{
|
||||
$preferred = TransactionCurrency::whereCode($preference->data)->first();
|
||||
$preferred = TransactionCurrency::where('code', $preference->data)->first();
|
||||
if (is_null($preferred)) {
|
||||
$preferred = TransactionCurrency::first();
|
||||
}
|
||||
|
@ -86,6 +86,20 @@ class ImportJobRepository implements ImportJobRepositoryInterface
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ImportJob $job
|
||||
* @param array $configuration
|
||||
*
|
||||
* @return ImportJob
|
||||
*/
|
||||
public function setConfiguration(ImportJob $job, array $configuration): ImportJob
|
||||
{
|
||||
$job->configuration = $configuration;
|
||||
$job->save();
|
||||
|
||||
return $job;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
@ -93,4 +107,18 @@ class ImportJobRepository implements ImportJobRepositoryInterface
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ImportJob $job
|
||||
* @param string $status
|
||||
*
|
||||
* @return ImportJob
|
||||
*/
|
||||
public function updateStatus(ImportJob $job, string $status): ImportJob
|
||||
{
|
||||
$job->status = $status;
|
||||
$job->save();
|
||||
|
||||
return $job;
|
||||
}
|
||||
}
|
||||
|
@ -37,8 +37,24 @@ interface ImportJobRepositoryInterface
|
||||
*/
|
||||
public function findByKey(string $key): ImportJob;
|
||||
|
||||
/**
|
||||
* @param ImportJob $job
|
||||
* @param array $configuration
|
||||
*
|
||||
* @return ImportJob
|
||||
*/
|
||||
public function setConfiguration(ImportJob $job, array $configuration): ImportJob;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user);
|
||||
|
||||
/**
|
||||
* @param ImportJob $job
|
||||
* @param string $status
|
||||
*
|
||||
* @return ImportJob
|
||||
*/
|
||||
public function updateStatus(ImportJob $job, string $status): ImportJob;
|
||||
}
|
||||
|
@ -135,6 +135,20 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
return TransactionType::orderBy('type', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param int $order
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setOrder(TransactionJournal $journal, int $order): bool
|
||||
{
|
||||
$journal->order = $order;
|
||||
$journal->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
|
@ -67,6 +67,14 @@ interface JournalRepositoryInterface
|
||||
*/
|
||||
public function getTransactionTypes(): Collection;
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param int $order
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setOrder(TransactionJournal $journal, int $order): bool;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
|
@ -32,6 +32,54 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function addAmount(PiggyBank $piggyBank, string $amount): bool
|
||||
{
|
||||
$repetition = $piggyBank->currentRelevantRep();
|
||||
$currentAmount = $repetition->currentamount ?? '0';
|
||||
$repetition->currentamount = bcadd($currentAmount, $amount);
|
||||
$repetition->save();
|
||||
|
||||
// create event
|
||||
$this->createEvent($piggyBank, $amount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAddAmount(PiggyBank $piggyBank, string $amount): bool
|
||||
{
|
||||
$leftOnAccount = $piggyBank->leftOnAccount(new Carbon);
|
||||
$savedSoFar = strval($piggyBank->currentRelevantRep()->currentamount);
|
||||
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
|
||||
$maxAmount = strval(min(round($leftOnAccount, 12), round($leftToSave, 12)));
|
||||
|
||||
return bccomp($amount, $maxAmount) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canRemoveAmount(PiggyBank $piggyBank, string $amount): bool
|
||||
{
|
||||
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
|
||||
|
||||
return bccomp($amount, $savedSoFar) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
@ -119,6 +167,24 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function removeAmount(PiggyBank $piggyBank, string $amount): bool
|
||||
{
|
||||
$repetition = $piggyBank->currentRelevantRep();
|
||||
$repetition->currentamount = bcsub($repetition->currentamount, $amount);
|
||||
$repetition->save();
|
||||
|
||||
// create event
|
||||
$this->createEvent($piggyBank, bcmul($amount, '-1'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all piggy banks to order 0.
|
||||
*
|
||||
|
@ -26,6 +26,30 @@ use Illuminate\Support\Collection;
|
||||
interface PiggyBankRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function addAmount(PiggyBank $piggyBank, string $amount): bool;
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAddAmount(PiggyBank $piggyBank, string $amount): bool;
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canRemoveAmount(PiggyBank $piggyBank, string $amount): bool;
|
||||
|
||||
/**
|
||||
* Create a new event.
|
||||
*
|
||||
@ -82,6 +106,14 @@ interface PiggyBankRepositoryInterface
|
||||
*/
|
||||
public function getPiggyBanksWithAmount(): Collection;
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function removeAmount(PiggyBank $piggyBank, string $amount): bool;
|
||||
|
||||
/**
|
||||
* Set all piggy banks to order 0.
|
||||
*
|
||||
|
@ -246,6 +246,73 @@ class TagRepository implements TagRepositoryInterface
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Can a tag become an advance payment?
|
||||
*
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function tagAllowAdvance(Tag $tag): bool
|
||||
{
|
||||
/*
|
||||
* If this tag is a balancing act, and it contains transfers, it cannot be
|
||||
* changed to an advancePayment.
|
||||
*/
|
||||
|
||||
if ($tag->tagMode == 'balancingAct' || $tag->tagMode == 'nothing') {
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->isTransfer()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this tag contains more than one expenses, it cannot become an advance payment.
|
||||
*/
|
||||
$count = 0;
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->isWithdrawal()) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
if ($count > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can a tag become a balancing act?
|
||||
*
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function tagAllowBalancing(Tag $tag): bool
|
||||
{
|
||||
/*
|
||||
* If has more than two transactions already, cannot become a balancing act:
|
||||
*/
|
||||
if ($tag->transactionjournals->count() > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If any transaction is a deposit, cannot become a balancing act.
|
||||
*/
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->isDeposit()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
* @param array $data
|
||||
|
@ -27,6 +27,7 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface TagRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* This method will connect a journal with a tag.
|
||||
*
|
||||
@ -125,6 +126,20 @@ interface TagRepositoryInterface
|
||||
*/
|
||||
public function store(array $data): Tag;
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function tagAllowAdvance(Tag $tag): bool;
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function tagAllowBalancing(Tag $tag): bool;
|
||||
|
||||
/**
|
||||
* Update a tag.
|
||||
*
|
||||
|
@ -66,6 +66,23 @@ class UserRepository implements UserRepositoryInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param bool $isBlocked
|
||||
* @param string $code
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function changeStatus(User $user, bool $isBlocked, string $code): bool
|
||||
{
|
||||
// change blocked status and code:
|
||||
$user->blocked = $isBlocked;
|
||||
$user->blocked_code = $code;
|
||||
$user->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
@ -147,4 +164,15 @@ class UserRepository implements UserRepositoryInterface
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $role
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasRole(User $user, string $role): bool
|
||||
{
|
||||
return $user->hasRole($role);
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,15 @@ interface UserRepositoryInterface
|
||||
*/
|
||||
public function changePassword(User $user, string $password);
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param bool $isBlocked
|
||||
* @param string $code
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function changeStatus(User $user, bool $isBlocked, string $code): bool;
|
||||
|
||||
/**
|
||||
* Returns a count of all users.
|
||||
*
|
||||
@ -79,4 +88,12 @@ interface UserRepositoryInterface
|
||||
* @return array
|
||||
*/
|
||||
public function getUserData(User $user): array;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $role
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasRole(User $user, string $role): bool;
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ declare(strict_types = 1);
|
||||
|
||||
namespace FireflyIII\Support;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Preferences as Prefs;
|
||||
|
||||
/**
|
||||
@ -97,7 +97,6 @@ class Amount
|
||||
// alternative is currency before amount
|
||||
$format = $pos_a . $pos_b . '%s' . $pos_c . $space . $pos_d . '%v' . $pos_e;
|
||||
}
|
||||
Log::debug(sprintf('Final format: "%s"', $format));
|
||||
|
||||
return $format;
|
||||
}
|
||||
@ -130,7 +129,7 @@ class Amount
|
||||
setlocale(LC_MONETARY, $locale);
|
||||
$float = round($amount, 12);
|
||||
$info = localeconv();
|
||||
$formatted = number_format($float, $format->decimal_places, $info['mon_decimal_point'], $info['mon_thousands_sep']);
|
||||
$formatted = number_format($float, intval($format->decimal_places), $info['mon_decimal_point'], $info['mon_thousands_sep']);
|
||||
|
||||
// some complicated switches to format the amount correctly:
|
||||
$precedes = $amount < 0 ? $info['n_cs_precedes'] : $info['p_cs_precedes'];
|
||||
@ -171,7 +170,7 @@ class Amount
|
||||
*/
|
||||
public function formatByCode(string $currencyCode, string $amount, bool $coloured = true): string
|
||||
{
|
||||
$currency = TransactionCurrency::whereCode($currencyCode)->first();
|
||||
$currency = TransactionCurrency::where('code', $currencyCode)->first();
|
||||
|
||||
return $this->formatAnything($currency, $amount, $coloured);
|
||||
}
|
||||
@ -224,7 +223,7 @@ class Amount
|
||||
} else {
|
||||
$currencyPreference = Prefs::get('currencyPreference', config('firefly.default_currency', 'EUR'));
|
||||
|
||||
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||
$currency = TransactionCurrency::where('code', $currencyPreference->data)->first();
|
||||
if ($currency) {
|
||||
|
||||
$cache->store($currency->code);
|
||||
@ -248,7 +247,7 @@ class Amount
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
} else {
|
||||
$currencyPreference = Prefs::get('currencyPreference', config('firefly.default_currency', 'EUR'));
|
||||
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||
$currency = TransactionCurrency::where('code', $currencyPreference->data)->first();
|
||||
|
||||
$cache->store($currency->symbol);
|
||||
|
||||
@ -257,7 +256,8 @@ class Amount
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \FireflyIII\Models\TransactionCurrency
|
||||
* @return TransactionCurrency
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getDefaultCurrency(): TransactionCurrency
|
||||
{
|
||||
@ -267,7 +267,10 @@ class Amount
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
$currencyPreference = Prefs::get('currencyPreference', config('firefly.default_currency', 'EUR'));
|
||||
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||
$currency = TransactionCurrency::where('code', $currencyPreference->data)->first();
|
||||
if (is_null($currency)) {
|
||||
throw new FireflyException(sprintf('No currency found with code "%s"', $currencyPreference->data));
|
||||
}
|
||||
$cache->store($currency);
|
||||
|
||||
return $currency;
|
||||
|
@ -39,11 +39,13 @@ class JournalList implements BinderInterface
|
||||
$object = TransactionJournal::whereIn('transaction_journals.id', $ids)
|
||||
->expanded()
|
||||
->where('transaction_journals.user_id', auth()->user()->id)
|
||||
->get([
|
||||
->get(
|
||||
[
|
||||
'transaction_journals.*',
|
||||
'transaction_types.type AS transaction_type_type',
|
||||
'transaction_currencies.code AS transaction_currency_code',
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
if ($object->count() > 0) {
|
||||
return $object;
|
||||
|
@ -1,90 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* TagTrait.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace FireflyIII\Support\Models;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
*
|
||||
* @property Collection $transactionjournals
|
||||
* @property string $tagMode
|
||||
*
|
||||
* Class TagSupport
|
||||
*
|
||||
* @package FireflyIII\Support\Models
|
||||
*/
|
||||
trait TagTrait
|
||||
{
|
||||
/**
|
||||
* Can a tag become an advance payment?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function tagAllowAdvance(): bool
|
||||
{
|
||||
/*
|
||||
* If this tag is a balancing act, and it contains transfers, it cannot be
|
||||
* changes to an advancePayment.
|
||||
*/
|
||||
|
||||
if ($this->tagMode == 'balancingAct' || $this->tagMode == 'nothing') {
|
||||
foreach ($this->transactionjournals as $journal) {
|
||||
if ($journal->isTransfer()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this tag contains more than one expenses, it cannot become an advance payment.
|
||||
*/
|
||||
$count = 0;
|
||||
foreach ($this->transactionjournals as $journal) {
|
||||
if ($journal->isWithdrawal()) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
if ($count > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can a tag become a balancing act?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function tagAllowBalancing(): bool
|
||||
{
|
||||
/*
|
||||
* If has more than two transactions already, cannot become a balancing act:
|
||||
*/
|
||||
if ($this->transactionjournals->count() > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If any transaction is a deposit, cannot become a balancing act.
|
||||
*/
|
||||
foreach ($this->transactionjournals as $journal) {
|
||||
if ($journal->isDeposit()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -15,10 +15,8 @@ namespace FireflyIII\Support\Models;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,7 @@ class Navigation
|
||||
* @return \Carbon\Carbon
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function endOfPeriod(Carbon $end, string $repeatFreq): Carbon
|
||||
public function endOfPeriod(\Carbon\Carbon $end, string $repeatFreq): Carbon
|
||||
{
|
||||
$currentEnd = clone $end;
|
||||
|
||||
|
@ -37,6 +37,8 @@ class Search implements SearchInterface
|
||||
private $limit = 100;
|
||||
/** @var Collection */
|
||||
private $modifiers;
|
||||
/** @var string */
|
||||
private $originalQuery = '';
|
||||
/** @var User */
|
||||
private $user;
|
||||
/** @var array */
|
||||
@ -58,7 +60,11 @@ class Search implements SearchInterface
|
||||
*/
|
||||
public function getWordsAsString(): string
|
||||
{
|
||||
return join(' ', $this->words);
|
||||
$string = join(' ', $this->words);
|
||||
if (strlen($string) === 0) {
|
||||
return is_string($this->originalQuery) ? $this->originalQuery : '';
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,6 +81,7 @@ class Search implements SearchInterface
|
||||
public function parseQuery(string $query)
|
||||
{
|
||||
$filteredQuery = $query;
|
||||
$this->originalQuery = $query;
|
||||
$pattern = '/[a-z_]*:[0-9a-z-.]*/i';
|
||||
$matches = [];
|
||||
preg_match_all($pattern, $query, $matches);
|
||||
|
@ -29,7 +29,6 @@ use Google2FA;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Contracts\Translation\Translator;
|
||||
use Illuminate\Validation\Validator;
|
||||
use Session;
|
||||
|
||||
/**
|
||||
* Class FireflyValidator
|
||||
@ -66,7 +65,7 @@ class FireflyValidator extends Validator
|
||||
return false;
|
||||
}
|
||||
|
||||
$secret = Session::get('two-factor-secret');
|
||||
$secret = session('two-factor-secret');
|
||||
|
||||
return Google2FA::verifyKey($secret, $value);
|
||||
}
|
||||
|
@ -72,7 +72,8 @@
|
||||
"symfony/css-selector": "3.1.*",
|
||||
"symfony/dom-crawler": "3.1.*",
|
||||
"barryvdh/laravel-debugbar": "2.*",
|
||||
"barryvdh/laravel-ide-helper": "2.*"
|
||||
"barryvdh/laravel-ide-helper": "2.*",
|
||||
"satooshi/php-coveralls": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
|
537
composer.lock
generated
537
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "5286d8b4bfb450a5cecae36d2f67a862",
|
||||
"content-hash": "3570b1bf4768d7a7db0667317e82c668",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@ -623,16 +623,16 @@
|
||||
},
|
||||
{
|
||||
"name": "erusev/parsedown",
|
||||
"version": "1.6.1",
|
||||
"version": "1.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/erusev/parsedown.git",
|
||||
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb"
|
||||
"reference": "1bf24f7334fe16c88bf9d467863309ceaf285b01"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/erusev/parsedown/zipball/20ff8bbb57205368b4b42d094642a3e52dac85fb",
|
||||
"reference": "20ff8bbb57205368b4b42d094642a3e52dac85fb",
|
||||
"url": "https://api.github.com/repos/erusev/parsedown/zipball/1bf24f7334fe16c88bf9d467863309ceaf285b01",
|
||||
"reference": "1bf24f7334fe16c88bf9d467863309ceaf285b01",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -661,20 +661,20 @@
|
||||
"markdown",
|
||||
"parser"
|
||||
],
|
||||
"time": "2016-11-02T15:56:58+00:00"
|
||||
"time": "2017-03-29T16:04:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v5.4.15",
|
||||
"version": "v5.4.17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "ecc6468b8af30b77566a8519ce8898740ef691d7"
|
||||
"reference": "f7675d59e3863a58ecdff1a5ee1dcd0cff788f4b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/ecc6468b8af30b77566a8519ce8898740ef691d7",
|
||||
"reference": "ecc6468b8af30b77566a8519ce8898740ef691d7",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/f7675d59e3863a58ecdff1a5ee1dcd0cff788f4b",
|
||||
"reference": "f7675d59e3863a58ecdff1a5ee1dcd0cff788f4b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -790,7 +790,7 @@
|
||||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2017-03-02T14:41:40+00:00"
|
||||
"time": "2017-04-03T13:07:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravelcollective/html",
|
||||
@ -974,16 +974,16 @@
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem",
|
||||
"version": "1.0.35",
|
||||
"version": "1.0.37",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/flysystem.git",
|
||||
"reference": "dda7f3ab94158a002d9846a97dc18ebfb7acc062"
|
||||
"reference": "78b5cc4feb61a882302df4fbaf63b7662e5e4ccd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/dda7f3ab94158a002d9846a97dc18ebfb7acc062",
|
||||
"reference": "dda7f3ab94158a002d9846a97dc18ebfb7acc062",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/78b5cc4feb61a882302df4fbaf63b7662e5e4ccd",
|
||||
"reference": "78b5cc4feb61a882302df4fbaf63b7662e5e4ccd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1053,20 +1053,20 @@
|
||||
"sftp",
|
||||
"storage"
|
||||
],
|
||||
"time": "2017-02-09T11:33:58+00:00"
|
||||
"time": "2017-03-22T15:43:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "1.22.0",
|
||||
"version": "1.22.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/monolog.git",
|
||||
"reference": "bad29cb8d18ab0315e6c477751418a82c850d558"
|
||||
"reference": "1e044bc4b34e91743943479f1be7a1d5eb93add0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/bad29cb8d18ab0315e6c477751418a82c850d558",
|
||||
"reference": "bad29cb8d18ab0315e6c477751418a82c850d558",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/1e044bc4b34e91743943479f1be7a1d5eb93add0",
|
||||
"reference": "1e044bc4b34e91743943479f1be7a1d5eb93add0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1131,7 +1131,7 @@
|
||||
"logging",
|
||||
"psr-3"
|
||||
],
|
||||
"time": "2016-11-26T00:15:39+00:00"
|
||||
"time": "2017-03-13T07:08:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mtdowling/cron-expression",
|
||||
@ -1232,16 +1232,16 @@
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v2.0.9",
|
||||
"version": "v2.0.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "6968531206671f94377b01dc7888d5d1b858a01b"
|
||||
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/6968531206671f94377b01dc7888d5d1b858a01b",
|
||||
"reference": "6968531206671f94377b01dc7888d5d1b858a01b",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d",
|
||||
"reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1276,7 +1276,7 @@
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"time": "2017-03-03T20:43:42+00:00"
|
||||
"time": "2017-03-13T16:27:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pragmarx/google2fa",
|
||||
@ -1388,30 +1388,30 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
"version": "3.5.2",
|
||||
"version": "3.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "5677cfe02397dd6b58c861870dfaa5d9007d3954"
|
||||
"reference": "4ae32dd9ab8860a4bbd750ad269cba7f06f7934e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/5677cfe02397dd6b58c861870dfaa5d9007d3954",
|
||||
"reference": "5677cfe02397dd6b58c861870dfaa5d9007d3954",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/4ae32dd9ab8860a4bbd750ad269cba7f06f7934e",
|
||||
"reference": "4ae32dd9ab8860a4bbd750ad269cba7f06f7934e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"paragonie/random_compat": "^1.0|^2.0",
|
||||
"php": ">=5.4"
|
||||
"php": "^5.4 || ^7.0"
|
||||
},
|
||||
"replace": {
|
||||
"rhumsaa/uuid": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"apigen/apigen": "^4.1",
|
||||
"codeception/aspect-mock": "1.0.0",
|
||||
"codeception/aspect-mock": "^1.0 | ^2.0",
|
||||
"doctrine/annotations": "~1.2.0",
|
||||
"goaop/framework": "1.0.0-alpha.2",
|
||||
"goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1",
|
||||
"ircmaxell/random-lib": "^1.1",
|
||||
"jakub-onderka/php-parallel-lint": "^0.9.0",
|
||||
"mockery/mockery": "^0.9.4",
|
||||
@ -1466,7 +1466,7 @@
|
||||
"identifier",
|
||||
"uuid"
|
||||
],
|
||||
"time": "2016-11-22T19:21:44+00:00"
|
||||
"time": "2017-03-26T20:37:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rcrowe/twigbridge",
|
||||
@ -1637,16 +1637,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v3.2.4",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "0e5e6899f82230fcb1153bcaf0e106ffaa44b870"
|
||||
"reference": "c30243cc51f726812be3551316b109a2f5deaf8d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/0e5e6899f82230fcb1153bcaf0e106ffaa44b870",
|
||||
"reference": "0e5e6899f82230fcb1153bcaf0e106ffaa44b870",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/c30243cc51f726812be3551316b109a2f5deaf8d",
|
||||
"reference": "c30243cc51f726812be3551316b109a2f5deaf8d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1696,7 +1696,7 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-02-16T14:07:22+00:00"
|
||||
"time": "2017-04-04T14:33:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
@ -1753,16 +1753,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
"version": "v3.2.4",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/debug.git",
|
||||
"reference": "9b98854cb45bc59d100b7d4cc4cf9e05f21026b9"
|
||||
"reference": "56f613406446a4a0a031475cfd0a01751de22659"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/debug/zipball/9b98854cb45bc59d100b7d4cc4cf9e05f21026b9",
|
||||
"reference": "9b98854cb45bc59d100b7d4cc4cf9e05f21026b9",
|
||||
"url": "https://api.github.com/repos/symfony/debug/zipball/56f613406446a4a0a031475cfd0a01751de22659",
|
||||
"reference": "56f613406446a4a0a031475cfd0a01751de22659",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1806,31 +1806,31 @@
|
||||
],
|
||||
"description": "Symfony Debug Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-02-16T16:34:18+00:00"
|
||||
"time": "2017-03-28T21:38:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v3.2.4",
|
||||
"version": "v2.8.19",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "9137eb3a3328e413212826d63eeeb0217836e2b6"
|
||||
"reference": "88b65f0ac25355090e524aba4ceb066025df8bd2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9137eb3a3328e413212826d63eeeb0217836e2b6",
|
||||
"reference": "9137eb3a3328e413212826d63eeeb0217836e2b6",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/88b65f0ac25355090e524aba4ceb066025df8bd2",
|
||||
"reference": "88b65f0ac25355090e524aba4ceb066025df8bd2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~2.8|~3.0",
|
||||
"symfony/dependency-injection": "~2.8|~3.0",
|
||||
"symfony/expression-language": "~2.8|~3.0",
|
||||
"symfony/stopwatch": "~2.8|~3.0"
|
||||
"symfony/config": "^2.0.5|~3.0.0",
|
||||
"symfony/dependency-injection": "~2.6|~3.0.0",
|
||||
"symfony/expression-language": "~2.6|~3.0.0",
|
||||
"symfony/stopwatch": "~2.3|~3.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/dependency-injection": "",
|
||||
@ -1839,7 +1839,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.2-dev"
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -1866,20 +1866,20 @@
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-01-02T20:32:22+00:00"
|
||||
"time": "2017-04-03T20:37:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v3.2.4",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "8c71141cae8e2957946b403cc71a67213c0380d6"
|
||||
"reference": "b20900ce5ea164cd9314af52725b0bb5a758217a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/8c71141cae8e2957946b403cc71a67213c0380d6",
|
||||
"reference": "8c71141cae8e2957946b403cc71a67213c0380d6",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/b20900ce5ea164cd9314af52725b0bb5a758217a",
|
||||
"reference": "b20900ce5ea164cd9314af52725b0bb5a758217a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1915,20 +1915,20 @@
|
||||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-01-02T20:32:22+00:00"
|
||||
"time": "2017-03-20T09:32:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v3.2.4",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "a90da6dd679605d88c9803a57a6fc1fb7a19a6e0"
|
||||
"reference": "cb0b6418f588952c9290b3df4ca650f1b7ab570a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/a90da6dd679605d88c9803a57a6fc1fb7a19a6e0",
|
||||
"reference": "a90da6dd679605d88c9803a57a6fc1fb7a19a6e0",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/cb0b6418f588952c9290b3df4ca650f1b7ab570a",
|
||||
"reference": "cb0b6418f588952c9290b3df4ca650f1b7ab570a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1968,20 +1968,20 @@
|
||||
],
|
||||
"description": "Symfony HttpFoundation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-02-16T22:46:52+00:00"
|
||||
"time": "2017-04-04T15:30:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-kernel",
|
||||
"version": "v3.2.4",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-kernel.git",
|
||||
"reference": "4cd0d4bc31819095c6ef13573069f621eb321081"
|
||||
"reference": "8285ab5faf1306b1a5ebcf287fe91c231a6de88e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/4cd0d4bc31819095c6ef13573069f621eb321081",
|
||||
"reference": "4cd0d4bc31819095c6ef13573069f621eb321081",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/8285ab5faf1306b1a5ebcf287fe91c231a6de88e",
|
||||
"reference": "8285ab5faf1306b1a5ebcf287fe91c231a6de88e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2050,7 +2050,7 @@
|
||||
],
|
||||
"description": "Symfony HttpKernel Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-02-16T23:59:56+00:00"
|
||||
"time": "2017-04-05T12:52:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
@ -2221,16 +2221,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v3.2.4",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "0ab87c1e7570b3534a6e51eb4ca8e9f6d7327856"
|
||||
"reference": "57fdaa55827ae14d617550ebe71a820f0a5e2282"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/0ab87c1e7570b3534a6e51eb4ca8e9f6d7327856",
|
||||
"reference": "0ab87c1e7570b3534a6e51eb4ca8e9f6d7327856",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/57fdaa55827ae14d617550ebe71a820f0a5e2282",
|
||||
"reference": "57fdaa55827ae14d617550ebe71a820f0a5e2282",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2266,20 +2266,20 @@
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-02-16T14:07:22+00:00"
|
||||
"time": "2017-03-27T18:07:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/routing",
|
||||
"version": "v3.2.4",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/routing.git",
|
||||
"reference": "af464432c177dbcdbb32295113b7627500331f2d"
|
||||
"reference": "d6605f9a5767bc5bc4895e1c762ba93964608aee"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/af464432c177dbcdbb32295113b7627500331f2d",
|
||||
"reference": "af464432c177dbcdbb32295113b7627500331f2d",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/d6605f9a5767bc5bc4895e1c762ba93964608aee",
|
||||
"reference": "d6605f9a5767bc5bc4895e1c762ba93964608aee",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2341,20 +2341,20 @@
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2017-01-28T02:37:08+00:00"
|
||||
"time": "2017-03-02T15:58:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v3.2.4",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "d6825c6bb2f1da13f564678f9f236fe8242c0029"
|
||||
"reference": "c740eee70783d2af4d3d6b70d5146f209e6b4d13"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/d6825c6bb2f1da13f564678f9f236fe8242c0029",
|
||||
"reference": "d6825c6bb2f1da13f564678f9f236fe8242c0029",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/c740eee70783d2af4d3d6b70d5146f209e6b4d13",
|
||||
"reference": "c740eee70783d2af4d3d6b70d5146f209e6b4d13",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2367,7 +2367,7 @@
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~2.8|~3.0",
|
||||
"symfony/intl": "~2.8|~3.0",
|
||||
"symfony/intl": "^2.8.18|^3.2.5",
|
||||
"symfony/yaml": "~2.8|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
@ -2405,26 +2405,29 @@
|
||||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-02-16T22:46:52+00:00"
|
||||
"time": "2017-03-21T21:44:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v3.2.4",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "cb50260b674ee1c2d4ab49f2395a42e0b4681e20"
|
||||
"reference": "81dce20f69a8b40427e1f4e6462178df87cafc03"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/cb50260b674ee1c2d4ab49f2395a42e0b4681e20",
|
||||
"reference": "cb50260b674ee1c2d4ab49f2395a42e0b4681e20",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/81dce20f69a8b40427e1f4e6462178df87cafc03",
|
||||
"reference": "81dce20f69a8b40427e1f4e6462178df87cafc03",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"twig/twig": "~1.20|~2.0"
|
||||
},
|
||||
@ -2468,7 +2471,7 @@
|
||||
"debug",
|
||||
"dump"
|
||||
],
|
||||
"time": "2017-02-16T22:46:52+00:00"
|
||||
"time": "2017-03-12T16:07:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tijsverkoyen/css-to-inline-styles",
|
||||
@ -2951,6 +2954,102 @@
|
||||
],
|
||||
"time": "2016-04-29T12:21:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzle/guzzle",
|
||||
"version": "v3.9.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/guzzle3.git",
|
||||
"reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9",
|
||||
"reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"php": ">=5.3.3",
|
||||
"symfony/event-dispatcher": "~2.1"
|
||||
},
|
||||
"replace": {
|
||||
"guzzle/batch": "self.version",
|
||||
"guzzle/cache": "self.version",
|
||||
"guzzle/common": "self.version",
|
||||
"guzzle/http": "self.version",
|
||||
"guzzle/inflection": "self.version",
|
||||
"guzzle/iterator": "self.version",
|
||||
"guzzle/log": "self.version",
|
||||
"guzzle/parser": "self.version",
|
||||
"guzzle/plugin": "self.version",
|
||||
"guzzle/plugin-async": "self.version",
|
||||
"guzzle/plugin-backoff": "self.version",
|
||||
"guzzle/plugin-cache": "self.version",
|
||||
"guzzle/plugin-cookie": "self.version",
|
||||
"guzzle/plugin-curlauth": "self.version",
|
||||
"guzzle/plugin-error-response": "self.version",
|
||||
"guzzle/plugin-history": "self.version",
|
||||
"guzzle/plugin-log": "self.version",
|
||||
"guzzle/plugin-md5": "self.version",
|
||||
"guzzle/plugin-mock": "self.version",
|
||||
"guzzle/plugin-oauth": "self.version",
|
||||
"guzzle/service": "self.version",
|
||||
"guzzle/stream": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/cache": "~1.3",
|
||||
"monolog/monolog": "~1.0",
|
||||
"phpunit/phpunit": "3.7.*",
|
||||
"psr/log": "~1.0",
|
||||
"symfony/class-loader": "~2.1",
|
||||
"zendframework/zend-cache": "2.*,<2.3",
|
||||
"zendframework/zend-log": "2.*,<2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.9-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Guzzle": "src/",
|
||||
"Guzzle\\Tests": "tests/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
},
|
||||
{
|
||||
"name": "Guzzle Community",
|
||||
"homepage": "https://github.com/guzzle/guzzle/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
|
||||
"homepage": "http://guzzlephp.org/",
|
||||
"keywords": [
|
||||
"client",
|
||||
"curl",
|
||||
"framework",
|
||||
"http",
|
||||
"http client",
|
||||
"rest",
|
||||
"web service"
|
||||
],
|
||||
"abandoned": "guzzlehttp/guzzle",
|
||||
"time": "2015-03-18T18:23:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hamcrest/hamcrest-php",
|
||||
"version": "v1.2.2",
|
||||
@ -3375,16 +3474,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "4.0.7",
|
||||
"version": "4.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "09e2277d14ea467e5a984010f501343ef29ffc69"
|
||||
"reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/09e2277d14ea467e5a984010f501343ef29ffc69",
|
||||
"reference": "09e2277d14ea467e5a984010f501343ef29ffc69",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
|
||||
"reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3434,7 +3533,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2017-03-01T09:12:17+00:00"
|
||||
"time": "2017-04-02T07:44:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -3624,16 +3723,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "5.7.15",
|
||||
"version": "5.7.19",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "b99112aecc01f62acf3d81a3f59646700a1849e5"
|
||||
"reference": "69c4f49ff376af2692bad9cebd883d17ebaa98a1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b99112aecc01f62acf3d81a3f59646700a1849e5",
|
||||
"reference": "b99112aecc01f62acf3d81a3f59646700a1849e5",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/69c4f49ff376af2692bad9cebd883d17ebaa98a1",
|
||||
"reference": "69c4f49ff376af2692bad9cebd883d17ebaa98a1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3702,7 +3801,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2017-03-02T15:22:43+00:00"
|
||||
"time": "2017-04-03T02:22:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
@ -3763,6 +3862,64 @@
|
||||
],
|
||||
"time": "2016-12-08T20:27:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "satooshi/php-coveralls",
|
||||
"version": "v1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/satooshi/php-coveralls.git",
|
||||
"reference": "da51d304fe8622bf9a6da39a8446e7afd432115c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/da51d304fe8622bf9a6da39a8446e7afd432115c",
|
||||
"reference": "da51d304fe8622bf9a6da39a8446e7afd432115c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-simplexml": "*",
|
||||
"guzzle/guzzle": "^2.8|^3.0",
|
||||
"php": ">=5.3.3",
|
||||
"psr/log": "^1.0",
|
||||
"symfony/config": "^2.1|^3.0",
|
||||
"symfony/console": "^2.1|^3.0",
|
||||
"symfony/stopwatch": "^2.0|^3.0",
|
||||
"symfony/yaml": "^2.0|^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/http-kernel": "Allows Symfony integration"
|
||||
},
|
||||
"bin": [
|
||||
"bin/coveralls"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Satooshi\\": "src/Satooshi/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kitamura Satoshi",
|
||||
"email": "with.no.parachute@gmail.com",
|
||||
"homepage": "https://www.facebook.com/satooshi.jp"
|
||||
}
|
||||
],
|
||||
"description": "PHP client library for Coveralls API",
|
||||
"homepage": "https://github.com/satooshi/php-coveralls",
|
||||
"keywords": [
|
||||
"ci",
|
||||
"coverage",
|
||||
"github",
|
||||
"test"
|
||||
],
|
||||
"time": "2016-01-20T17:35:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
"version": "1.0.1",
|
||||
@ -4278,16 +4435,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/class-loader",
|
||||
"version": "v3.2.4",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/class-loader.git",
|
||||
"reference": "2847d56f518ad5721bf85aa9174b3aa3fd12aa03"
|
||||
"reference": "c29a5bc6ca14cfff1f5e3d7781ed74b6e898d2b9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/class-loader/zipball/2847d56f518ad5721bf85aa9174b3aa3fd12aa03",
|
||||
"reference": "2847d56f518ad5721bf85aa9174b3aa3fd12aa03",
|
||||
"url": "https://api.github.com/repos/symfony/class-loader/zipball/c29a5bc6ca14cfff1f5e3d7781ed74b6e898d2b9",
|
||||
"reference": "c29a5bc6ca14cfff1f5e3d7781ed74b6e898d2b9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4330,7 +4487,63 @@
|
||||
],
|
||||
"description": "Symfony ClassLoader Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-01-21T17:06:35+00:00"
|
||||
"time": "2017-02-18T17:28:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/config.git",
|
||||
"reference": "8444bde28e3c2a33e571e6f180c2d78bfdc4480d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/8444bde28e3c2a33e571e6f180c2d78bfdc4480d",
|
||||
"reference": "8444bde28e3c2a33e571e6f180c2d78bfdc4480d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"symfony/filesystem": "~2.8|~3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/yaml": "~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/yaml": "To use the yaml reference dumper"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Config\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Config Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-04-04T15:30:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
@ -4389,17 +4602,115 @@
|
||||
"time": "2017-01-21T17:13:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.2.4",
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "9724c684646fcb5387d579b4bfaa63ee0b0c64c8"
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "64421e6479c4a8e60d790fb666bd520992861b66"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/9724c684646fcb5387d579b4bfaa63ee0b0c64c8",
|
||||
"reference": "9724c684646fcb5387d579b4bfaa63ee0b0c64c8",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/64421e6479c4a8e60d790fb666bd520992861b66",
|
||||
"reference": "64421e6479c4a8e60d790fb666bd520992861b66",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Filesystem\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-03-26T15:47:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/stopwatch",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/stopwatch.git",
|
||||
"reference": "c5ee0f8650c84b4d36a5f76b3b504233feaabf75"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/c5ee0f8650c84b4d36a5f76b3b504233feaabf75",
|
||||
"reference": "c5ee0f8650c84b4d36a5f76b3b504233feaabf75",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Stopwatch\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Stopwatch Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-02-18T17:28:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "62b4cdb99d52cb1ff253c465eb1532a80cebb621"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/62b4cdb99d52cb1ff253c465eb1532a80cebb621",
|
||||
"reference": "62b4cdb99d52cb1ff253c465eb1532a80cebb621",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4441,7 +4752,7 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-02-16T22:46:52+00:00"
|
||||
"time": "2017-03-20T09:45:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
|
@ -70,7 +70,7 @@ return [
|
||||
//Barryvdh\Debugbar\ServiceProvider::class,
|
||||
DaveJamesMiller\Breadcrumbs\ServiceProvider::class,
|
||||
TwigBridge\ServiceProvider::class,
|
||||
'PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider',
|
||||
PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider::class,
|
||||
|
||||
/*
|
||||
* More service providers.
|
||||
@ -125,7 +125,7 @@ return [
|
||||
'URL' => Illuminate\Support\Facades\URL::class,
|
||||
'Validator' => Illuminate\Support\Facades\Validator::class,
|
||||
'View' => Illuminate\Support\Facades\View::class,
|
||||
'Twig' => 'TwigBridge\Facade\Twig',
|
||||
'Twig' => TwigBridge\Facade\Twig::class,
|
||||
'Form' => Collective\Html\FormFacade::class,
|
||||
'Html' => Collective\Html\HtmlFacade::class,
|
||||
'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade',
|
||||
@ -137,7 +137,7 @@ return [
|
||||
'ExpandedForm' => 'FireflyIII\Support\Facades\ExpandedForm',
|
||||
'Entrust' => 'Zizaco\Entrust\EntrustFacade',
|
||||
'Input' => 'Illuminate\Support\Facades\Input',
|
||||
'Google2FA' => 'PragmaRX\Google2FA\Vendor\Laravel\Facade',
|
||||
'Google2FA' => PragmaRX\Google2FA\Vendor\Laravel\Facade::class,
|
||||
],
|
||||
|
||||
];
|
||||
|
@ -23,7 +23,7 @@ return [
|
||||
'is_demo_site' => false,
|
||||
],
|
||||
'encryption' => (is_null(env('USE_ENCRYPTION')) || env('USE_ENCRYPTION') === true),
|
||||
'version' => '4.3.7',
|
||||
'version' => '4.3.8',
|
||||
'maxUploadSize' => 5242880,
|
||||
'allowedMimes' => ['image/png', 'image/jpeg', 'application/pdf'],
|
||||
'list_length' => 10,
|
||||
|
@ -10,6 +10,9 @@
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Model Factories
|
||||
@ -33,10 +36,89 @@ $factory->define(
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
$factory->define(
|
||||
FireflyIII\Models\ImportJob::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'id' => $faker->numberBetween(1, 10),
|
||||
'user_id' => 1,
|
||||
'key' => $faker->words(1, true),
|
||||
'file_type' => 'csv',
|
||||
'status' => 'import_status_never_started',
|
||||
'configuration' => null,
|
||||
'extended_status' => [
|
||||
'total_steps' => 0,
|
||||
'steps_done' => 0,
|
||||
'import_count' => 0,
|
||||
'importTag' => 0,
|
||||
'errors' => [],
|
||||
],
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
$factory->define(
|
||||
FireflyIII\Models\TransactionJournal::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'id' => $faker->numberBetween(1, 10),
|
||||
'user_id' => 1,
|
||||
'transaction_type_id' => 1,
|
||||
'bill_id' => null,
|
||||
'transaction_currency_id' => 1,
|
||||
'description' => $faker->words(3, true),
|
||||
'date' => '2017-01-01',
|
||||
'interest_date' => null,
|
||||
'book_date' => null,
|
||||
'process_date' => null,
|
||||
'order' => 0,
|
||||
'tag_count' => 0,
|
||||
'encrypted' => 0,
|
||||
'completed' => 1,
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
$factory->define(
|
||||
FireflyIII\Models\Bill::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'id' => $faker->numberBetween(1, 10),
|
||||
'user_id' => 1,
|
||||
'name' => $faker->words(3, true),
|
||||
'match' => $faker->words(3, true),
|
||||
'amount_min' => '100.00',
|
||||
'amount_max' => '100.00',
|
||||
'date' => '2017-01-01',
|
||||
'repeat_freq' => 'monthly',
|
||||
'skip' => 0,
|
||||
'automatch' => 1,
|
||||
'name_encrypted' => 0,
|
||||
'match_encrypted' => 0,
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
$factory->define(
|
||||
FireflyIII\Models\PiggyBank::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'id' => $faker->numberBetween(1, 10),
|
||||
'account_id' => $faker->numberBetween(1, 10),
|
||||
'name' => $faker->words(3, true),
|
||||
'target_amount' => '1000.00',
|
||||
'startdate' => '2017-01-01',
|
||||
'order' => 1,
|
||||
'active' => 1,
|
||||
'encrypted' => 0,
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
$factory->define(
|
||||
FireflyIII\Models\Tag::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'id' => $faker->numberBetween(1, 10),
|
||||
'id' => $faker->numberBetween(100, 150),
|
||||
'user_id' => 1,
|
||||
'tagMode' => 'nothing',
|
||||
'tag' => $faker->words(1, true),
|
||||
];
|
||||
}
|
||||
@ -60,6 +142,31 @@ $factory->define(
|
||||
}
|
||||
);
|
||||
|
||||
$factory->define(
|
||||
FireflyIII\Models\PiggyBankEvent::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'id' => $faker->numberBetween(1, 10),
|
||||
'piggy_bank_id' => $faker->numberBetween(1, 10),
|
||||
'transaction_journal_id' => $faker->numberBetween(1, 10),
|
||||
'date' => $faker->date('Y-m-d'),
|
||||
'amount' => '100',
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
$factory->define(
|
||||
FireflyIII\Models\BudgetLimit::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'id' => $faker->numberBetween(1, 10),
|
||||
'start_date' => '2017-01-01',
|
||||
'end_date' => '2017-01-31',
|
||||
'amount' => '300',
|
||||
'budget_id' => $faker->numberBetween(1, 6),
|
||||
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
$factory->define(
|
||||
FireflyIII\Models\Account::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
@ -80,6 +187,7 @@ $factory->define(
|
||||
'description' => $faker->words(3, true),
|
||||
'source_account_name' => $faker->words(3, true),
|
||||
'destination_account_id' => $faker->numberBetween(1, 10),
|
||||
'date' => new Carbon,
|
||||
'destination_account_name' => $faker->words(3, true),
|
||||
'amount' => strval($faker->randomFloat(2, -100, 100)),
|
||||
'budget_id' => 0,
|
||||
|
@ -76,6 +76,23 @@ class CreateSupportTables extends Migration
|
||||
}
|
||||
}
|
||||
|
||||
private function createConfigurationTable()
|
||||
{
|
||||
if (!Schema::hasTable('configuration')) {
|
||||
Schema::create(
|
||||
'configuration', function (Blueprint $table) {
|
||||
|
||||
$table->increments('id');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->string('name', 50);
|
||||
$table->text('data');
|
||||
$table->unique(['name']);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ -99,23 +116,6 @@ class CreateSupportTables extends Migration
|
||||
}
|
||||
}
|
||||
|
||||
private function createConfigurationTable()
|
||||
{
|
||||
if (!Schema::hasTable('configuration')) {
|
||||
Schema::create(
|
||||
'configuration', function (Blueprint $table) {
|
||||
|
||||
$table->increments('id');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->string('name', 50);
|
||||
$table->text('data');
|
||||
$table->unique(['name']);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -18,6 +18,14 @@ use Illuminate\Database\Schema\Blueprint;
|
||||
*/
|
||||
class CreateUsersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('users');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
@ -40,12 +48,4 @@ class CreateUsersTable extends Migration
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('users');
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
|
||||
use FireflyIII\Models\Role;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
|
@ -8,11 +8,15 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
/** global: budgetChartUri */
|
||||
/** global: budgetChartUri,budgetLimitID */
|
||||
|
||||
$(function () {
|
||||
"use strict";
|
||||
|
||||
if (budgetLimitID > 0) {
|
||||
lineChart(budgetChartUri, 'budgetOverview');
|
||||
}
|
||||
if (budgetLimitID == 0) {
|
||||
columnChart(budgetChartUri, 'budgetOverview');
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'Nichts ausgewählt',
|
||||
'multi_select_all_selected' => 'Alle ausgewählt',
|
||||
'multi_select_filter_placeholder' => 'Suche..',
|
||||
'between_dates_breadcrumb' => 'Between :start and :end',
|
||||
'all_journals_without_budget' => 'All transactions without a budget',
|
||||
'journals_without_budget' => 'Transactions without a budget',
|
||||
'all_journals_without_category' => 'All transactions without a category',
|
||||
'journals_without_category' => 'Transactions without a category',
|
||||
'all_journals_for_account' => 'All transactions for account :name',
|
||||
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
|
||||
'transferred' => 'Transferred',
|
||||
'all_withdrawal' => 'All expenses',
|
||||
'all_transactions' => 'All transactions',
|
||||
'title_withdrawal_between' => 'All expenses between :start and :end',
|
||||
'all_deposit' => 'All revenue',
|
||||
'title_deposit_between' => 'All revenue between :start and :end',
|
||||
'all_transfers' => 'All transfers',
|
||||
'title_transfers_between' => 'All transfers between :start and :end',
|
||||
'all_transfer' => 'All transfers',
|
||||
'title_transfer_between' => 'All transfers between :start and :end',
|
||||
'all_journals_for_category' => 'All transactions for category :name',
|
||||
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
|
||||
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
@ -855,7 +875,7 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?',
|
||||
'tag_title_nothing' => 'Standard-Tags',
|
||||
'tag_title_balancingAct' => 'Ausgleich Tags',
|
||||
'tag_title_advancePayment' => 'Vorauszahlung Tags',
|
||||
'tags_introduction' => 'In der Regel sind Tags einzelne Worte, erdacht um Einträge mit Begriffen wie <span class="label label-info">Ausgaben</span>, <span class="label label-info">Rechnungen</span> oder <span class="label label-info">Partyvorbereitung</span> schnell zusammenzufassen. In Firefly III können Tags weitere Eigenschaften wie ein Datum, eine Beschreibung und einen Ort enthalten. Dieses erlaubt es Ihnen Transaktionen in sinnvoller Weise miteinander zu verknüpfen. Zum Beispiel können Sie einen Tag mit dem Titel <span class="label label-success"> Weihnachtsessen mit Freunden</span> erstellen und Informationen über das Restaurant hinzufügen. Solche Tags sind "einzigartig", sie werden nur für einen Anlass genutzt, enthalten aber eventuell mehrere Transaktionen.',
|
||||
'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like <span class="label label-info">expensive</span>, <span class="label label-info">bill</span> or <span class="label label-info">for-party</span>. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called <span class="label label-success">Christmas dinner with friends</span> and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.',
|
||||
'tags_group' => 'Tags group transactions together, which makes it possible to store reimbursements (in case you front money for others) and other "balancing acts" where expenses are summed up (the payments on your new TV) or where expenses and deposits are cancelling each other out (buying something with saved money). It\'s all up to you. Using tags the old-fashioned way is of course always possible.',
|
||||
'tags_start' => 'Create a tag to get started or enter tags when creating new transactions.',
|
||||
|
||||
|
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'None selected',
|
||||
'multi_select_all_selected' => 'All selected',
|
||||
'multi_select_filter_placeholder' => 'Find..',
|
||||
'between_dates_breadcrumb' => 'Between :start and :end',
|
||||
'all_journals_without_budget' => 'All transactions without a budget',
|
||||
'journals_without_budget' => 'Transactions without a budget',
|
||||
'all_journals_without_category' => 'All transactions without a category',
|
||||
'journals_without_category' => 'Transactions without a category',
|
||||
'all_journals_for_account' => 'All transactions for account :name',
|
||||
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
|
||||
'transferred' => 'Transferred',
|
||||
'all_withdrawal' => 'All expenses',
|
||||
'all_transactions' => 'All transactions',
|
||||
'title_withdrawal_between' => 'All expenses between :start and :end',
|
||||
'all_deposit' => 'All revenue',
|
||||
'title_deposit_between' => 'All revenue between :start and :end',
|
||||
'all_transfers' => 'All transfers',
|
||||
'title_transfers_between' => 'All transfers between :start and :end',
|
||||
'all_transfer' => 'All transfers',
|
||||
'title_transfer_between' => 'All transfers between :start and :end',
|
||||
'all_journals_for_category' => 'All transactions for category :name',
|
||||
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
|
||||
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
|
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'None selected',
|
||||
'multi_select_all_selected' => 'All selected',
|
||||
'multi_select_filter_placeholder' => 'Find..',
|
||||
'between_dates_breadcrumb' => 'Between :start and :end',
|
||||
'all_journals_without_budget' => 'All transactions without a budget',
|
||||
'journals_without_budget' => 'Transactions without a budget',
|
||||
'all_journals_without_category' => 'All transactions without a category',
|
||||
'journals_without_category' => 'Transactions without a category',
|
||||
'all_journals_for_account' => 'All transactions for account :name',
|
||||
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
|
||||
'transferred' => 'Transferred',
|
||||
'all_withdrawal' => 'All expenses',
|
||||
'all_transactions' => 'All transactions',
|
||||
'title_withdrawal_between' => 'All expenses between :start and :end',
|
||||
'all_deposit' => 'All revenue',
|
||||
'title_deposit_between' => 'All revenue between :start and :end',
|
||||
'all_transfers' => 'All transfers',
|
||||
'title_transfers_between' => 'All transfers between :start and :end',
|
||||
'all_transfer' => 'All transfers',
|
||||
'title_transfer_between' => 'All transfers between :start and :end',
|
||||
'all_journals_for_category' => 'All transactions for category :name',
|
||||
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
|
||||
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
|
@ -15,7 +15,7 @@ return [
|
||||
'month_and_day' => '%e %B %Y',
|
||||
'date_time' => '%B %e %Y @ %T',
|
||||
'specific_day' => '%e %B %Y',
|
||||
'week_in_year' => '%W %Y',
|
||||
'week_in_year' => 'Semaine %W %Y',
|
||||
'quarter_of_year' => '%B %Y',
|
||||
'year' => '%Y',
|
||||
'half_year' => '%B %Y',
|
||||
|
@ -15,7 +15,7 @@ return [
|
||||
|
||||
'import_configure_title' => 'Configurer l\'import',
|
||||
'import_configure_intro' => 'Il y a des options pour l\'import CSV. Veuillez indiquer si votre fichier CSV contient les en-têtes dans la première colonne, et quel est le format des dates de vos champs date. Cela peut nécessiter quelques essais. Le délimiteur de champ est généralement un « , », mais pourrait également être un « ; ». Cochez cette case avec soin.',
|
||||
'import_configure_form' => 'Basic CSV import options',
|
||||
'import_configure_form' => 'Options d’importation CSV basique',
|
||||
'header_help' => 'Cochez cette case si la première ligne de votre fichier CSV contient les entêtes des colonnes',
|
||||
'date_help' => 'Le format de la date et de l’heure dans votre fichier CSV. Utiliser les formats comme indiqué sur <a href="https://secure.php.net/manual/en/datetime.createfromformat.php#refsect1-datetime.createfromformat-parameters">cette page</a>. La valeur par défaut va analyser les dates ressemblant à ceci: :dateExample.',
|
||||
'delimiter_help' => 'Choisissez le délimiteur de champ qui est utilisé dans votre fichier d’entrée. Si vous n’êtes pas certain, la virgule est l’option la plus sûre.',
|
||||
|
@ -8,17 +8,17 @@
|
||||
*/
|
||||
|
||||
return [
|
||||
'no_demo_text' => 'Sorry, there is no extra demo-explanation text for <abbr title=":route">this page</abbr>.',
|
||||
'see_help_icon' => 'However, the <i class="fa fa-question-circle"></i>-icon in the top right corner may tell you more.',
|
||||
'index' => 'Welcome to <strong>Firefly III</strong>! On this page you get a quick overview of your finances. For more information, check out Accounts → <a href=":asset">Asset Accounts</a> and of course the <a href=":budgets">Budgets</a> and <a href=":reports">Reports</a> pages. Or just take a look around and see where you end up.',
|
||||
'no_demo_text' => 'Désolé, il n’y a aucun texte supplémentaire de démonstration ou d\'explication pour <abbr title=":route"> cette page</abbr>.',
|
||||
'see_help_icon' => 'Cependant, l\'icône <i class="fa fa-question-circle"></i> située dans le coin supérieur droit peut vous en dire plus.',
|
||||
'index' => 'Bienvenue chez <strong>Firefly III</strong> ! Sur cette page, vous obtenez un aperçu rapide de vos finances. Pour plus d’informations, consultez comptes → <a href=":asset"> Comptes d’actif</a> et, bien sûr, les pages des <a href=":budgets"> Budgets</a> et des <a href=":reports"> rapports</a>. Ou juste jetez un coup d’œil et voyez où vous vous retrouvez.',
|
||||
'accounts-index' => 'Asset accounts are your personal bank accounts. Expense accounts are the accounts you spend money at, such as stores and friends. Revenue accounts are accounts you receive money from, such as your job, the government or other sources of income. On this page you can edit or remove them.',
|
||||
'budgets-index' => 'This page shows you an overview of your budgets. The top bar shows the amount that is available to be budgeted. This can be customized for any period by clicking the amount on the right. The amount you\'ve actually spent is shown in the bar below. Below that are the expenses per budget and what you\'ve budgeted for them.',
|
||||
'reports-index-start' => 'Firefly III supports four types of reports. Read about them by clicking on the <i class="fa fa-question-circle"></i>-icon in the top right corner.',
|
||||
'reports-index-examples' => 'Be sure to check out these examples: <a href=":one">a monthly financial overview</a>, <a href=":two">a yearly financial overview</a> and <a href=":three">a budget overview</a>.',
|
||||
'currencies-index' => 'Firefly III supports multiple currencies. Although it defaults to the Euro it can be set to the US Dollar and many other currencies. As you can see a small selection of currencies has been included but you can add your own if you wish to. Changing the default currency will not change the currency of existing transactions however: Firefly III supports the use of multiple currencies at the same time.',
|
||||
'transactions-index' => 'These expenses, deposits and transfers are not particularly imaginative. They have been generated automatically.',
|
||||
'piggy-banks-index' => 'As you can see, there are three piggy banks. Use the plus and minus buttons to influence the amount of money in each piggy bank. Click the name of the piggy bank to see the administration for each piggy bank.',
|
||||
'import-index' => 'Of course, any CSV file can be imported into Firefly III ',
|
||||
'import-configure-security' => 'Because of security concerns, your upload has been replaced with a local file.',
|
||||
'import-configure-configuration' => 'The configuration you see below is correct for the local file.',
|
||||
'budgets-index' => 'Cette page vous présente un aperçu de vos budgets. La barre du haut affiche le montant disponible à budgétiser. Cela peut être personnalisé pour toute période en cliquant sur le montant sur la droite. Le montant que vous avez réellement dépensé s’affiche dans la barre ci-dessous. Visualisez ainsi les dépenses budgétisées et votre prévisionnel.',
|
||||
'reports-index-start' => 'Firefly III prend en charge quatre types de rapports. Apprenez-en plus à leur sujet en cliquant sur l\'icône <i class="fa fa-question-circle"></i> située dans le coin supérieur droit.',
|
||||
'reports-index-examples' => 'N’oubliez pas de consultez ces exemples : <a href=":one"> un aperçu financier mensuel</a>, <a href=":two"> une vue d’ensemble financière annuelle</a> ainsi <a href=":three"> qu’une présentation du budget</a>.',
|
||||
'currencies-index' => 'Firefly III prend en charge plusieurs devises. Bien que l\'Euro soit la devise par défaut, cette dernière peut être changée pour le Dollar américain et de nombreuses autres devises. Comme vous pouvez le remarquer une petite sélection des monnaies a été incluse, mais vous pouvez ajouter vos propres devises si vous le souhaitez. Gardez à l\'esprit que la modification de la devise par défaut ne modifie pas la monnaie des transactions existantes : Firefly III prend en charge l’utilisation de plusieurs devises en même temps.',
|
||||
'transactions-index' => 'Ces dépenses, dépôts et transferts ne sont pas particulièrement imaginatifs. Ils ont été générés automatiquement.',
|
||||
'piggy-banks-index' => 'Comme vous pouvez le voir, il y a trois tirelires. Utilisez les boutons plus et moins pour influer sur le montant d’argent dans chaque tirelire. Cliquez sur le nom de la tirelire pour voir l’administration pour chaque tirelire.',
|
||||
'import-index' => 'Bien sûr, n’importe quel fichier CSV peut être importé dans Firefly III ',
|
||||
'import-configure-security' => 'Pour des raisons de sécurité, votre téléchargement a été remplacé par un fichier local.',
|
||||
'import-configure-configuration' => 'La configuration que vous voyez ci-dessous est correcte pour le fichier local.',
|
||||
];
|
@ -26,7 +26,7 @@ return [
|
||||
'showEverything' => 'Tout Afficher',
|
||||
'never' => 'Jamais',
|
||||
'search_results_for' => 'Résultats de recherche pour ":query"',
|
||||
'advanced_search' => 'Advanced search',
|
||||
'advanced_search' => 'Recherche avancée',
|
||||
'advanced_search_intro' => 'There are several modifiers that you can use in your search to narrow down the results. If you use any of these, the search will <em>only</em> return transactions. Please click the <i class="fa fa-question-circle"></i>-icon for more information.',
|
||||
'bounced_error' => 'Le message envoyé à :email a été rejeté, donc pas d\'accès pour vous.',
|
||||
'deleted_error' => 'Ces informations d\'identification ne sont pas présentes dans nos données.',
|
||||
@ -53,8 +53,8 @@ return [
|
||||
'flash_info_multiple' => 'Il y a un message| Il y a :count messages',
|
||||
'flash_error_multiple' => 'Il y a une erreur|Il y a :count errors',
|
||||
'net_worth' => 'Valeur nette',
|
||||
'route_has_no_help' => 'There is no help for this route.',
|
||||
'help_may_not_be_your_language' => 'This help text is in English. It is not yet available in your language',
|
||||
'route_has_no_help' => 'Il n\'y a pas d\'aide pour cette page.',
|
||||
'help_may_not_be_your_language' => 'Ce texte d’aide est en anglais. Il n’est pas encore disponible dans votre langue',
|
||||
'two_factor_welcome' => 'Bonjour, :user !',
|
||||
'two_factor_enter_code' => 'Pour continuer, veuillez entrer votre code d’authentification à deux facteurs. Votre application peut la générer pour vous.',
|
||||
'two_factor_code_here' => 'Entrez votre code ici',
|
||||
@ -69,12 +69,12 @@ return [
|
||||
'warning_much_data' => ':days de données peuvent prendre un certain temps à charger.',
|
||||
'registered' => 'Vous avez été enregistré avec succès !',
|
||||
'search' => 'Rechercher',
|
||||
'search_found_accounts' => 'Found :count account(s) for your query.',
|
||||
'search_found_categories' => 'Found :count category(ies) for your query.',
|
||||
'search_found_budgets' => 'Found :count budget(s) for your query.',
|
||||
'search_found_tags' => 'Found :count tag(s) for your query.',
|
||||
'search_found_transactions' => 'Found :count transaction(s) for your query.',
|
||||
'results_limited' => 'The results are limited to :count entries.',
|
||||
'search_found_accounts' => 'Trouvé :count compte(s) correspondant à votre requête.',
|
||||
'search_found_categories' => 'Trouvé :count catégorie(s) correspondant à votre requête.',
|
||||
'search_found_budgets' => 'Trouvé :count budget(s) correspondant à votre requête.',
|
||||
'search_found_tags' => 'Trouvé :count mot(s)-clef(s) correspondant à votre requête.',
|
||||
'search_found_transactions' => 'Trouvé :count transaction(s) correspondant à votre requête.',
|
||||
'results_limited' => 'Les résultats sont limités à :count entrées.',
|
||||
'tagbalancingAct' => 'Balancing act',
|
||||
'tagadvancePayment' => 'Advance payment',
|
||||
'tagnothing' => '',
|
||||
@ -84,26 +84,26 @@ return [
|
||||
'Credit card' => 'Credit card',
|
||||
'source_accounts' => 'Compte(s) source',
|
||||
'destination_accounts' => 'Compte(s) de destination',
|
||||
'user_id_is' => 'Your user id is <strong>:user</strong>',
|
||||
'field_supports_markdown' => 'This field supports <a href="https://en.support.wordpress.com/markdown-quick-reference/">Markdown</a>.',
|
||||
'need_more_help' => 'If you need more help using Firefly III, please <a href="https://github.com/firefly-iii/firefly-iii/issues">open a ticket on Github</a>.',
|
||||
'nothing_to_display' => 'There are no transactions to show you',
|
||||
'show_all_no_filter' => 'Show all transactions without grouping them by date.',
|
||||
'expenses_by_category' => 'Expenses by category',
|
||||
'expenses_by_budget' => 'Expenses by budget',
|
||||
'income_by_category' => 'Income by category',
|
||||
'cannot_redirect_to_account' => 'Firefly III cannot redirect you to the correct page. Apologies.',
|
||||
'sum_of_expenses' => 'Sum of expenses',
|
||||
'sum_of_income' => 'Sum of income',
|
||||
'user_id_is' => 'Votre identifiant d’utilisateur est <strong>:user</strong>',
|
||||
'field_supports_markdown' => 'Ce champ prend en charge la <a href="https://en.support.wordpress.com/markdown-quick-reference/">syntaxe Markdown</a>.',
|
||||
'need_more_help' => 'Si vous désirez plus de renseignements sur l\'utilisation de Firefly III, merci <a href="https://github.com/firefly-iii/firefly-iii/issues">d\'ouvrir un ticket sur Github</a>.',
|
||||
'nothing_to_display' => 'Il n’y a aucune transaction à afficher',
|
||||
'show_all_no_filter' => 'Montrer toutes les transactions sans les classer par date.',
|
||||
'expenses_by_category' => 'Dépenses par catégorie',
|
||||
'expenses_by_budget' => 'Dépenses par budget',
|
||||
'income_by_category' => 'Revenu par catégorie',
|
||||
'cannot_redirect_to_account' => 'Firefly III n\'est pas en mesure de vous rediriger vers la bonne page. Veuillez nous en excuser.',
|
||||
'sum_of_expenses' => 'Montant des dépenses',
|
||||
'sum_of_income' => 'Montant des revenus',
|
||||
'spent_in_specific_budget' => 'Spent in budget ":budget"',
|
||||
'sum_of_expenses_in_budget' => 'Spent total in budget ":budget"',
|
||||
'left_in_budget_limit' => 'Left to spend according to budgeting',
|
||||
'cannot_change_demo' => 'You cannot change the password of the demonstration account.',
|
||||
'cannot_delete_demo' => 'You cannot remove the demonstration account.',
|
||||
'cannot_reset_demo_user' => 'You cannot reset the password of the demonstration account',
|
||||
'cannot_change_demo' => 'Vous ne pouvez pas modifier le mot de passe du compte de démonstration.',
|
||||
'cannot_delete_demo' => 'Vous ne pouvez pas supprimer le compte de démonstration.',
|
||||
'cannot_reset_demo_user' => 'Vous ne pouvez pas réinitialiser le mot de passe du compte démonstration',
|
||||
'per_period' => 'Per period',
|
||||
'all_periods' => 'All periods',
|
||||
'current_period' => 'Current period',
|
||||
'all_periods' => 'Toutes les périodes',
|
||||
'current_period' => 'Période en cours',
|
||||
'show_the_current_period_and_overview' => 'Show the current period and overview',
|
||||
'pref_languages_locale' => 'For a language other than English to work properly, your operating system must be equipped with the correct locale-information. If these are not present, currency data, dates and amounts may be formatted wrong.',
|
||||
'budget_in_period' => '":name" between :start and :end',
|
||||
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'None selected',
|
||||
'multi_select_all_selected' => 'All selected',
|
||||
'multi_select_filter_placeholder' => 'Find..',
|
||||
'between_dates_breadcrumb' => 'Between :start and :end',
|
||||
'all_journals_without_budget' => 'All transactions without a budget',
|
||||
'journals_without_budget' => 'Transactions without a budget',
|
||||
'all_journals_without_category' => 'All transactions without a category',
|
||||
'journals_without_category' => 'Transactions without a category',
|
||||
'all_journals_for_account' => 'All transactions for account :name',
|
||||
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
|
||||
'transferred' => 'Transferred',
|
||||
'all_withdrawal' => 'All expenses',
|
||||
'all_transactions' => 'All transactions',
|
||||
'title_withdrawal_between' => 'All expenses between :start and :end',
|
||||
'all_deposit' => 'All revenue',
|
||||
'title_deposit_between' => 'All revenue between :start and :end',
|
||||
'all_transfers' => 'All transfers',
|
||||
'title_transfers_between' => 'All transfers between :start and :end',
|
||||
'all_transfer' => 'All transfers',
|
||||
'title_transfer_between' => 'All transfers between :start and :end',
|
||||
'all_journals_for_category' => 'All transactions for category :name',
|
||||
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
|
||||
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
@ -854,7 +874,7 @@ return [
|
||||
'tag_title_nothing' => 'Tags par défaut',
|
||||
'tag_title_balancingAct' => 'Balancing act tags',
|
||||
'tag_title_advancePayment' => 'Tags de paiement anticipé',
|
||||
'tags_introduction' => 'Les tags sont généralement des mots au singulier, conçus pour grouper rapidement des éléments en utilisant des mots comme <span class="label label-info">cher</span>, <span class="label label-info">factures</span> ou <span class="label label-info">pour-fêtes</span>. Dans Firefly III, les tags peuvent avoir plus de propriétés comme une date, la description et l’emplacement. Cela vous permet de réunir des opérations de façon plus significative. Par exemple, vous pourriez faire un tag appelé <span class="label label-success">Dîner de Noël avec des amis</span> et ajouter des informations sur le restaurant. Ces tags sont au singulier, vous devez seulement les utiliser pour une occasion unique, peut-être avec plusieurs opérations.',
|
||||
'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like <span class="label label-info">expensive</span>, <span class="label label-info">bill</span> or <span class="label label-info">for-party</span>. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called <span class="label label-success">Christmas dinner with friends</span> and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.',
|
||||
'tags_group' => 'Les tags groupent des opérations ensemble, ce qui permet de stocker des remboursements (dans le cas où vous avancer de l\'argent aux autres) et d\'autres types "d\'équilibres" où résumer les dépenses (les remboursements de votre nouvelle TV) ou quand les dépenses et les dépôts s\'annulent les uns les autres (achat de quelque chose avec de l\'argent mis de coté). C\'est comme vous souhaitez. Utiliser les tags à l\'ancienne est toujours possible.',
|
||||
'tags_start' => 'Create a tag to get started or enter tags when creating new transactions.',
|
||||
|
||||
|
@ -25,17 +25,17 @@ return [
|
||||
'match' => 'Correspondre à',
|
||||
'repeat_freq' => 'Répétitions',
|
||||
'journal_currency_id' => 'Devise',
|
||||
'currency_id' => 'Currency',
|
||||
'attachments' => 'Attachments',
|
||||
'currency_id' => 'Devise',
|
||||
'attachments' => 'Documents joints',
|
||||
'journal_amount' => 'Montant',
|
||||
'journal_asset_source_account' => 'Compte d’actif (source)',
|
||||
'journal_source_account_name' => 'Compte de recettes (source)',
|
||||
'journal_source_account_id' => 'Compte d’actif (source)',
|
||||
'BIC' => 'BIC',
|
||||
'BIC' => 'Code BIC',
|
||||
'account_from_id' => 'Compte d\'origine',
|
||||
'account_to_id' => 'Compte de destination',
|
||||
'source_account' => 'Source account',
|
||||
'destination_account' => 'Destination account',
|
||||
'source_account' => 'Compte d\'origine',
|
||||
'destination_account' => 'Compte destinataire',
|
||||
'journal_destination_account_id' => 'Compte d’actif (destination)',
|
||||
'asset_destination_account' => 'Compte d’actif (destination)',
|
||||
'asset_source_account' => 'Compte d’actif (source)',
|
||||
@ -82,15 +82,15 @@ return [
|
||||
'book_date' => 'Book date',
|
||||
'process_date' => 'Date de traitement',
|
||||
'category' => 'Catégorie',
|
||||
'tags' => 'Tags',
|
||||
'tags' => 'Mots-clés',
|
||||
'deletePermanently' => 'Supprimer définitivement',
|
||||
'cancel' => 'Annuler',
|
||||
'targetdate' => 'Date cible',
|
||||
'tag' => 'Tag',
|
||||
'tag' => 'Mot-clé',
|
||||
'under' => 'En dessous de',
|
||||
'symbol' => 'Symbole',
|
||||
'code' => 'Code',
|
||||
'iban' => 'IBAN',
|
||||
'iban' => 'Numéro IBAN',
|
||||
'accountNumber' => 'N° de compte',
|
||||
'has_headers' => 'Entêtes ',
|
||||
'date_format' => 'Format de la date',
|
||||
@ -151,18 +151,18 @@ return [
|
||||
'category_keep_transactions' => 'La seule opération liée à cette catégorie ne sera pas supprimée.|Les :count opérations liées à cette catégorie ne seront pas supprimées.',
|
||||
'tag_keep_transactions' => 'La seule opération liée à ce tag ne sera pas supprimée.|Les :count opérations liées à ce tag ne seront pas supprimées.',
|
||||
|
||||
'email' => 'Email address',
|
||||
'password' => 'Password',
|
||||
'password_confirmation' => 'Password (again)',
|
||||
'blocked' => 'Is blocked?',
|
||||
'blocked_code' => 'Reason for block',
|
||||
'email' => 'Adresse Email',
|
||||
'password' => 'Mot de passe',
|
||||
'password_confirmation' => 'Entrer à nouveau le mot de passe',
|
||||
'blocked' => 'Est bloqué?',
|
||||
'blocked_code' => 'Raison du blocage',
|
||||
|
||||
|
||||
// admin
|
||||
'domain' => 'Domaine',
|
||||
'single_user_mode' => 'Mode utilisateur unique',
|
||||
'must_confirm_account' => 'New users must activate account',
|
||||
'is_demo_site' => 'Is demo site',
|
||||
'must_confirm_account' => 'Les nouveaux utilisateurs doivent activer le compte',
|
||||
'is_demo_site' => 'Est un site de démonstration',
|
||||
|
||||
|
||||
// import
|
||||
|
@ -12,7 +12,7 @@
|
||||
return [
|
||||
'buttons' => 'Boutons',
|
||||
'icon' => 'Icône',
|
||||
'id' => 'ID',
|
||||
'id' => 'Identifiant',
|
||||
'create_date' => 'Créé le',
|
||||
'update_date' => 'Mis à jour le',
|
||||
'balance_before' => 'Solde avant',
|
||||
@ -26,7 +26,7 @@ return [
|
||||
'matchedOn' => 'Correspond à',
|
||||
'matchesOn' => 'Correspond à',
|
||||
'account_type' => 'Type de compte',
|
||||
'created_at' => 'Created at',
|
||||
'created_at' => 'Créé le',
|
||||
'new_balance' => 'Nouveau solde',
|
||||
'account' => 'Compte',
|
||||
'matchingAmount' => 'Montant',
|
||||
@ -39,12 +39,12 @@ return [
|
||||
'repeat_freq' => 'Répétitions',
|
||||
'description' => 'Description',
|
||||
'amount' => 'Montant',
|
||||
'internal_reference' => 'Internal reference',
|
||||
'internal_reference' => 'Référence interne',
|
||||
'date' => 'Date',
|
||||
'interest_date' => 'Date des intérêts',
|
||||
'book_date' => 'Book date',
|
||||
'book_date' => 'Date de réservation',
|
||||
'process_date' => 'Date de traitement',
|
||||
'due_date' => 'Due date',
|
||||
'due_date' => 'Échéance',
|
||||
'payment_date' => 'Date de paiement',
|
||||
'invoice_date' => 'Date de facturation',
|
||||
'interal_reference' => 'Référence interne',
|
||||
@ -60,7 +60,7 @@ return [
|
||||
'transfer' => 'Transfert',
|
||||
'type' => 'Type',
|
||||
'completed' => 'Terminé',
|
||||
'iban' => 'IBAN',
|
||||
'iban' => 'Numéro IBAN',
|
||||
'paid_current_period' => 'Payé cette période',
|
||||
'email' => 'E-mail',
|
||||
'registered_at' => 'Enregistré le',
|
||||
@ -69,21 +69,21 @@ return [
|
||||
'is_admin' => 'Est admin',
|
||||
'has_two_factor' => 'A 2FA',
|
||||
'confirmed_from' => 'Confirmed from',
|
||||
'registered_from' => 'Registered from',
|
||||
'registered_from' => 'Inscrit depuis le',
|
||||
'blocked_code' => 'Code de blocage',
|
||||
'domain' => 'Domaine',
|
||||
'registration_attempts' => 'Registration attempts',
|
||||
'source_account' => 'Source account',
|
||||
'destination_account' => 'Destination account',
|
||||
'source_account' => 'Compte d\'origine',
|
||||
'destination_account' => 'Compte destinataire',
|
||||
|
||||
'accounts_count' => 'Number of accounts',
|
||||
'journals_count' => 'Number of transactions',
|
||||
'attachments_count' => 'Number of attachments',
|
||||
'accounts_count' => 'Nombre de comptes',
|
||||
'journals_count' => 'Nombre d\'opérations',
|
||||
'attachments_count' => 'Nombre de pièces jointes',
|
||||
'bills_count' => 'Number of bills',
|
||||
'categories_count' => 'Number of categories',
|
||||
'export_jobs_count' => 'Number of export jobs',
|
||||
'import_jobs_count' => 'Number of import jobs',
|
||||
'budget_count' => 'Number of budgets',
|
||||
'rule_and_groups_count' => 'Number of rules and rule groups',
|
||||
'rule_and_groups_count' => 'Nombre de règles et de groupes de règles',
|
||||
'tags_count' => 'Number of tags',
|
||||
];
|
@ -12,7 +12,7 @@
|
||||
return [
|
||||
'iban' => 'Il ne s\'agit pas d\'un IBAN valide.',
|
||||
'unique_account_number_for_user' => 'Il semble que ce numéro de compte est déjà utilisé.',
|
||||
'deleted_user' => 'Due to security constraints, you cannot register using this email address.',
|
||||
'deleted_user' => 'Compte tenu des contraintes de sécurité, vous ne pouvez pas vous inscrire en utilisant cette adresse e-mail.',
|
||||
'rule_trigger_value' => 'Cette valeur n’est pas valide pour le déclencheur sélectionné.',
|
||||
'rule_action_value' => 'Cette valeur n’est pas valide pour l’action sélectionnée.',
|
||||
'invalid_domain' => 'Compte tenu des contraintes de sécurité, vous ne pouvez pas vous enregistrer depuis ce domaine.',
|
||||
@ -22,8 +22,8 @@ return [
|
||||
'file_too_large' => 'Le fichier ":name" est trop grand.',
|
||||
'belongs_to_user' => 'La valeur de :attribute est inconnue',
|
||||
'accepted' => 'Le champ :attribute doit être accepté.',
|
||||
'bic' => 'This is not a valid BIC.',
|
||||
'more' => ':attribute must be larger than zero.',
|
||||
'bic' => 'Ce n’est pas un code BIC valide.',
|
||||
'more' => ':attribute doit être supérieur à zéro.',
|
||||
'active_url' => 'Le champ :attribute n\'est pas une URL valide.',
|
||||
'after' => 'Le champ :attribute doit être une date postérieure à :date.',
|
||||
'alpha' => 'Le champ :attribute doit seulement contenir des lettres.',
|
||||
@ -82,10 +82,10 @@ return [
|
||||
'url' => 'Le format de l\'URL de :attribute n\'est pas valide.',
|
||||
'timezone' => 'Le champ :attribute doit être un fuseau horaire valide.',
|
||||
'2fa_code' => 'Le champ :attribute est invalide.',
|
||||
'dimensions' => 'The :attribute has invalid image dimensions.',
|
||||
'distinct' => 'The :attribute field has a duplicate value.',
|
||||
'file' => 'The :attribute must be a file.',
|
||||
'in_array' => 'The :attribute field does not exist in :other.',
|
||||
'present' => 'The :attribute field must be present.',
|
||||
'amount_zero' => 'The total amount cannot be zero',
|
||||
'dimensions' => 'Le :attribute possède des dimensions d’image non valides.',
|
||||
'distinct' => ':attribute possède une valeur en double.',
|
||||
'file' => 'Le :attribute doit être un fichier.',
|
||||
'in_array' => 'Le champ :attribute n\'existe pas dans :other.',
|
||||
'present' => 'Le champs :attribute doit être rempli.',
|
||||
'amount_zero' => 'Le montant total ne peut pas être zéro',
|
||||
];
|
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'None selected',
|
||||
'multi_select_all_selected' => 'All selected',
|
||||
'multi_select_filter_placeholder' => 'Find..',
|
||||
'between_dates_breadcrumb' => 'Between :start and :end',
|
||||
'all_journals_without_budget' => 'All transactions without a budget',
|
||||
'journals_without_budget' => 'Transactions without a budget',
|
||||
'all_journals_without_category' => 'All transactions without a category',
|
||||
'journals_without_category' => 'Transactions without a category',
|
||||
'all_journals_for_account' => 'All transactions for account :name',
|
||||
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
|
||||
'transferred' => 'Transferred',
|
||||
'all_withdrawal' => 'All expenses',
|
||||
'all_transactions' => 'All transactions',
|
||||
'title_withdrawal_between' => 'All expenses between :start and :end',
|
||||
'all_deposit' => 'All revenue',
|
||||
'title_deposit_between' => 'All revenue between :start and :end',
|
||||
'all_transfers' => 'All transfers',
|
||||
'title_transfers_between' => 'All transfers between :start and :end',
|
||||
'all_transfer' => 'All transfers',
|
||||
'title_transfer_between' => 'All transfers between :start and :end',
|
||||
'all_journals_for_category' => 'All transactions for category :name',
|
||||
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
|
||||
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
|
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'Niets geselecteerd',
|
||||
'multi_select_all_selected' => 'Alles geselecteerd',
|
||||
'multi_select_filter_placeholder' => 'Vinden..',
|
||||
'between_dates_breadcrumb' => 'Tussen :start en :end',
|
||||
'all_journals_without_budget' => 'Alle transacties zonder budget',
|
||||
'journals_without_budget' => 'Transacties zonder budget',
|
||||
'all_journals_without_category' => 'Alle transacties zonder categorie',
|
||||
'journals_without_category' => 'Transacties zonder categorie',
|
||||
'all_journals_for_account' => 'Alle transacties voor rekening :name',
|
||||
'journals_in_period_for_account' => 'Alle transacties voor rekening :name tussen :start en :end',
|
||||
'transferred' => 'Overgeschreven',
|
||||
'all_withdrawal' => 'Alle uitgaven',
|
||||
'all_transactions' => 'Alle transacties',
|
||||
'title_withdrawal_between' => 'Alle uitgaven tussen :start en :end',
|
||||
'all_deposit' => 'Alle inkomsten',
|
||||
'title_deposit_between' => 'Alle inkomsten tussen :start en :end',
|
||||
'all_transfers' => 'Alle overschrijvingen',
|
||||
'title_transfers_between' => 'Alle overschrijvingen tussen :start en :end',
|
||||
'all_transfer' => 'Alle overschrijvingen',
|
||||
'title_transfer_between' => 'Alle overschrijvingen tussen :start en :end',
|
||||
'all_journals_for_category' => 'Alle transacties in categorie :name',
|
||||
'journals_in_period_for_category' => 'Alle transacties in categorie :name tussen :start en :end',
|
||||
'not_available_demo_user' => 'De functie die je probeert te gebruiken is niet beschikbaar voor gebruikers van de demo.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
@ -997,32 +1017,32 @@ return [
|
||||
'no_budgets_create_default' => 'Maak een budget',
|
||||
'no_categories_title_default' => 'Je hebt een categorie nodig!',
|
||||
'no_categories_intro_default' => 'Je hebt nog geen categorieën. Categorieën gebruik je om je transacties gedetailleerd in te delen.',
|
||||
'no_categories_imperative_default' => 'Categories are created automatically when you create transactions, but you can create one manually too. Let\'s create one now:',
|
||||
'no_categories_create_default' => 'Create a category',
|
||||
'no_categories_imperative_default' => 'Categorieën worden automatisch aangemaakt als je transacties maakt, maar dit kan ook met de hand. Zoals nu:',
|
||||
'no_categories_create_default' => 'Maak een categorie',
|
||||
'no_tags_title_default' => 'Je hebt tags nodig!',
|
||||
'no_tags_intro_default' => 'You have no tags yet. Tags are used to fine tune your transactions and label them with specific keywords.',
|
||||
'no_tags_imperative_default' => 'Tags are created automatically when you create transactions, but you can create one manually too. Let\'s create one now:',
|
||||
'no_tags_create_default' => 'Create a tag',
|
||||
'no_tags_intro_default' => 'Je hebt nog geen tags. Tags gebruik je om je transacties te voorzien van specifieke keywords.',
|
||||
'no_tags_imperative_default' => 'Tags worden automatisch gemaakt als je ze toevoegt aan een transactie, maar dit kan ook met de hand. Zoals nu:',
|
||||
'no_tags_create_default' => 'Maak een tag',
|
||||
'no_transactions_title_withdrawal' => 'Je hebt uitgaven nodig!',
|
||||
'no_transactions_intro_withdrawal' => 'You have no expenses yet. You should create expenses to start managing your finances.',
|
||||
'no_transactions_imperative_withdrawal' => 'Have you spent some money? Then you should write it down:',
|
||||
'no_transactions_create_withdrawal' => 'Create an expense',
|
||||
'no_transactions_intro_withdrawal' => 'Je hebt nog geen uitgaven opgeslagen. Doe dit om te beginnen met het beheren van je financiën.',
|
||||
'no_transactions_imperative_withdrawal' => 'Heb je geld uitgegeven? Schrijf het dan op:',
|
||||
'no_transactions_create_withdrawal' => 'Registreer een uitgave',
|
||||
'no_transactions_title_deposit' => 'Je hebt inkomsten nodig!',
|
||||
'no_transactions_intro_deposit' => 'You have no recorded income yet. You should create income entries to start managing your finances.',
|
||||
'no_transactions_imperative_deposit' => 'Have you received some money? Then you should write it down:',
|
||||
'no_transactions_create_deposit' => 'Create a deposit',
|
||||
'no_transactions_intro_deposit' => 'Je hebt nog geen inkomsten opgeslagen. Doe dit om te beginnen met het beheren van je financiën.',
|
||||
'no_transactions_imperative_deposit' => 'Heb je geld ontvangen? Schrijf het dan op:',
|
||||
'no_transactions_create_deposit' => 'Registreer inkomsten',
|
||||
'no_transactions_title_transfers' => 'Je hebt overschrijvingen nodig!',
|
||||
'no_transactions_intro_transfers' => 'You have no transfers yet. When you move money between asset accounts, it is recorded as a transfer.',
|
||||
'no_transactions_imperative_transfers' => 'Have you moved some money around? Then you should write it down:',
|
||||
'no_transactions_create_transfers' => 'Create a transfer',
|
||||
'no_transactions_intro_transfers' => 'Je hebt nog geen overschrijvingen opgeslagen. Doe dit om te beginnen met het beheren van je financiën.',
|
||||
'no_transactions_imperative_transfers' => 'Heb je geld heen-en-weer geschoven? Schrijf het dan op:',
|
||||
'no_transactions_create_transfers' => 'Registreer een overschrijving',
|
||||
'no_piggies_title_default' => 'Je hebt spaarpotjes nodig!',
|
||||
'no_piggies_intro_default' => 'You have no piggy banks yet. You can create piggy banks to divide your savings and keep track of what you\'re saving up for.',
|
||||
'no_piggies_imperative_default' => 'Do you have things you\'re saving money for? Create a piggy bank and keep track:',
|
||||
'no_piggies_create_default' => 'Create a new piggy bank',
|
||||
'no_piggies_intro_default' => 'Je hebt nog geen spaarpotjes. Maak spaarpotjes om je spaargeld te verdelen over de zaken waar je voor wilt sparen.',
|
||||
'no_piggies_imperative_default' => 'Heb je zaken waar je voor wilt sparen? Maak dan een spaarpotje en houd het bij:',
|
||||
'no_piggies_create_default' => 'Maak een spaarpotje',
|
||||
'no_bills_title_default' => 'Je hebt contracten nodig!',
|
||||
'no_bills_intro_default' => 'You have no bills yet. You can create bills to keep track of regular expenses, like your rent of insurance.',
|
||||
'no_bills_imperative_default' => 'Do you have such regular bills? Create a bill and keep track of your payments:',
|
||||
'no_bills_create_default' => 'Create a bill',
|
||||
'no_bills_intro_default' => 'Je hebt nog geen contracten. Je kan contracten gebruiken om terugkerende uitgaven bij te houden, zoals de huur of verzekeringen.',
|
||||
'no_bills_imperative_default' => 'Heb je zulke uitgaven? Maak dan een contract en houd de betalingen bij:',
|
||||
'no_bills_create_default' => 'Maak een contract',
|
||||
|
||||
|
||||
];
|
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'Nie wybrano',
|
||||
'multi_select_all_selected' => 'Wybrano wszystko',
|
||||
'multi_select_filter_placeholder' => 'Find..',
|
||||
'between_dates_breadcrumb' => 'Between :start and :end',
|
||||
'all_journals_without_budget' => 'All transactions without a budget',
|
||||
'journals_without_budget' => 'Transactions without a budget',
|
||||
'all_journals_without_category' => 'All transactions without a category',
|
||||
'journals_without_category' => 'Transactions without a category',
|
||||
'all_journals_for_account' => 'All transactions for account :name',
|
||||
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
|
||||
'transferred' => 'Transferred',
|
||||
'all_withdrawal' => 'All expenses',
|
||||
'all_transactions' => 'All transactions',
|
||||
'title_withdrawal_between' => 'All expenses between :start and :end',
|
||||
'all_deposit' => 'All revenue',
|
||||
'title_deposit_between' => 'All revenue between :start and :end',
|
||||
'all_transfers' => 'All transfers',
|
||||
'title_transfers_between' => 'All transfers between :start and :end',
|
||||
'all_transfer' => 'All transfers',
|
||||
'title_transfer_between' => 'All transfers between :start and :end',
|
||||
'all_journals_for_category' => 'All transactions for category :name',
|
||||
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
|
||||
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
|
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'None selected',
|
||||
'multi_select_all_selected' => 'All selected',
|
||||
'multi_select_filter_placeholder' => 'Find..',
|
||||
'between_dates_breadcrumb' => 'Between :start and :end',
|
||||
'all_journals_without_budget' => 'All transactions without a budget',
|
||||
'journals_without_budget' => 'Transactions without a budget',
|
||||
'all_journals_without_category' => 'All transactions without a category',
|
||||
'journals_without_category' => 'Transactions without a category',
|
||||
'all_journals_for_account' => 'All transactions for account :name',
|
||||
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
|
||||
'transferred' => 'Transferred',
|
||||
'all_withdrawal' => 'All expenses',
|
||||
'all_transactions' => 'All transactions',
|
||||
'title_withdrawal_between' => 'All expenses between :start and :end',
|
||||
'all_deposit' => 'All revenue',
|
||||
'title_deposit_between' => 'All revenue between :start and :end',
|
||||
'all_transfers' => 'All transfers',
|
||||
'title_transfers_between' => 'All transfers between :start and :end',
|
||||
'all_transfer' => 'All transfers',
|
||||
'title_transfer_between' => 'All transfers between :start and :end',
|
||||
'all_journals_for_category' => 'All transactions for category :name',
|
||||
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
|
||||
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
@ -854,7 +874,7 @@ return [
|
||||
'tag_title_nothing' => 'Tags padrões',
|
||||
'tag_title_balancingAct' => 'Saldo das tags',
|
||||
'tag_title_advancePayment' => 'Tags de pagamento do adiantamento',
|
||||
'tags_introduction' => 'Geralmente tags são palavras singulares, projetadas para rapidamente agrupar itens usando coisas como <span class="label label-info">caro</span>, <span class="label label-info">conta</span> ou <span class="label label-info">para a festa</span>. Em Firefly III, tags podem ter propriedades mais como uma data, descrição e localização. Isso permite que você una as operações de uma forma mais significativa. Por exemplo, você poderia fazer uma tag chamada <span class="label label-success">ceia de Natal com amigos</span> e adicionar informações sobre o restaurante. Tais tags são "singulares", só use-as para uma ocasião única, talvez com várias transações.',
|
||||
'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like <span class="label label-info">expensive</span>, <span class="label label-info">bill</span> or <span class="label label-info">for-party</span>. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called <span class="label label-success">Christmas dinner with friends</span> and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.',
|
||||
'tags_group' => 'Tags agrupam transações, que torna possível armazenar os reembolsos (no caso você empreste dinheiro para os outros) e outros "balancetes" onde as despesas são somadas (os pagamentos na sua TV nova) ou onde as despesas e depósitos estão anulando uns aos outros (compra algo com dinheiro guardado). Isso é tudo para você. Usando tags à moda antiga claro é sempre possível.',
|
||||
'tags_start' => 'Crie uma tag para começar ou insira tags ao criar novas transações.',
|
||||
|
||||
|
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'None selected',
|
||||
'multi_select_all_selected' => 'All selected',
|
||||
'multi_select_filter_placeholder' => 'Find..',
|
||||
'between_dates_breadcrumb' => 'Between :start and :end',
|
||||
'all_journals_without_budget' => 'All transactions without a budget',
|
||||
'journals_without_budget' => 'Transactions without a budget',
|
||||
'all_journals_without_category' => 'All transactions without a category',
|
||||
'journals_without_category' => 'Transactions without a category',
|
||||
'all_journals_for_account' => 'All transactions for account :name',
|
||||
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
|
||||
'transferred' => 'Transferred',
|
||||
'all_withdrawal' => 'All expenses',
|
||||
'all_transactions' => 'All transactions',
|
||||
'title_withdrawal_between' => 'All expenses between :start and :end',
|
||||
'all_deposit' => 'All revenue',
|
||||
'title_deposit_between' => 'All revenue between :start and :end',
|
||||
'all_transfers' => 'All transfers',
|
||||
'title_transfers_between' => 'All transfers between :start and :end',
|
||||
'all_transfer' => 'All transfers',
|
||||
'title_transfer_between' => 'All transfers between :start and :end',
|
||||
'all_journals_for_category' => 'All transactions for category :name',
|
||||
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
|
||||
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
|
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'None selected',
|
||||
'multi_select_all_selected' => 'All selected',
|
||||
'multi_select_filter_placeholder' => 'Find..',
|
||||
'between_dates_breadcrumb' => 'Between :start and :end',
|
||||
'all_journals_without_budget' => 'All transactions without a budget',
|
||||
'journals_without_budget' => 'Transactions without a budget',
|
||||
'all_journals_without_category' => 'All transactions without a category',
|
||||
'journals_without_category' => 'Transactions without a category',
|
||||
'all_journals_for_account' => 'All transactions for account :name',
|
||||
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
|
||||
'transferred' => 'Transferred',
|
||||
'all_withdrawal' => 'All expenses',
|
||||
'all_transactions' => 'All transactions',
|
||||
'title_withdrawal_between' => 'All expenses between :start and :end',
|
||||
'all_deposit' => 'All revenue',
|
||||
'title_deposit_between' => 'All revenue between :start and :end',
|
||||
'all_transfers' => 'All transfers',
|
||||
'title_transfers_between' => 'All transfers between :start and :end',
|
||||
'all_transfer' => 'All transfers',
|
||||
'title_transfer_between' => 'All transfers between :start and :end',
|
||||
'all_journals_for_category' => 'All transactions for category :name',
|
||||
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
|
||||
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
|
@ -115,6 +115,26 @@ return [
|
||||
'multi_select_no_selection' => 'None selected',
|
||||
'multi_select_all_selected' => 'All selected',
|
||||
'multi_select_filter_placeholder' => 'Find..',
|
||||
'between_dates_breadcrumb' => 'Between :start and :end',
|
||||
'all_journals_without_budget' => 'All transactions without a budget',
|
||||
'journals_without_budget' => 'Transactions without a budget',
|
||||
'all_journals_without_category' => 'All transactions without a category',
|
||||
'journals_without_category' => 'Transactions without a category',
|
||||
'all_journals_for_account' => 'All transactions for account :name',
|
||||
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
|
||||
'transferred' => 'Transferred',
|
||||
'all_withdrawal' => 'All expenses',
|
||||
'all_transactions' => 'All transactions',
|
||||
'title_withdrawal_between' => 'All expenses between :start and :end',
|
||||
'all_deposit' => 'All revenue',
|
||||
'title_deposit_between' => 'All revenue between :start and :end',
|
||||
'all_transfers' => 'All transfers',
|
||||
'title_transfers_between' => 'All transfers between :start and :end',
|
||||
'all_transfer' => 'All transfers',
|
||||
'title_transfer_between' => 'All transfers between :start and :end',
|
||||
'all_journals_for_category' => 'All transactions for category :name',
|
||||
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
|
||||
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
|
||||
|
||||
|
||||
// repeat frequencies:
|
||||
@ -854,7 +874,7 @@ return [
|
||||
'tag_title_nothing' => '預設標籤',
|
||||
'tag_title_balancingAct' => '抵銷行為標籤',
|
||||
'tag_title_advancePayment' => '預付款標籤',
|
||||
'tags_introduction' => '標籤通常是一些方便分類的短語,例如 <span class="label label-info">很貴</span>, <span class="label label-info">賬單</span> 或者 <span class="label label-info">派對用品</span>。 在 Firefly III 裡,標籤可以有不同的屬性,例如日期、描述、或位置。這能方便你更有意義地把交易分類。例如,你可以建立一個 <span class="label label-success">與朋友一起吃聖誕大餐</span>的標籤,並加上餐廳的資訊。這類的標籤標籤是 「即棄」 的,你只會在一次事件中使用它,而標籤可能有多個交易。',
|
||||
'tags_introduction' => 'Usually tags are singular words, designed to quickly band items together using things like <span class="label label-info">expensive</span>, <span class="label label-info">bill</span> or <span class="label label-info">for-party</span>. In Firefly III, tags can have more properties such as a date, description and location. This allows you to join transactions together in a more meaningful way. For example, you could make a tag called <span class="label label-success">Christmas dinner with friends</span> and add information about the restaurant. Such tags are "singular", you would only use them for a single occasion, perhaps with multiple transactions.',
|
||||
'tags_group' => '標籤可以把交易進行分組,容許你記錄報銷(你為其他人墊支),或者其他「抵銷行為」——例如分期付款(買電視機的時候),或者支出和收入會互相抵銷(以儲蓄買東西)的交易。當然,你也可以建立普通的標籤,隨你喜歡。',
|
||||
'tags_start' => '要開始使用,請新增標籤或在建立新交易紀錄時輸入標籤。',
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
{% extends "./layout/default" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute().getName(), account) }}
|
||||
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, account) }}
|
||||
{{ Route.getCurrentRoute.getName }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% extends "./layout/default" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, account, start, end) }}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, account, moment, start, end) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@ -9,12 +9,8 @@
|
||||
<div class="col-lg-12 col-md-10 col-sm-12">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ account.name }}
|
||||
{% if start and end %}
|
||||
({{ trans('firefly.from_to_breadcrumb', {start: start.formatLocalized(monthAndDayFormat), end: end.formatLocalized(monthAndDayFormat)}) }})
|
||||
{% else %}
|
||||
({{ trans('firefly.everything')|lower }})
|
||||
{% endif %}
|
||||
<h3 class="box-title">
|
||||
{{ subTitle }}
|
||||
</h3>
|
||||
<!-- ACTIONS MENU -->
|
||||
<div class="box-tools pull-right">
|
||||
@ -74,7 +70,7 @@
|
||||
{% if periods.count > 0 %}
|
||||
<div class="row">
|
||||
<div class="col-lg-offset-10 col-lg-2 col-md-offset-10 col-md-2 col-sm-12 col-xs-12">
|
||||
<p class="small text-center"><a href="{{ route('accounts.show.date',[account.id, 'all']) }}">{{ 'showEverything'|_ }}</a></p>
|
||||
<p class="small text-center"><a href="{{ route('accounts.show',[account.id, 'all']) }}">{{ 'showEverything'|_ }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -90,7 +86,7 @@
|
||||
{% if periods.count > 0 %}
|
||||
<p>
|
||||
<i class="fa fa-calendar" aria-hidden="true"></i>
|
||||
<a href="{{ route('accounts.show.date', [account.id, 'all']) }}">
|
||||
<a href="{{ route('accounts.show', [account.id, 'all']) }}">
|
||||
{{ 'show_all_no_filter'|_ }}
|
||||
</a>
|
||||
</p>
|
||||
@ -107,25 +103,25 @@
|
||||
</div>
|
||||
{% if periods.count > 0 %}
|
||||
<div class="col-lg-2 col-md-2 col-sm-12 col-xs-12">
|
||||
{% for entry in periods %}
|
||||
{% if (entry[2] != 0 or entry[3] != 0) or (accountType == 'Asset account') %}
|
||||
<div class="box {% if entry[4] == start %}box-solid box-primary{% endif %}">
|
||||
{% for period in periods %}
|
||||
{% if (period.spent != 0 or period.earned != 0) or (accountType == 'Asset account') %}
|
||||
<div class="box {% if period.date == start %}box-solid box-primary{% endif %}">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title"><a href="{{ route('accounts.show.date',[account.id,entry[0]]) }}">{{ entry[1] }}</a>
|
||||
<h3 class="box-title"><a href="{{ route('accounts.show',[account.id,period.string]) }}">{{ period.name }}</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-hover">
|
||||
{% if entry[2] != 0 or (accountType == 'Asset account') %}
|
||||
{% if period.spent != 0 or (accountType == 'Asset account') %}
|
||||
<tr>
|
||||
<td style="width:33%;">{{ 'spent'|_ }}</td>
|
||||
<td style="text-align: right;">{{ entry[2]|formatAmount }}</td>
|
||||
<td style="text-align: right;">{{ period.spent|formatAmount }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if entry[3] != 0 or (accountType == 'Asset account') %}
|
||||
{% if period.earned != 0 or (accountType == 'Asset account') %}
|
||||
<tr>
|
||||
<td style="width: 33%;">{{ 'earned'|_ }}</td>
|
||||
<td style="text-align: right;">{{ entry[3]|formatAmount }}</td>
|
||||
<td style="text-align: right;">{{ period.earned|formatAmount }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
@ -133,7 +129,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<p class="small text-center"><a href="{{ route('accounts.show.date',[account.id, 'all']) }}">{{ 'showEverything'|_ }}</a></p>
|
||||
<p class="small text-center"><a href="{{ route('accounts.show',[account.id, 'all']) }}">{{ 'showEverything'|_ }}</a></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@ -1,22 +1,78 @@
|
||||
{% extends "./layout/default" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, subTitle) }}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, moment, start, end) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{# upper show-all instruction #}
|
||||
{% if periods.count > 0 %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="col-lg-offset-10 col-lg-2 col-md-offset-10 col-md-2 col-sm-12 col-xs-12">
|
||||
<p class="small text-center"><a href="{{ route('budgets.no-budget',['all']) }}">{{ 'showEverything'|_ }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="row">
|
||||
<div class="{% if periods.count > 0 %}col-lg-10 col-md-10 col-sm-12{% else %}col-lg-12 col-md-12 col-sm-12{% endif %}">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ subTitle }}</h3>
|
||||
</div>
|
||||
<div class="box-body ">
|
||||
{% include 'list.journals-tasker' with {'journals': journals} %}
|
||||
{% include 'list.journals-tasker' with {'journals': journals,'hideBudgets': true} %}
|
||||
{% if periods.count > 0 %}
|
||||
<p>
|
||||
<i class="fa fa-calendar" aria-hidden="true"></i>
|
||||
<a href="{{ route('budgets.no-budget', ['all']) }}">{{ 'show_all_no_filter'|_ }}</a>
|
||||
</p>
|
||||
{% else %}
|
||||
<p>
|
||||
<i class="fa fa-calendar" aria-hidden="true"></i>
|
||||
<a href="{{ route('budgets.no-budget') }}">{{ 'show_the_current_period_and_overview'|_ }}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if periods.count > 0 %}
|
||||
<div class="col-lg-2 col-md-2 col-sm-12 col-xs-12">
|
||||
{% for period in periods %}
|
||||
<div class="box {% if period.date == start %}box-solid box-primary{% endif %}">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title"><a href="{{ route('budgets.no-budget',[period.string]) }}">{{ period.name }}</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-hover">
|
||||
<tr>
|
||||
<td style="width:33%;">{{ 'transactions'|_ }}</td>
|
||||
<td style="text-align: right;">{{ period.count }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:33%;">{{ 'spent'|_ }}</td>
|
||||
<td style="text-align: right;">{{ period.sum|formatAmount }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{# lower show-all instruction #}
|
||||
{% if periods.count > 0 %}
|
||||
<div class="row">
|
||||
<div class="col-lg-offset-10 col-lg-2 col-md-offset-10 col-md-2 col-sm-12 col-xs-12">
|
||||
<p class="small text-center"><a href="{{ route('budgets.no-budget',['all']) }}">{{ 'showEverything'|_ }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
|
@ -43,7 +43,7 @@
|
||||
<h3 class="box-title">{{ 'transactions'|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{% include 'list.journals-tasker' %}
|
||||
{% include 'list.journals-tasker' with {hideBudgets:true, hideBills:true} %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -101,8 +101,9 @@
|
||||
{% block scripts %}
|
||||
<script type="text/javascript">
|
||||
var budgetID = {{ budget.id }};
|
||||
var budgetLimitID = 0;
|
||||
{% if budgetLimit.id %}
|
||||
var budgetLimitID = {{ budgetLimit.id }};
|
||||
budgetLimitID = {{ budgetLimit.id }};
|
||||
var budgetChartUri = '{{ route('chart.budget.budget-limit', [budget.id, budgetLimit.id] ) }}';
|
||||
{% else %}
|
||||
var budgetChartUri = '{{ route('chart.budget.budget', [budget.id] ) }}';
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user