Merge branch 'release/4.2.1'

This commit is contained in:
James Cole 2016-12-08 21:23:19 +01:00
commit 529bab1112
259 changed files with 3848 additions and 5568 deletions

View File

@ -2,6 +2,17 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [4.2.1] - 2015-05-25
### Added
- BIC support (see #430)
- New category report section and chart (see the general financial report)
### Changed
- Date range picker now also available on mobile devices (see #435)
- Extended range of amounts for issue #439
- Rewrote all routes. Old bookmarks may break.
## [4.2.0] - 2016-11-27
### Added
- Lots of (empty) tests

View File

@ -72,8 +72,7 @@ class UpgradeDatabase extends Command
}
$subQuery = TransactionJournal
::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
$subQuery = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->whereNull('transaction_journals.deleted_at')
->whereNull('transactions.deleted_at')
->groupBy(['transaction_journals.id'])
@ -98,8 +97,7 @@ class UpgradeDatabase extends Command
try {
/** @var Transaction $opposing */
$opposing = Transaction
::where('transaction_journal_id', $journalId)
$opposing = Transaction::where('transaction_journal_id', $journalId)
->where('amount', $amount)->where('identifier', '=', 0)
->whereNotIn('id', $processed)
->first();

View File

@ -102,8 +102,7 @@ class VerifyDatabase extends Command
*/
private function reportAccounts()
{
$set = Account
::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
$set = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
->leftJoin('users', 'accounts.user_id', '=', 'users.id')
->groupBy(['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email'])
->whereNull('transactions.account_id')
@ -125,8 +124,7 @@ class VerifyDatabase extends Command
*/
private function reportBudgetLimits()
{
$set = Budget
::leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
$set = Budget::leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
->groupBy(['budgets.id', 'budgets.name', 'budgets.user_id', 'users.email'])
->whereNull('budget_limits.id')
@ -148,8 +146,7 @@ class VerifyDatabase extends Command
*/
private function reportDeletedAccounts()
{
$set = Account
::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
$set = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->whereNotNull('accounts.deleted_at')
->whereNotNull('transactions.id')
@ -187,8 +184,7 @@ class VerifyDatabase extends Command
TransactionType::TRANSFER => [AccountType::EXPENSE, AccountType::REVENUE],
];
foreach ($configuration as $transactionType => $accountTypes) {
$set = TransactionJournal
::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
$set = TransactionJournal::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'account_types.id', 'accounts.account_type_id')
@ -218,8 +214,7 @@ class VerifyDatabase extends Command
*/
private function reportJournals()
{
$set = TransactionJournal
::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
$set = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->whereNotNull('transaction_journals.deleted_at')// USE THIS
->whereNull('transactions.deleted_at')
->whereNotNull('transactions.id')
@ -245,8 +240,7 @@ class VerifyDatabase extends Command
*/
private function reportNoTransactions()
{
$set = TransactionJournal
::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
$set = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->groupBy('transaction_journals.id')
->whereNull('transactions.transaction_journal_id')
->get(['transaction_journals.id']);
@ -335,8 +329,7 @@ class VerifyDatabase extends Command
*/
private function reportTransfersBudgets()
{
$set = TransactionJournal
::distinct()
$set = TransactionJournal::distinct()
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin('budget_transaction_journal', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id')
->where('transaction_types.type', TransactionType::TRANSFER)

View File

@ -292,8 +292,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
private function getWorkSet()
{
$accountIds = $this->accounts->pluck('id')->toArray();
$this->workSet = Transaction
::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
$this->workSet = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin(
'transactions AS opposing', function (JoinClause $join) {
$join->on('opposing.transaction_journal_id', '=', 'transactions.transaction_journal_id')

View File

@ -44,4 +44,11 @@ interface BudgetChartGeneratorInterface
* @return array
*/
public function period(array $entries): array;
/**
* @param array $entries
*
* @return array
*/
public function periodNoBudget(array $entries): array;
}

View File

@ -104,7 +104,7 @@ class ChartJsBudgetChartGenerator implements BudgetChartGeneratorInterface
*
* @return array
*/
public function period(array $entries) : array
public function period(array $entries): array
{
$data = [
@ -133,4 +133,32 @@ class ChartJsBudgetChartGenerator implements BudgetChartGeneratorInterface
return $data;
}
/**
* @param array $entries
*
* @return array
*/
public function periodNoBudget(array $entries): array
{
$data = [
'labels' => array_keys($entries),
'datasets' => [
0 => [
'label' => trans('firefly.spent'),
'data' => [],
],
],
'count' => 1,
];
foreach ($entries as $label => $entry) {
// data set 0 is budgeted
// data set 1 is spent:
$data['datasets'][0]['data'][] = round(($entry['spent'] * -1), 2);
}
return $data;
}
}

View File

@ -22,7 +22,6 @@ use Illuminate\Support\Collection;
*/
interface CategoryChartGeneratorInterface
{
/**
* @param Collection $entries
*
@ -58,4 +57,11 @@ interface CategoryChartGeneratorInterface
*/
public function pieChart(array $data): array;
/**
* @param array $entries
*
* @return array
*/
public function reportPeriod(array $entries): array;
}

View File

@ -142,6 +142,41 @@ class ChartJsCategoryChartGenerator implements CategoryChartGeneratorInterface
}
/**
* @param array $entries
*
* @return array
*/
public function reportPeriod(array $entries): array
{
$data = [
'labels' => array_keys($entries),
'datasets' => [
0 => [
'label' => trans('firefly.earned'),
'data' => [],
],
1 => [
'label' => trans('firefly.spent'),
'data' => [],
],
],
'count' => 2,
];
foreach ($entries as $label => $entry) {
// data set 0 is budgeted
// data set 1 is spent:
$data['datasets'][0]['data'][] = round($entry['earned'], 2);
$data['datasets'][1]['data'][] = round(bcmul($entry['spent'], '-1'), 2);
}
return $data;
}
/**
* @param array $entries
*

View File

@ -29,7 +29,7 @@ class ChartJsReportChartGenerator implements ReportChartGeneratorInterface
*
* @return array
*/
public function multiYearInOut(Collection $entries): array
public function multiYearOperations(Collection $entries): array
{
$data = [
'count' => 2,
@ -62,7 +62,7 @@ class ChartJsReportChartGenerator implements ReportChartGeneratorInterface
*
* @return array
*/
public function multiYearInOutSummarized(string $income, string $expense, int $count): array
public function multiYearSum(string $income, string $expense, int $count): array
{
$data = [
'count' => 2,
@ -117,7 +117,7 @@ class ChartJsReportChartGenerator implements ReportChartGeneratorInterface
*
* @return array
*/
public function yearInOut(Collection $entries): array
public function yearOperations(Collection $entries): array
{
// language:
$format = (string)trans('config.month');
@ -153,7 +153,7 @@ class ChartJsReportChartGenerator implements ReportChartGeneratorInterface
*
* @return array
*/
public function yearInOutSummarized(string $income, string $expense, int $count): array
public function yearSum(string $income, string $expense, int $count): array
{
$data = [

View File

@ -28,7 +28,7 @@ interface ReportChartGeneratorInterface
*
* @return array
*/
public function multiYearInOut(Collection $entries): array;
public function multiYearOperations(Collection $entries): array;
/**
* @param string $income
@ -37,7 +37,7 @@ interface ReportChartGeneratorInterface
*
* @return array
*/
public function multiYearInOutSummarized(string $income, string $expense, int $count): array;
public function multiYearSum(string $income, string $expense, int $count): array;
/**
* @param Collection $entries
@ -51,7 +51,7 @@ interface ReportChartGeneratorInterface
*
* @return array
*/
public function yearInOut(Collection $entries): array;
public function yearOperations(Collection $entries): array;
/**
* @param string $income
@ -60,6 +60,6 @@ interface ReportChartGeneratorInterface
*
* @return array
*/
public function yearInOutSummarized(string $income, string $expense, int $count): array;
public function yearSum(string $income, string $expense, int $count): array;
}

View File

@ -78,9 +78,9 @@ class MonthReportGenerator implements ReportGeneratorInterface
$auditData[$id]['dayBeforeBalance'] = $dayBeforeBalance;
}
$reportType = 'audit';
$accountIds = join(',', $this->accounts->pluck('id')->toArray());
$defaultShow = ['icon', 'description', 'balance_before', 'amount', 'balance_after', 'date', 'to'];
$reportType = 'audit';
$accountIds = join(',', $this->accounts->pluck('id')->toArray());
$hideable = ['buttons', 'icon', 'description', 'balance_before', 'amount', 'balance_after', 'date',
'interest_date', 'book_date', 'process_date',
// three new optional fields.
@ -88,10 +88,9 @@ class MonthReportGenerator implements ReportGeneratorInterface
'from', 'to', 'budget', 'category', 'bill',
// more new optional fields
'internal_reference', 'notes',
'create_date', 'update_date',
];
$defaultShow = ['icon', 'description', 'balance_before', 'amount', 'balance_after', 'date', 'to'];
return view('reports.audit.report', compact('reportType', 'accountIds', 'auditData', 'hideable', 'defaultShow'))
->with('start', $this->start)->with('end', $this->end)->with('accounts', $this->accounts)

View File

@ -148,8 +148,6 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
// is not set?
if (!isset($result[$opposingId])) {
$name = $transaction->opposing_account_name;
$encrypted = intval($transaction->opposing_account_encrypted);
$name = $encrypted === 1 ? Crypt::decrypt($name) : $name;
$result[$opposingId] = [
'name' => $name,
'count' => 1,
@ -267,14 +265,6 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
{
$transactions = $this->getExpenses()->sortBy('transaction_amount');
$transactions = $transactions->each(
function (Transaction $transaction) {
if (intval($transaction->opposing_account_encrypted) === 1) {
$transaction->opposing_account_name = Crypt::decrypt($transaction->opposing_account_name);
}
}
);
return $transactions;
}
@ -285,14 +275,6 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
{
$transactions = $this->getIncome()->sortByDesc('transaction_amount');
$transactions = $transactions->each(
function (Transaction $transaction) {
if (intval($transaction->opposing_account_encrypted) === 1) {
$transaction->opposing_account_name = Crypt::decrypt($transaction->opposing_account_name);
}
}
);
return $transactions;
}

View File

@ -34,25 +34,25 @@ class BudgetEventHandler
/**
* This method creates a new budget limit repetition when a new budget limit has been created.
*
* @param StoredBudgetLimit $event
* @param StoredBudgetLimit $budgetLimitEvent
*
* @return bool
*/
public function storeRepetition(StoredBudgetLimit $event):bool
public function storeRepetition(StoredBudgetLimit $budgetLimitEvent):bool
{
return $this->processRepetitionChange($event->budgetLimit, $event->end);
return $this->processRepetitionChange($budgetLimitEvent->budgetLimit, $budgetLimitEvent->end);
}
/**
* Updates, if present the budget limit repetition part of a budget limit.
*
* @param UpdatedBudgetLimit $event
* @param UpdatedBudgetLimit $budgetLimitEvent
*
* @return bool
*/
public function updateRepetition(UpdatedBudgetLimit $event): bool
public function updateRepetition(UpdatedBudgetLimit $budgetLimitEvent): bool
{
return $this->processRepetitionChange($event->budgetLimit, $event->end);
return $this->processRepetitionChange($budgetLimitEvent->budgetLimit, $budgetLimitEvent->end);
}
/**

View File

@ -33,15 +33,15 @@ class StoredJournalEventHandler
/**
* This method connects a new transfer to a piggy bank.
*
* @param StoredTransactionJournal $event
* @param StoredTransactionJournal $storedJournalEvent
*
* @return bool
*/
public function connectToPiggyBank(StoredTransactionJournal $event): bool
public function connectToPiggyBank(StoredTransactionJournal $storedJournalEvent): bool
{
/** @var TransactionJournal $journal */
$journal = $event->journal;
$piggyBankId = $event->piggyBankId;
$journal = $storedJournalEvent->journal;
$piggyBankId = $storedJournalEvent->piggyBankId;
Log::debug(sprintf('Trying to connect journal %d to piggy bank %d.', $journal->id, $piggyBankId));
@ -101,11 +101,11 @@ class StoredJournalEventHandler
$repetition->currentamount = bcadd($repetition->currentamount, $amount);
$repetition->save();
/** @var PiggyBankEvent $event */
$event = PiggyBankEvent::create(
/** @var PiggyBankEvent $storedJournalEvent */
$storedJournalEvent = PiggyBankEvent::create(
['piggy_bank_id' => $piggyBank->id, 'transaction_journal_id' => $journal->id, 'date' => $journal->date, 'amount' => $amount]
);
Log::debug(sprintf('Created piggy bank event #%d', $event->id));
Log::debug(sprintf('Created piggy bank event #%d', $storedJournalEvent->id));
return true;
}
@ -113,14 +113,14 @@ class StoredJournalEventHandler
/**
* This method grabs all the users rules and processes them.
*
* @param StoredTransactionJournal $event
* @param StoredTransactionJournal $storedJournalEvent
*
* @return bool
*/
public function processRules(StoredTransactionJournal $event): bool
public function processRules(StoredTransactionJournal $storedJournalEvent): bool
{
// get all the user's rule groups, with the rules, order by 'order'.
$journal = $event->journal;
$journal = $storedJournalEvent->journal;
$groups = $journal->user->ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get();
//
/** @var RuleGroup $group */
@ -150,13 +150,13 @@ class StoredJournalEventHandler
/**
* This method calls a special bill scanner that will check if the stored journal is part of a bill.
*
* @param StoredTransactionJournal $event
* @param StoredTransactionJournal $storedJournalEvent
*
* @return bool
*/
public function scanBills(StoredTransactionJournal $event): bool
public function scanBills(StoredTransactionJournal $storedJournalEvent): bool
{
$journal = $event->journal;
$journal = $storedJournalEvent->journal;
BillScanner::scan($journal);
return true;

View File

@ -31,14 +31,14 @@ class UpdatedJournalEventHandler
/**
* This method will check all the rules when a journal is updated.
*
* @param UpdatedTransactionJournal $event
* @param UpdatedTransactionJournal $updatedJournalEvent
*
* @return bool
*/
public function processRules(UpdatedTransactionJournal $event):bool
public function processRules(UpdatedTransactionJournal $updatedJournalEvent):bool
{
// get all the user's rule groups, with the rules, order by 'order'.
$journal = $event->journal;
$journal = $updatedJournalEvent->journal;
$groups = $journal->user->ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get();
//
/** @var RuleGroup $group */
@ -67,13 +67,13 @@ class UpdatedJournalEventHandler
/**
* This method calls a special bill scanner that will check if the updated journal is part of a bill.
*
* @param UpdatedTransactionJournal $event
* @param UpdatedTransactionJournal $updatedJournalEvent
*
* @return bool
*/
public function scanBills(UpdatedTransactionJournal $event): bool
public function scanBills(UpdatedTransactionJournal $updatedJournalEvent): bool
{
$journal = $event->journal;
$journal = $updatedJournalEvent->journal;
BillScanner::scan($journal);
return true;

View File

@ -1,85 +0,0 @@
<?php
/**
* Expense.php
* Copyright (C) 2016 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\Collection;
use Illuminate\Support\Collection;
use stdClass;
/**
*
* Class Expense
*
* @package FireflyIII\Helpers\Collection
*/
class Expense
{
/** @var Collection */
protected $expenses;
/** @var string */
protected $total = '0';
/**
*
*/
public function __construct()
{
$this->expenses = new Collection;
}
/**
* @param stdClass $entry
*/
public function addOrCreateExpense(stdClass $entry)
{
$this->expenses->put($entry->id, $entry);
}
/**
* @param string $add
*/
public function addToTotal(string $add)
{
$add = strval(round($add, 2));
if (bccomp('0', $add) === -1) {
$add = bcmul($add, '-1');
}
// if amount is positive, the original transaction
// was a transfer. But since this is an expense report,
// that amount must be negative.
$this->total = bcadd($this->total, $add);
}
/**
* @return Collection
*/
public function getExpenses(): Collection
{
$set = $this->expenses->sortBy(
function (stdClass $object) {
return $object->amount;
}
);
return $set;
}
/**
* @return string
*/
public function getTotal(): string
{
return strval(round($this->total, 2));
}
}

View File

@ -1,81 +0,0 @@
<?php
/**
* Income.php
* Copyright (C) 2016 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\Collection;
use Illuminate\Support\Collection;
use stdClass;
/**
*
* Class Income
*
* @package FireflyIII\Helpers\Collection
*/
class Income
{
/** @var Collection */
protected $incomes;
/** @var string */
protected $total = '0';
/**
*
*/
public function __construct()
{
$this->incomes = new Collection;
}
/**
* @param stdClass $entry
*/
public function addOrCreateIncome(stdClass $entry)
{
$this->incomes->put($entry->id, $entry);
}
/**
* @param string $add
*/
public function addToTotal(string $add)
{
$add = strval(round($add, 2));
$this->total = bcadd($this->total, $add);
}
/**
* @return Collection
*/
public function getIncomes(): Collection
{
$set = $this->incomes->sortByDesc(
function (stdClass $object) {
return $object->amount;
}
);
return $set;
}
/**
* @return string
*/
public function getTotal(): string
{
return strval(round($this->total, 2));
}
}

View File

@ -1,4 +1,14 @@
<?php
/**
* JournalCollector.php
* Copyright (C) 2016 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\Collector;
@ -16,6 +26,7 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
@ -60,6 +71,8 @@ class JournalCollector implements JournalCollectorInterface
'account_types.type as account_type',
];
/** @var bool */
private $filterInternalTransfers;
/** @var bool */
private $filterTransfers = false;
/** @var bool */
private $joinedBudget = false;
@ -127,6 +140,26 @@ class JournalCollector implements JournalCollectorInterface
return $this;
}
/**
* @return JournalCollectorInterface
*/
public function disableInternalFilter(): JournalCollectorInterface
{
$this->filterInternalTransfers = false;
return $this;
}
/**
* @return JournalCollectorInterface
*/
public function enableInternalFilter(): JournalCollectorInterface
{
$this->filterInternalTransfers = true;
return $this;
}
/**
* @return Collection
*/
@ -138,12 +171,25 @@ class JournalCollector implements JournalCollectorInterface
$set = $this->filterTransfers($set);
Log::debug(sprintf('Count of set after filterTransfers() is %d', $set->count()));
// possibly filter "internal" transfers:
$set = $this->filterInternalTransfers($set);
Log::debug(sprintf('Count of set after filterInternalTransfers() is %d', $set->count()));
// loop for decryption.
$set->each(
function (Transaction $transaction) {
$transaction->date = new Carbon($transaction->date);
$transaction->description = intval($transaction->encrypted) === 1 ? Crypt::decrypt($transaction->description) : $transaction->description;
$transaction->bill_name = !is_null($transaction->bill_name) ? Crypt::decrypt($transaction->bill_name) : '';
// optionally decrypted:
try {
$transaction->opposing_account_name = Crypt::decrypt($transaction->opposing_account_name);
} catch (DecryptException $e) {
// if this fails its already decrypted.
}
}
);
@ -501,6 +547,47 @@ class JournalCollector implements JournalCollectorInterface
return $this;
}
/**
* @param Collection $set
*
* @return Collection
*/
private function filterInternalTransfers(Collection $set): Collection
{
if ($this->filterInternalTransfers === false) {
Log::debug('Did NO filtering for internal transfers on given set.');
return $set;
}
if ($this->joinedOpposing === false) {
Log::error('Cannot filter internal transfers because no opposing information is present.');
return $set;
}
$accountIds = $this->accountIds;
$set = $set->filter(
function (Transaction $transaction) use ($accountIds) {
// both id's in $accountids?
if (in_array($transaction->account_id, $accountIds) && in_array($transaction->opposing_account_id, $accountIds)) {
Log::debug(
sprintf(
'Transaction #%d has #%d and #%d in set, so removed',
$transaction->id, $transaction->account_id, $transaction->opposing_account_id
), $accountIds
);
return false;
}
return $transaction;
}
);
return $set;
}
/**
* If the set of accounts used by the collector includes more than one asset
* account, chances are the set include double entries: transfers get selected
@ -583,6 +670,7 @@ class JournalCollector implements JournalCollectorInterface
private function joinOpposingTables()
{
if (!$this->joinedOpposing) {
Log::debug('joinedOpposing is false');
// join opposing transaction (hard):
$this->query->leftJoin(
'transactions as opposing', function (JoinClause $join) {
@ -595,11 +683,12 @@ class JournalCollector implements JournalCollectorInterface
$this->query->leftJoin('account_types as opposing_account_types', 'opposing_accounts.account_type_id', '=', 'opposing_account_types.id');
$this->query->whereNull('opposing.deleted_at');
$this->fields[] = 'opposing.account_id as opposing_account_id';
$this->fields[] = 'opposing_accounts.name as opposing_account_name';
$this->fields[] = 'opposing_accounts.encrypted as opposing_account_encrypted';
$this->fields[] = 'opposing_account_types.type as opposing_account_type';
$this->fields[] = 'opposing.account_id as opposing_account_id';
$this->fields[] = 'opposing_accounts.name as opposing_account_name';
$this->fields[] = 'opposing_accounts.encrypted as opposing_account_encrypted';
$this->fields[] = 'opposing_account_types.type as opposing_account_type';
$this->joinedOpposing = true;
Log::debug('joinedOpposing is now true!');
}
}
@ -621,19 +710,18 @@ class JournalCollector implements JournalCollectorInterface
private function startQuery(): EloquentBuilder
{
$query = Transaction
::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transaction_journals.user_id', $this->user->id)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC');
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transaction_journals.user_id', $this->user->id)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC');
return $query;

View File

@ -38,6 +38,16 @@ interface JournalCollectorInterface
*/
public function disableFilter(): JournalCollectorInterface;
/**
* @return JournalCollectorInterface
*/
public function disableInternalFilter(): JournalCollectorInterface;
/**
* @return JournalCollectorInterface
*/
public function enableInternalFilter(): JournalCollectorInterface;
/**
* @return Collection
*/
@ -46,7 +56,7 @@ interface JournalCollectorInterface
/**
* @return LengthAwarePaginator
*/
public function getPaginatedJournals():LengthAwarePaginator;
public function getPaginatedJournals(): LengthAwarePaginator;
/**
* @param Collection $accounts

View File

@ -120,7 +120,6 @@ class Help implements HelpInterface
* @param string $language
* @param string $content
*
* @internal param $title
*/
public function putInCache(string $route, string $language, string $content)
{

View File

@ -51,13 +51,13 @@ class BalanceReportHelper implements BalanceReportHelperInterface
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Balance
*/
public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts): Balance
public function getBalanceReport(Collection $accounts, Carbon $start, Carbon $end): Balance
{
$balance = new Balance;
$header = new BalanceHeader;

View File

@ -26,11 +26,11 @@ use Illuminate\Support\Collection;
interface BalanceReportHelperInterface
{
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Balance
*/
public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts): Balance;
public function getBalanceReport(Collection $accounts, Carbon $start, Carbon $end): Balance;
}

View File

@ -42,22 +42,6 @@ class BudgetReportHelper implements BudgetReportHelperInterface
$this->repository = $repository;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return array
*/
public function getBudgetPeriodReport(Carbon $start, Carbon $end, Collection $accounts): array
{
$budgets = $this->repository->getBudgets();
$report = $this->repository->getBudgetPeriodReport($budgets, $accounts, $start, $end);
$data = $this->filterBudgetPeriodReport($report);
return $data;
}
/**
* @param Carbon $start
* @param Carbon $end
@ -162,31 +146,4 @@ class BudgetReportHelper implements BudgetReportHelperInterface
return $array;
}
/**
* Filters empty results from getBudgetPeriodReport
*
* @param array $data
*
* @return array
*/
private function filterBudgetPeriodReport(array $data): array
{
/**
* @var int $budgetId
* @var array $set
*/
foreach ($data as $budgetId => $set) {
$sum = '0';
foreach ($set['entries'] as $amount) {
$sum = bcadd($amount, $sum);
}
$data[$budgetId]['sum'] = $sum;
if (bccomp('0', $sum) === 0) {
unset($data[$budgetId]);
}
}
return $data;
}
}

View File

@ -26,15 +26,6 @@ use Illuminate\Support\Collection;
interface BudgetReportHelperInterface
{
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return array
*/
public function getBudgetPeriodReport(Carbon $start, Carbon $end, Collection $accounts): array;
/**
* @param Carbon $start
* @param Carbon $end

View File

@ -17,19 +17,15 @@ use Carbon\Carbon;
use FireflyIII\Helpers\Collection\Bill as BillCollection;
use FireflyIII\Helpers\Collection\BillLine;
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
use FireflyIII\Helpers\Collection\Expense;
use FireflyIII\Helpers\Collection\Income;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\FiscalHelperInterface;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use Illuminate\Support\Collection;
use stdClass;
/**
* Class ReportHelper
@ -118,7 +114,7 @@ class ReportHelper implements ReportHelperInterface
*
* @return CategoryCollection
*/
public function getCategoryReport(Carbon $start, Carbon $end, Collection $accounts): CategoryCollection
public function getCategoryReport(Collection $accounts, Carbon $start, Carbon $end): CategoryCollection
{
$object = new CategoryCollection;
/** @var CategoryRepositoryInterface $repository */
@ -136,57 +132,6 @@ class ReportHelper implements ReportHelperInterface
return $object;
}
/**
* Get a full report on the users expenses during the period for a list of accounts.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Expense
*/
public function getExpenseReport(Carbon $start, Carbon $end, Collection $accounts): Expense
{
$object = new Expense;
/** @var AccountTaskerInterface $tasker */
$tasker = app(AccountTaskerInterface::class);
$collection = $tasker->expenseReport($accounts, $accounts, $start, $end);
/** @var stdClass $entry */
foreach ($collection as $entry) {
$object->addToTotal($entry->amount);
$object->addOrCreateExpense($entry);
}
return $object;
}
/**
* Get a full report on the users incomes during the period for the given accounts.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Income
*/
public function getIncomeReport(Carbon $start, Carbon $end, Collection $accounts): Income
{
$object = new Income;
/** @var AccountTaskerInterface $tasker */
$tasker = app(AccountTaskerInterface::class);
$collection = $tasker->incomeReport($accounts, $accounts, $start, $end);
/** @var stdClass $entry */
foreach ($collection as $entry) {
$object->addToTotal($entry->amount);
$object->addOrCreateIncome($entry);
}
return $object;
}
/**
* @param Carbon $date
*

View File

@ -49,29 +49,7 @@ interface ReportHelperInterface
*
* @return CategoryCollection
*/
public function getCategoryReport(Carbon $start, Carbon $end, Collection $accounts): CategoryCollection;
/**
* Get a full report on the users expenses during the period for a list of accounts.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Expense
*/
public function getExpenseReport(Carbon $start, Carbon $end, Collection $accounts): Expense;
/**
* Get a full report on the users incomes during the period for the given accounts.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Income
*/
public function getIncomeReport(Carbon $start, Carbon $end, Collection $accounts): Income;
public function getCategoryReport(Collection $accounts, Carbon $start, Carbon $end): CategoryCollection;
/**
* @param Carbon $date

View File

@ -171,6 +171,7 @@ class AccountController extends Controller
'accountRole' => $account->getMeta('accountRole'),
'ccType' => $account->getMeta('ccType'),
'ccMonthlyPaymentDate' => $account->getMeta('ccMonthlyPaymentDate'),
'BIC' => $account->getMeta('BIC'),
'openingBalanceDate' => $openingBalanceDate,
'openingBalance' => $openingBalanceAmount,
'virtualBalance' => $account->virtual_balance,
@ -281,7 +282,7 @@ class AccountController extends Controller
*
* @return View
*/
public function showWithDate(Account $account, string $date)
public function showByDate(Account $account, string $date)
{
$carbon = new Carbon($date);
$range = Preferences::get('viewRange', '1M')->data;
@ -297,7 +298,7 @@ class AccountController extends Controller
$journals = $collector->getPaginatedJournals();
$journals->setPath('accounts/show/' . $account->id . '/' . $date);
return view('accounts.show_with_date', compact('category', 'date', 'account', 'journals', 'subTitle', 'carbon', 'start', 'end'));
return view('accounts.show-by-date', compact('category', 'date', 'account', 'journals', 'subTitle', 'carbon', 'start', 'end'));
}
/**

View File

@ -71,7 +71,7 @@ class ConfigurationController extends Controller
*
* @return \Illuminate\Http\RedirectResponse
*/
public function store(ConfigurationRequest $request)
public function postIndex(ConfigurationRequest $request)
{
// get config values:
$data = $request->getConfigurationData();

View File

@ -38,10 +38,16 @@ 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', '')->data;
$secret = Preferences::get('twoFactorAuthSecret', null)->data;
$title = strval(trans('firefly.two_factor_title'));
if (strlen($secret) === 0) {
// make sure the user has two factor configured:
$has2FA = Preferences::get('twoFactorAuthEnabled', null)->data;
if (is_null($has2FA) || $has2FA === false) {
return redirect(route('index'));
}
if (strlen(strval($secret)) === 0) {
throw new FireflyException('Your two factor authentication secret is empty, which it cannot be at this point. Please check the log files.');
}
Session::flash('two-factor-secret', $secret);

View File

@ -332,7 +332,7 @@ class BudgetController extends Controller
* @return View
* @throws FireflyException
*/
public function showWithRepetition(Budget $budget, LimitRepetition $repetition)
public function showByRepetition(Budget $budget, LimitRepetition $repetition)
{
if ($repetition->budgetLimit->budget->id != $budget->id) {
throw new FireflyException('This budget limit is not part of this budget.');

View File

@ -245,7 +245,7 @@ class CategoryController extends Controller
*
* @return View
*/
public function showWithDate(Category $category, string $date)
public function showByDate(Category $category, string $date)
{
$carbon = new Carbon($date);
$range = Preferences::get('viewRange', '1M')->data;
@ -263,7 +263,7 @@ class CategoryController extends Controller
$journals->setPath('categories/show/' . $category->id . '/' . $date);
return view('categories.show_with_date', compact('category', 'journals', 'hideCategory', 'subTitle', 'carbon'));
return view('categories.show-by-date', compact('category', 'journals', 'hideCategory', 'subTitle', 'carbon'));
}
/**

View File

@ -112,7 +112,7 @@ class AccountController extends Controller
*
* @return \Illuminate\Http\JsonResponse
*/
public function expenseByBudget(JournalCollectorInterface $collector, Account $account, Carbon $start, Carbon $end)
public function expenseBudget(JournalCollectorInterface $collector, Account $account, Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($account->id);
@ -153,7 +153,7 @@ class AccountController extends Controller
*
* @return \Illuminate\Http\JsonResponse
*/
public function expenseByCategory(JournalCollectorInterface $collector, Account $account, Carbon $start, Carbon $end)
public function expenseCategory(JournalCollectorInterface $collector, Account $account, Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($account->id);
@ -199,7 +199,7 @@ class AccountController extends Controller
$frontPage = Preferences::get('frontPageAccounts', $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])->pluck('id')->toArray());
$accounts = $repository->getAccountsById($frontPage->data);
return Response::json($this->accountBalanceChart($start, $end, $accounts));
return Response::json($this->accountBalanceChart($accounts, $start, $end));
}
/**
@ -210,7 +210,7 @@ class AccountController extends Controller
*
* @return \Illuminate\Http\JsonResponse
*/
public function incomeByCategory(JournalCollectorInterface $collector, Account $account, Carbon $start, Carbon $end)
public function incomeCategory(JournalCollectorInterface $collector, Account $account, Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($account->id);
@ -251,9 +251,9 @@ class AccountController extends Controller
*
* @return \Illuminate\Http\JsonResponse
*/
public function report(Carbon $start, Carbon $end, Collection $accounts)
public function report(Collection $accounts, Carbon $start, Carbon $end)
{
return Response::json($this->accountBalanceChart($start, $end, $accounts));
return Response::json($this->accountBalanceChart($accounts, $start, $end));
}
/**
@ -406,13 +406,13 @@ class AccountController extends Controller
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return array
*/
private function accountBalanceChart(Carbon $start, Carbon $end, Collection $accounts): array
private function accountBalanceChart(Collection $accounts, Carbon $start, Carbon $end): array
{
// chart properties for cache:
$cache = new CacheProperties();

View File

@ -193,7 +193,7 @@ class BudgetController extends Controller
*
* @return \Illuminate\Http\JsonResponse
*/
public function period(BudgetRepositoryInterface $repository, Budget $budget, Carbon $start, Carbon $end, Collection $accounts)
public function period(BudgetRepositoryInterface $repository, Budget $budget, Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
$cache = new CacheProperties();
@ -209,7 +209,7 @@ class BudgetController extends Controller
// the expenses:
$periods = Navigation::listOfPeriods($start, $end);
$entries = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end);
$entries = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end, false);
$budgeted = [];
$key = Navigation::preferredCarbonFormat($start, $end);
$range = Navigation::preferredRangeFormat($start, $end);
@ -252,6 +252,47 @@ class BudgetController extends Controller
return Response::json($data);
}
/**
* @param BudgetRepositoryInterface $repository
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Http\JsonResponse
*/
public function periodNoBudget(BudgetRepositoryInterface $repository, Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($accounts);
$cache->addProperty('no-budget');
$cache->addProperty('period');
if ($cache->has()) {
return Response::json($cache->get());
}
// the expenses:
$periods = Navigation::listOfPeriods($start, $end);
$entries = $repository->getNoBudgetPeriodReport($accounts, $start, $end);
// join them:
$result = [];
foreach (array_keys($periods) as $period) {
$nice = $periods[$period];
$result[$nice] = [
'spent' => isset($entries['entries'][$period]) ? $entries['entries'][$period] : '0',
];
}
$data = $this->generator->periodNoBudget($result);
$cache->store($data);
return Response::json($data);
}
/**
* @param Collection $repetitions
* @param Budget $budget

View File

@ -152,6 +152,84 @@ class CategoryController extends Controller
}
/**
* @param CRI $repository
* @param Category $category
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Http\JsonResponse|mixed
*/
public function reportPeriod(CRI $repository, Category $category, Collection $accounts, Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('category-period-chart');
$cache->addProperty($accounts->pluck('id')->toArray());
$cache->addProperty($category);
if ($cache->has()) {
return $cache->get();
}
$expenses = $repository->periodExpenses(new Collection([$category]), $accounts, $start, $end);
$income = $repository->periodIncome(new Collection([$category]), $accounts, $start, $end);
$periods = Navigation::listOfPeriods($start, $end);
// join them:
$result = [];
foreach (array_keys($periods) as $period) {
$nice = $periods[$period];
$result[$nice] = [
'earned' => $income[$category->id]['entries'][$period] ?? '0',
'spent' => $expenses[$category->id]['entries'][$period] ?? '0',
];
}
$data = $this->generator->reportPeriod($result);
return Response::json($data);
}
/**
* @param CRI $repository
* @param Category $category
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Http\JsonResponse|mixed
*/
public function reportPeriodNoCategory(CRI $repository, Collection $accounts, Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('no-category-period-chart');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
return $cache->get();
}
$expenses = $repository->periodExpensesNoCategory($accounts, $start, $end);
$income = $repository->periodIncomeNoCategory($accounts, $start, $end);
$periods = Navigation::listOfPeriods($start, $end);
// join them:
$result = [];
foreach (array_keys($periods) as $period) {
$nice = $periods[$period];
$result[$nice] = [
'earned' => $income['entries'][$period] ?? '0',
'spent' => $expenses['entries'][$period] ?? '0',
];
}
$data = $this->generator->reportPeriod($result);
return Response::json($data);
}
/**
* @param CRI $repository
* @param Category $category

View File

@ -49,13 +49,12 @@ class ReportController extends Controller
* This chart, by default, is shown on the multi-year and year report pages,
* which means that giving it a 2 week "period" should be enough granularity.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @param Carbon $start
* @param Carbon $end
* @return \Illuminate\Http\JsonResponse
*/
public function netWorth(Carbon $start, Carbon $end, Collection $accounts)
public function netWorth(Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
$cache = new CacheProperties;
@ -90,13 +89,16 @@ class ReportController extends Controller
/**
* Shows income and expense, debet/credit: operations
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
*
* @return \Illuminate\Http\JsonResponse
*/
public function yearInOut(Carbon $start, Carbon $end, Collection $accounts)
public function operations(Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
$cache = new CacheProperties;
@ -112,14 +114,14 @@ class ReportController extends Controller
if ($start->diffInMonths($end) > 12) {
// data = method X
$data = $this->multiYearInOut($chartSource['earned'], $chartSource['spent'], $start, $end);
$data = $this->multiYearOperations($chartSource['earned'], $chartSource['spent'], $start, $end);
$cache->store($data);
return Response::json($data);
}
// data = method Y
$data = $this->singleYearInOut($chartSource['earned'], $chartSource['spent'], $start, $end);
$data = $this->singleYearOperations($chartSource['earned'], $chartSource['spent'], $start, $end);
$cache->store($data);
return Response::json($data);
@ -128,14 +130,14 @@ class ReportController extends Controller
}
/**
* Shows sum income and expense, debet/credit: operations
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return \Illuminate\Http\JsonResponse
* @internal param AccountRepositoryInterface $repository
*/
public function yearInOutSummarized(Carbon $start, Carbon $end, Collection $accounts)
public function sum(Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
@ -151,13 +153,13 @@ class ReportController extends Controller
if ($start->diffInMonths($end) > 12) {
// per year
$data = $this->multiYearInOutSummarized($chartSource['earned'], $chartSource['spent'], $start, $end);
$data = $this->multiYearSum($chartSource['earned'], $chartSource['spent'], $start, $end);
$cache->store($data);
return Response::json($data);
}
// per month!
$data = $this->singleYearInOutSummarized($chartSource['earned'], $chartSource['spent'], $start, $end);
$data = $this->singleYearSum($chartSource['earned'], $chartSource['spent'], $start, $end);
$cache->store($data);
return Response::json($data);
@ -172,7 +174,7 @@ class ReportController extends Controller
*
* @return array
*/
protected function multiYearInOut(array $earned, array $spent, Carbon $start, Carbon $end)
protected function multiYearOperations(array $earned, array $spent, Carbon $start, Carbon $end)
{
$entries = new Collection;
while ($start < $end) {
@ -184,7 +186,7 @@ class ReportController extends Controller
$start->addYear();
}
$data = $this->generator->multiYearInOut($entries);
$data = $this->generator->multiYearOperations($entries);
return $data;
}
@ -197,7 +199,7 @@ class ReportController extends Controller
*
* @return array
*/
protected function multiYearInOutSummarized(array $earned, array $spent, Carbon $start, Carbon $end)
protected function multiYearSum(array $earned, array $spent, Carbon $start, Carbon $end)
{
$income = '0';
$expense = '0';
@ -213,7 +215,7 @@ class ReportController extends Controller
$start->addYear();
}
$data = $this->generator->multiYearInOutSummarized($income, $expense, $count);
$data = $this->generator->multiYearSum($income, $expense, $count);
return $data;
}
@ -245,7 +247,7 @@ class ReportController extends Controller
*
* @return array
*/
protected function singleYearInOut(array $earned, array $spent, Carbon $start, Carbon $end)
protected function singleYearOperations(array $earned, array $spent, Carbon $start, Carbon $end)
{
// per month? simply use each month.
@ -260,7 +262,7 @@ class ReportController extends Controller
$start->addMonth();
}
$data = $this->generator->yearInOut($entries);
$data = $this->generator->yearOperations($entries);
return $data;
}
@ -273,7 +275,7 @@ class ReportController extends Controller
*
* @return array
*/
protected function singleYearInOutSummarized(array $earned, array $spent, Carbon $start, Carbon $end)
protected function singleYearSum(array $earned, array $spent, Carbon $start, Carbon $end)
{
$income = '0';
$expense = '0';
@ -289,7 +291,7 @@ class ReportController extends Controller
$start->addMonth();
}
$data = $this->generator->yearInOutSummarized($income, $expense, $count);
$data = $this->generator->yearSum($income, $expense, $count);
return $data;
}

View File

@ -60,14 +60,14 @@ class CurrencyController extends Controller
$subTitle = trans('firefly.create_currency');
// put previous url in session if not redirect from store (not "create another").
if (session('currency.create.fromStore') !== true) {
Session::put('currency.create.url', URL::previous());
if (session('currencies.create.fromStore') !== true) {
Session::put('currencies.create.url', URL::previous());
}
Session::forget('currency.create.fromStore');
Session::forget('currencies.create.fromStore');
Session::flash('gaEventCategory', 'currency');
Session::flash('gaEventAction', 'create');
return view('currency.create', compact('subTitleIcon', 'subTitle'));
return view('currencies.create', compact('subTitleIcon', 'subTitle'));
}
/**
@ -85,7 +85,7 @@ class CurrencyController extends Controller
Cache::forget('FFCURRENCYSYMBOL');
Cache::forget('FFCURRENCYCODE');
return redirect(route('currency.index'));
return redirect(route('currencies.index'));
}
@ -99,18 +99,18 @@ class CurrencyController extends Controller
if (!$this->canDeleteCurrency($currency)) {
Session::flash('error', trans('firefly.cannot_delete_currency', ['name' => $currency->name]));
return redirect(route('currency.index'));
return redirect(route('currencies.index'));
}
// put previous url in session
Session::put('currency.delete.url', URL::previous());
Session::put('currencies.delete.url', URL::previous());
Session::flash('gaEventCategory', 'currency');
Session::flash('gaEventAction', 'delete');
$subTitle = trans('form.delete_currency', ['name' => $currency->name]);
return view('currency.delete', compact('currency', 'subTitle'));
return view('currencies.delete', compact('currency', 'subTitle'));
}
/**
@ -124,7 +124,7 @@ class CurrencyController extends Controller
if (!$this->canDeleteCurrency($currency)) {
Session::flash('error', trans('firefly.cannot_delete_currency', ['name' => $currency->name]));
return redirect(route('currency.index'));
return redirect(route('currencies.index'));
}
Session::flash('success', trans('firefly.deleted_currency', ['name' => $currency->name]));
@ -132,7 +132,7 @@ class CurrencyController extends Controller
$currency->forceDelete();
}
return redirect(session('currency.delete.url'));
return redirect(session('currencies.delete.url'));
}
/**
@ -147,14 +147,14 @@ class CurrencyController extends Controller
$currency->symbol = htmlentities($currency->symbol);
// put previous url in session if not redirect from store (not "return_to_edit").
if (session('currency.edit.fromUpdate') !== true) {
Session::put('currency.edit.url', URL::previous());
if (session('currencies.edit.fromUpdate') !== true) {
Session::put('currencies.edit.url', URL::previous());
}
Session::forget('currency.edit.fromUpdate');
Session::forget('currencies.edit.fromUpdate');
Session::flash('gaEventCategory', 'currency');
Session::flash('gaEventAction', 'edit');
return view('currency.edit', compact('currency', 'subTitle', 'subTitleIcon'));
return view('currencies.edit', compact('currency', 'subTitle', 'subTitleIcon'));
}
@ -174,7 +174,7 @@ class CurrencyController extends Controller
}
return view('currency.index', compact('currencies', 'defaultCurrency'));
return view('currencies.index', compact('currencies', 'defaultCurrency'));
}
/**
@ -189,7 +189,7 @@ class CurrencyController extends Controller
if (!auth()->user()->hasRole('owner')) {
Log::error('User ' . auth()->user()->id . ' is not admin, but tried to store a currency.');
return redirect(session('currency.create.url'));
return redirect(session('currencies.create.url'));
}
$data = $request->getCurrencyData();
@ -197,13 +197,13 @@ class CurrencyController extends Controller
Session::flash('success', trans('firefly.created_currency', ['name' => $currency->name]));
if (intval(Input::get('create_another')) === 1) {
Session::put('currency.create.fromStore', true);
Session::put('currencies.create.fromStore', true);
return redirect(route('currency.create'))->withInput();
return redirect(route('currencies.create'))->withInput();
}
// redirect to previous URL.
return redirect(session('currency.create.url'));
return redirect(session('currencies.create.url'));
}
@ -226,13 +226,13 @@ class CurrencyController extends Controller
if (intval(Input::get('return_to_edit')) === 1) {
Session::put('currency.edit.fromUpdate', true);
Session::put('currencies.edit.fromUpdate', true);
return redirect(route('currency.edit', [$currency->id]));
return redirect(route('currencies.edit', [$currency->id]));
}
// redirect to previous URL.
return redirect(session('currency.edit.url'));
return redirect(session('currencies.edit.url'));
}

View File

@ -102,7 +102,6 @@ class JsonController extends Controller
*
* @return \Illuminate\Http\JsonResponse
*
* @internal param ARI $accountRepository
*/
public function boxIn(AccountTaskerInterface $accountTasker, AccountRepositoryInterface $repository)
{

View File

@ -46,7 +46,7 @@ class ReportController extends Controller
* @return \Illuminate\Http\JsonResponse
* @throws FireflyException
*/
public function info(Request $request)
public function general(Request $request)
{
$attributes = $request->get('attributes') ?? [];
$attributes = $this->parseAttributes($attributes);

View File

@ -74,7 +74,7 @@ class PreferencesController extends Controller
Session::flash('success', strval(trans('firefly.pref_two_factor_auth_disabled')));
Session::flash('info', strval(trans('firefly.pref_two_factor_auth_remove_it')));
return redirect(route('preferences'));
return redirect(route('preferences.index'));
}
/**
@ -122,7 +122,7 @@ class PreferencesController extends Controller
Session::flash('success', strval(trans('firefly.saved_preferences')));
Preferences::mark();
return redirect(route('preferences'));
return redirect(route('preferences.index'));
}
/**
@ -206,7 +206,7 @@ class PreferencesController extends Controller
return redirect(route('preferences.code'));
}
return redirect(route('preferences'));
return redirect(route('preferences.index'));
}
/**

View File

@ -108,7 +108,7 @@ class ProfileController extends Controller
Session::flash('success', strval(trans('firefly.password_changed')));
return redirect(route('profile'));
return redirect(route('profile.index'));
}
/**

View File

@ -29,13 +29,13 @@ class AccountController extends Controller
{
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @return mixed|string
*/
public function accountReport(Carbon $start, Carbon $end, Collection $accounts)
public function general(Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
$cache = new CacheProperties;
@ -47,9 +47,9 @@ class AccountController extends Controller
return $cache->get();
}
/** @var AccountTaskerInterface $accountTasker */
$accountTasker = app(AccountTaskerInterface::class);
$accountReport = $accountTasker->getAccountReport($start, $end, $accounts);
$accountReport = $accountTasker->getAccountReport($accounts, $start, $end);
$result = view('reports.partials.accounts', compact('accountReport'))->render();
$cache->store($result);

View File

@ -30,13 +30,13 @@ class BalanceController extends Controller
/**
* @param BalanceReportHelperInterface $helper
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return string
* @return mixed|string
*/
public function balanceReport(BalanceReportHelperInterface $helper, Carbon $start, Carbon $end, Collection $accounts)
public function general(BalanceReportHelperInterface $helper,Collection $accounts, Carbon $start, Carbon $end)
{
@ -50,7 +50,7 @@ class BalanceController extends Controller
return $cache->get();
}
$balance = $helper->getBalanceReport($start, $end, $accounts);
$balance = $helper->getBalanceReport($accounts, $start, $end);
$result = view('reports.partials.balance', compact('balance'))->render();
$cache->store($result);

View File

@ -17,6 +17,7 @@ namespace FireflyIII\Http\Controllers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Report\BudgetReportHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
use Navigation;
@ -29,43 +30,16 @@ use Navigation;
class BudgetController extends Controller
{
/**
*
* @param BudgetReportHelperInterface $helper
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return string
*/
public function budgetPeriodReport(BudgetReportHelperInterface $helper, Carbon $start, Carbon $end, Collection $accounts)
{
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('budget-period-report');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
return $cache->get();
}
$periods = Navigation::listOfPeriods($start, $end);
$budgets = $helper->getBudgetPeriodReport($start, $end, $accounts);
$result = view('reports.partials.budget-period', compact('budgets', 'periods'))->render();
$cache->store($result);
return $result;
}
/**
* @param BudgetReportHelperInterface $helper
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return string
* @return mixed|string
*/
public function budgetReport(BudgetReportHelperInterface $helper, Carbon $start, Carbon $end, Collection $accounts)
public function general(BudgetReportHelperInterface $helper, Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
@ -86,4 +60,64 @@ class BudgetController extends Controller
return $result;
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return mixed|string
*/
public function period(Collection $accounts, Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('budget-period-report');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
return $cache->get();
}
// generate budget report right here.
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$budgets = $repository->getBudgets();
$data = $repository->getBudgetPeriodReport($budgets, $accounts, $start, $end);
$data[0] = $repository->getNoBudgetPeriodReport($accounts, $start, $end); // append report data for "no budget"
$report = $this->filterBudgetPeriodReport($data);
$periods = Navigation::listOfPeriods($start, $end);
$result = view('reports.partials.budget-period', compact('report', 'periods'))->render();
$cache->store($result);
return $result;
}
/**
* Filters empty results from getBudgetPeriodReport
*
* @param array $data
*
* @return array
*/
private function filterBudgetPeriodReport(array $data): array
{
/**
* @var int $budgetId
* @var array $set
*/
foreach ($data as $budgetId => $set) {
$sum = '0';
foreach ($set['entries'] as $amount) {
$sum = bcadd($amount, $sum);
}
$data[$budgetId]['sum'] = $sum;
if (bccomp('0', $sum) === 0) {
unset($data[$budgetId]);
}
}
return $data;
}
}

View File

@ -17,8 +17,12 @@ namespace FireflyIII\Http\Controllers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
use Log;
use Navigation;
/**
* Class CategoryController
@ -27,16 +31,82 @@ use Illuminate\Support\Collection;
*/
class CategoryController extends Controller
{
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return mixed|string
*/
public function expenses(Collection $accounts, Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('category-period-expenses-report');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
Log::debug('Return report from cache');
return $cache->get();
}
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
$categories = $repository->getCategories();
$data = $repository->periodExpenses($categories, $accounts, $start, $end);
$data[0] = $repository->periodExpensesNoCategory($accounts, $start, $end);
$report = $this->filterReport($data);
$periods = Navigation::listOfPeriods($start, $end);
$result = view('reports.partials.category-period', compact('report', 'periods'))->render();
$cache->store($result);
return $result;
}
/**
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return string
*/
public function income(Collection $accounts, Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('category-period-income-report');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
Log::debug('Return report from cache');
return $cache->get();
}
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
$categories = $repository->getCategories();
$data = $repository->periodIncome($categories, $accounts, $start, $end);
$data[0] = $repository->periodIncomeNoCategory($accounts, $start, $end);
$report = $this->filterReport($data);
$periods = Navigation::listOfPeriods($start, $end);
$result = view('reports.partials.category-period', compact('report', 'periods'))->render();
$cache->store($result);
return $result;
}
/**
* @param ReportHelperInterface $helper
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @return mixed|string
*/
public function categoryReport(ReportHelperInterface $helper, Carbon $start, Carbon $end, Collection $accounts)
public function operations(Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
$cache = new CacheProperties;
@ -48,12 +118,56 @@ class CategoryController extends Controller
return $cache->get();
}
$categories = $helper->getCategoryReport($start, $end, $accounts);
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
$categories = $repository->getCategories();
$report = [];
/** @var Category $category */
foreach ($categories as $category) {
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $end);
if (bccomp($spent, '0') !== 0) {
$report[$category->id] = ['name' => $category->name, 'spent' => $spent];
}
}
$result = view('reports.partials.categories', compact('categories'))->render();
// sort the result
// Obtain a list of columns
$sum = [];
foreach ($report as $categoryId => $row) {
$sum[$categoryId] = floatval($row['spent']);
}
array_multisort($sum, SORT_ASC, $report);
$result = view('reports.partials.categories', compact('report'))->render();
$cache->store($result);
return $result;
}
/**
* Filters empty results from category period report
*
* @param array $data
*
* @return array
*/
private function filterReport(array $data): array
{
foreach ($data as $categoryId => $set) {
$sum = '0';
foreach ($set['entries'] as $amount) {
$sum = bcadd($amount, $sum);
}
$data[$categoryId]['sum'] = $sum;
if (bccomp('0', $sum) === 0) {
unset($data[$categoryId]);
}
}
return $data;
}
}

View File

@ -1,119 +0,0 @@
<?php
/**
* InOutController.php
* Copyright (C) 2016 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\Controllers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
/**
* Class InOutController
*
* @package FireflyIII\Http\Controllers\Report
*/
class InOutController extends Controller
{
/**
* @param ReportHelperInterface $helper
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return \Illuminate\Http\JsonResponse
*/
public function expenseReport(ReportHelperInterface $helper, Carbon $start, Carbon $end, Collection $accounts)
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('expense-report');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
return $cache->get();
}
$expenses = $helper->getExpenseReport($start, $end, $accounts);
$result = view('reports.partials.expenses', compact('expenses'))->render();
$cache->store($result);
return $result;
}
/**
* @param ReportHelperInterface $helper
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return \Illuminate\Http\JsonResponse
*/
public function incExpReport(ReportHelperInterface $helper, Carbon $start, Carbon $end, Collection $accounts)
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('inc-exp-report');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
return $cache->get();
}
$incomes = $helper->getIncomeReport($start, $end, $accounts);
$expenses = $helper->getExpenseReport($start, $end, $accounts);
$result = view('reports.partials.income-vs-expenses', compact('expenses', 'incomes'))->render();
$cache->store($result);
return $result;
}
/**
* @param ReportHelperInterface $helper
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return \Illuminate\Http\JsonResponse
*/
public function incomeReport(ReportHelperInterface $helper, Carbon $start, Carbon $end, Collection $accounts)
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('income-report');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
return $cache->get();
}
$incomes = $helper->getIncomeReport($start, $end, $accounts);
$result = view('reports.partials.income', compact('incomes'))->render();
$cache->store($result);
return $result;
}
}

View File

@ -0,0 +1,245 @@
<?php
/**
* OperationsController.php
* Copyright (C) 2016 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\Controllers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
/**
* Class OperationsController
*
* @package FireflyIII\Http\Controllers\Report
*/
class OperationsController extends Controller
{
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return mixed|string
*/
public function expenses(Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('expense-report');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
return $cache->get();
}
$expenses = $this->getExpenseReport($start, $end, $accounts);
$result = view('reports.partials.expenses', compact('expenses'))->render();
$cache->store($result);
return $result;
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return mixed|string
*/
public function operations(Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('inc-exp-report');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
return $cache->get();
}
$incomes = $this->getIncomeReport($start, $end, $accounts);
$expenses = $this->getExpenseReport($start, $end, $accounts);
$incomeSum = array_sum(
array_map(
function ($item) {
return $item['sum'];
}, $incomes
)
);
$expensesSum = array_sum(
array_map(
function ($item) {
return $item['sum'];
}, $expenses
)
);
$result = view('reports.partials.operations', compact('incomeSum', 'expensesSum'))->render();
$cache->store($result);
return $result;
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return string
*/
public function income(Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('income-report');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
//return $cache->get();
}
$income = $this->getIncomeReport($start, $end, $accounts);
$result = view('reports.partials.income', compact('income'))->render();
$cache->store($result);
return $result;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return array
*/
private function getExpenseReport(Carbon $start, Carbon $end, Collection $accounts): array
{
// get all expenses for the given accounts in the given period!
// also transfers!
// get all transactions:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->withOpposingAccount()
->enableInternalFilter();
$transactions = $collector->getJournals();
$transactions = $transactions->filter(
function (Transaction $transaction) {
// return negative amounts only.
if (bccomp($transaction->transaction_amount, '0') === -1) {
return $transaction;
}
return false;
}
);
$expenses = $this->groupByOpposing($transactions);
// sort the result
// Obtain a list of columns
$sum = [];
foreach ($expenses as $accountId => $row) {
$sum[$accountId] = floatval($row['sum']);
}
array_multisort($sum, SORT_ASC, $expenses);
return $expenses;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return array
*/
private function getIncomeReport(Carbon $start, Carbon $end, Collection $accounts): array
{
// get all expenses for the given accounts in the given period!
// also transfers!
// get all transactions:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->withOpposingAccount()
->enableInternalFilter();
$transactions = $collector->getJournals();
$transactions = $transactions->filter(
function (Transaction $transaction) {
// return positive amounts only.
if (bccomp($transaction->transaction_amount, '0') === 1) {
return $transaction;
}
return false;
}
);
$income = $this->groupByOpposing($transactions);
// sort the result
// Obtain a list of columns
$sum = [];
foreach ($income as $accountId => $row) {
$sum[$accountId] = floatval($row['sum']);
}
array_multisort($sum, SORT_DESC, $income);
return $income;
}
/**
* @param Collection $transactions
*
* @return array
*/
private function groupByOpposing(Collection $transactions): array
{
$expenses = [];
// join the result together:
foreach ($transactions as $transaction) {
$opposingId = $transaction->opposing_account_id;
$name = $transaction->opposing_account_name;
if (!isset($expenses[$opposingId])) {
$expenses[$opposingId] = [
'id' => $opposingId,
'name' => $name,
'sum' => '0',
'count' => 0,
];
}
$expenses[$opposingId]['sum'] = bcadd($expenses[$opposingId]['sum'], $transaction->transaction_amount);
$expenses[$opposingId]['count']++;
}
return $expenses;
}
}

View File

@ -61,14 +61,13 @@ class ReportController extends Controller
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return string
* @throws FireflyException
*/
public function auditReport(Carbon $start, Carbon $end, Collection $accounts)
public function auditReport(Collection $accounts, Carbon $start, Carbon $end)
{
if ($end < $start) {
return view('error')->with('message', trans('firefly.end_after_start_date'));
@ -97,15 +96,14 @@ class ReportController extends Controller
}
/**
* @param Collection $accounts
* @param Collection $categories
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @param Collection $categories
*
* @return string
*/
public function categoryReport(Carbon $start, Carbon $end, Collection $accounts, Collection $categories)
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'));
@ -134,14 +132,13 @@ class ReportController extends Controller
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return string
* @throws FireflyException
*/
public function defaultReport(Carbon $start, Carbon $end, Collection $accounts)
public function defaultReport(Collection $accounts, Carbon $start, Carbon $end)
{
if ($end < $start) {
return view('error')->with('message', trans('firefly.end_after_start_date'));
@ -227,6 +224,12 @@ class ReportController extends Controller
return redirect(route('reports.index'));
}
if ($request->getCategoryList()->count() === 0 && $reportType === 'category') {
Session::flash('error', trans('firefly.select_more_than_one_category'));
return redirect(route('reports.index'));
}
if ($end < $start) {
return view('error')->with('message', trans('firefly.end_after_start_date'));
}
@ -240,13 +243,13 @@ class ReportController extends Controller
default:
throw new FireflyException(sprintf('Firefly does not support the "%s"-report yet.', $reportType));
case 'category':
$uri = route('reports.report.category', [$start, $end, $accounts, $categories]);
$uri = route('reports.report.category', [$accounts, $categories, $start, $end]);
break;
case 'default':
$uri = route('reports.report.default', [$start, $end, $accounts]);
$uri = route('reports.report.default', [$accounts, $start, $end]);
break;
case 'audit':
$uri = route('reports.report.audit', [$start, $end, $accounts]);
$uri = route('reports.report.audit', [$accounts, $start, $end]);
break;
}

View File

@ -104,7 +104,6 @@ class RuleController extends Controller
* @param Rule $rule
*
* @return View
* @internal param RuleRepositoryInterface $repository
*/
public function delete(Rule $rule)
{

View File

@ -15,14 +15,12 @@ namespace FireflyIII\Http\Controllers;
use FireflyIII\Helpers\Collector\JournalCollector;
use FireflyIII\Http\Requests\TagFormRequest;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Support\Collection;
use Input;
use Preferences;
use Response;
use Session;
use URL;
use View;
@ -170,33 +168,14 @@ class TagController extends Controller
return view('tags.edit', compact('tag', 'subTitle', 'subTitleIcon', 'tagOptions'));
}
/**
* @param $state
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function hideTagHelp(string $state)
{
$newState = $state == 'true' ? true : false;
Preferences::set('hideTagHelp', $newState);
return Response::json([true]);
}
/**
*
*/
public function index()
{
/** @var Preference $helpHiddenPref */
$helpHiddenPref = Preferences::get('hideTagHelp', false);
$title = 'Tags';
$mainTitleIcon = 'fa-tags';
$helpHidden = $helpHiddenPref->data;
// group years.
$types = ['nothing', 'balancingAct', 'advancePayment'];
$title = 'Tags';
$mainTitleIcon = 'fa-tags';
$types = ['nothing', 'balancingAct', 'advancePayment'];
// loop each types and get the tags, group them by year.
$collection = [];
@ -223,7 +202,7 @@ class TagController extends Controller
}
}
return view('tags.index', compact('title', 'mainTitleIcon', 'types', 'helpHidden', 'collection'));
return view('tags.index', compact('title', 'mainTitleIcon', 'types', 'collection'));
}
/**

View File

@ -62,7 +62,7 @@ class ConvertController extends Controller
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*/
public function convert(TransactionType $destinationType, TransactionJournal $journal)
public function index(TransactionType $destinationType, TransactionJournal $journal)
{
if ($this->isOpeningBalance($journal)) {
return $this->redirectToAccount($journal);
@ -115,7 +115,7 @@ class ConvertController extends Controller
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function submit(Request $request, JournalRepositoryInterface $repository, TransactionType $destinationType, TransactionJournal $journal)
public function postIndex(Request $request, JournalRepositoryInterface $repository, TransactionType $destinationType, TransactionJournal $journal)
{
if ($this->isOpeningBalance($journal)) {
return $this->redirectToAccount($journal);

View File

@ -179,7 +179,7 @@ class SingleController extends Controller
$count = $journal->transactions()->count();
if ($count > 2) {
return redirect(route('transactions.edit-split', [$journal->id]));
return redirect(route('transactions.split.edit', [$journal->id]));
}
$what = strtolower(TransactionJournal::transactionTypeStr($journal));
@ -286,7 +286,7 @@ class SingleController extends Controller
if ($doSplit === true) {
// redirect to edit screen:
return redirect(route('transactions.edit-split', [$journal->id]));
return redirect(route('transactions.split.edit', [$journal->id]));
}

View File

@ -157,7 +157,7 @@ class SplitController extends Controller
// set value so edit routine will not overwrite URL:
Session::put('transactions.edit-split.fromUpdate', true);
return redirect(route('transactions.edit-split', [$journal->id]))->withInput(['return_to_edit' => 1]);
return redirect(route('transactions.split.edit', [$journal->id]))->withInput(['return_to_edit' => 1]);
}
// redirect to previous URL.
@ -249,8 +249,8 @@ class SplitController extends Controller
$transactions = $this->tasker->getTransactionsOverview($journal);
$return = [];
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = [
foreach ($transactions as $index => $transaction) {
$set = [
'description' => $transaction['description'],
'source_account_id' => $transaction['source_account_id'],
'source_account_name' => $transaction['source_account_name'],
@ -260,6 +260,15 @@ class SplitController extends Controller
'budget_id' => isset($transaction['budget_id']) ? intval($transaction['budget_id']) : 0,
'category' => $transaction['category'],
];
// set initial category and/or budget:
if (count($transactions) === 1 && $index === 0) {
$set['budget_id'] = TransactionJournal::budgetId($journal);
$set['category'] = TransactionJournal::categoryAsString($journal);
}
$return[] = $set;
}
return $return;

View File

@ -146,7 +146,7 @@ class TransactionController extends Controller
*
* @return View
*/
public function indexDate(Request $request, string $what, string $date)
public function indexByDate(Request $request, string $what, string $date)
{
$carbon = new Carbon($date);
$range = Preferences::get('viewRange', '1M')->data;

View File

@ -57,7 +57,7 @@ class AuthenticateTwoFactor
$has2faSecret = !is_null(Preferences::get('twoFactorAuthSecret'));
$is2faAuthed = Session::get('twofactor-authenticated');
if ($is2faEnabled && $has2faSecret && !$is2faAuthed) {
return redirect(route('two-factor'));
return redirect(route('two-factor.index'));
}
return $next($request);

View File

@ -46,7 +46,12 @@ class IsConfirmed
return redirect()->guest('login');
}
// must the user be confirmed in the first place?
$mustConfirmAccount = FireflyConfig::get('must_confirm_account', config('firefly.configuration.must_confirm_account'))->data;
$confirmPreference = FireflyConfig::get('must_confirm_account', config('firefly.configuration.must_confirm_account'));
$mustConfirmAccount = false;
if (!is_null($confirmPreference)) {
$mustConfirmAccount = $confirmPreference->data;
}
// user must be logged in, then continue:
$isConfirmed = Preferences::get('user_confirmed', false)->data;

View File

@ -61,7 +61,6 @@ class Range
* @param string|null $guard
*
* @return mixed
* @internal param Closure $next
*/
public function handle(Request $request, Closure $next, $guard = null)
{

View File

@ -42,10 +42,11 @@ class AccountFormRequest extends Request
'name' => trim($this->input('name')),
'active' => intval($this->input('active')) === 1,
'accountType' => $this->input('what'),
'currency_id' => intval($this->input('currency_id')),
'currency_id' => intval($this->input('currency_id')),
'virtualBalance' => round($this->input('virtualBalance'), 2),
'virtualBalanceCurrency' => intval($this->input('amount_currency_id_virtualBalance')),
'iban' => trim($this->input('iban')),
'BIC' => trim($this->input('BIC')),
'accountNumber' => trim($this->input('accountNumber')),
'accountRole' => $this->input('accountRole'),
'openingBalance' => round($this->input('openingBalance'), 2),
@ -79,6 +80,7 @@ class AccountFormRequest extends Request
'name' => $nameRule,
'openingBalance' => 'numeric',
'iban' => 'iban',
'BIC' => 'bic',
'virtualBalance' => 'numeric',
'openingBalanceDate' => 'date',
'currency_id' => 'exists:transaction_currencies,id',

View File

@ -327,29 +327,29 @@ Breadcrumbs::register(
* CURRENCIES
*/
Breadcrumbs::register(
'currency.index', function (BreadCrumbGenerator $breadcrumbs) {
'currencies.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.currencies'), route('currency.index'));
$breadcrumbs->push(trans('firefly.currencies'), route('currencies.index'));
}
);
Breadcrumbs::register(
'currency.create', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('currency.index');
$breadcrumbs->push(trans('firefly.create_currency'), route('currency.create'));
'currencies.create', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('currencies.index');
$breadcrumbs->push(trans('firefly.create_currency'), route('currencies.create'));
}
);
Breadcrumbs::register(
'currency.edit', function (BreadCrumbGenerator $breadcrumbs, TransactionCurrency $currency) {
$breadcrumbs->parent('currency.index');
$breadcrumbs->push(trans('breadcrumbs.edit_currency', ['name' => e($currency->name)]), route('currency.edit', [$currency->id]));
'currencies.edit', function (BreadCrumbGenerator $breadcrumbs, TransactionCurrency $currency) {
$breadcrumbs->parent('currencies.index');
$breadcrumbs->push(trans('breadcrumbs.edit_currency', ['name' => e($currency->name)]), route('currencies.edit', [$currency->id]));
}
);
Breadcrumbs::register(
'currency.delete', function (BreadCrumbGenerator $breadcrumbs, TransactionCurrency $currency) {
$breadcrumbs->parent('currency.index');
$breadcrumbs->push(trans('breadcrumbs.delete_currency', ['name' => e($currency->name)]), route('currency.delete', [$currency->id]));
'currencies.delete', function (BreadCrumbGenerator $breadcrumbs, TransactionCurrency $currency) {
$breadcrumbs->parent('currencies.index');
$breadcrumbs->push(trans('breadcrumbs.delete_currency', ['name' => e($currency->name)]), route('currencies.delete', [$currency->id]));
}
);
@ -404,9 +404,9 @@ Breadcrumbs::register(
* PREFERENCES
*/
Breadcrumbs::register(
'preferences', function (BreadCrumbGenerator $breadcrumbs) {
'preferences.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.preferences'), route('preferences'));
$breadcrumbs->push(trans('breadcrumbs.preferences'), route('preferences.index'));
}
);
@ -414,7 +414,7 @@ Breadcrumbs::register(
Breadcrumbs::register(
'preferences.code', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.preferences'), route('preferences'));
$breadcrumbs->push(trans('breadcrumbs.preferences'), route('preferences.index'));
}
);
@ -423,22 +423,22 @@ Breadcrumbs::register(
* PROFILE
*/
Breadcrumbs::register(
'profile', function (BreadCrumbGenerator $breadcrumbs) {
'profile.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.profile'), route('profile'));
$breadcrumbs->push(trans('breadcrumbs.profile'), route('profile.index'));
}
);
Breadcrumbs::register(
'profile.change-password', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('profile');
$breadcrumbs->parent('profile.index');
$breadcrumbs->push(trans('breadcrumbs.changePassword'), route('profile.change-password'));
}
);
Breadcrumbs::register(
'profile.delete-account', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('profile');
$breadcrumbs->parent('profile.index');
$breadcrumbs->push(trans('firefly.delete_account'), route('profile.delete-account'));
}
@ -529,9 +529,9 @@ Breadcrumbs::register(
* SEARCH
*/
Breadcrumbs::register(
'search', function (BreadCrumbGenerator $breadcrumbs, $query) {
'search.index', function (BreadCrumbGenerator $breadcrumbs, $query) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.searchResult', ['query' => e($query)]), route('search'));
$breadcrumbs->push(trans('breadcrumbs.searchResult', ['query' => e($query)]), route('search.index'));
}
);

View File

@ -199,8 +199,7 @@ class Account extends Model
*/
public function getOpeningBalanceAmount(): string
{
$journal = TransactionJournal
::sortCorrectly()
$journal = TransactionJournal::sortCorrectly()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $this->id)
->transactionTypes([TransactionType::OPENING_BALANCE])
@ -230,8 +229,7 @@ class Account extends Model
public function getOpeningBalanceDate(): Carbon
{
$date = new Carbon('1900-01-01');
$journal = TransactionJournal
::sortCorrectly()
$journal = TransactionJournal::sortCorrectly()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $this->id)
->transactionTypes([TransactionType::OPENING_BALANCE])

View File

@ -64,8 +64,7 @@ class TransactionJournal extends TransactionJournalSupport
public static function routeBinder($value)
{
if (auth()->check()) {
$object = TransactionJournal
::where('transaction_journals.id', $value)
$object = TransactionJournal::where('transaction_journals.id', $value)
->with('transactionType')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->where('user_id', auth()->user()->id)->first(['transaction_journals.*']);

View File

@ -41,7 +41,7 @@ class AccountRepository implements AccountRepositoryInterface
/** @var User */
private $user;
/** @var array */
private $validFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType', 'accountNumber','currency_id'];
private $validFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType', 'accountNumber', 'currency_id', 'BIC'];
/**
* AttachmentRepository constructor.
@ -60,7 +60,7 @@ class AccountRepository implements AccountRepositoryInterface
*
* @return int
*/
public function count(array $types):int
public function count(array $types): int
{
$count = $this->user->accounts()->accountTypeIn($types)->count();
@ -367,12 +367,11 @@ class AccountRepository implements AccountRepositoryInterface
*/
protected function openingBalanceTransaction(Account $account): TransactionJournal
{
$journal = TransactionJournal
::sortCorrectly()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->transactionTypes([TransactionType::OPENING_BALANCE])
->first(['transaction_journals.*']);
$journal = TransactionJournal::sortCorrectly()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->transactionTypes([TransactionType::OPENING_BALANCE])
->first(['transaction_journals.*']);
if (is_null($journal)) {
Log::debug('Could not find a opening balance journal, return empty one.');
@ -482,7 +481,7 @@ class AccountRepository implements AccountRepositoryInterface
*
* @return Account
*/
protected function storeOpposingAccount(float $amount, string $name):Account
protected function storeOpposingAccount(float $amount, string $name): Account
{
$type = $amount < 0 ? 'expense' : 'revenue';
$opposingData = [

View File

@ -119,6 +119,6 @@ interface AccountRepositoryInterface
*
* @return Account
*/
public function store(array $data) : Account;
public function store(array $data): Account;
}

View File

@ -107,41 +107,12 @@ class AccountTasker implements AccountTaskerInterface
/**
* @param Collection $accounts
* @param Collection $excluded
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
* @see self::financialReport
*
*/
public function expenseReport(Collection $accounts, Collection $excluded, Carbon $start, Carbon $end): Collection
{
$idList = [
'accounts' => $accounts->pluck('id')->toArray(),
'exclude' => $excluded->pluck('id')->toArray(),
];
Log::debug(
'Now calling expenseReport.',
['accounts' => $idList['accounts'], 'excluded' => $idList['exclude'],
'start' => $start->format('Y-m-d'),
'end' => $end->format('Y-m-d'),
]
);
return $this->financialReport($idList, $start, $end, false);
}
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return AccountCollection
*/
public function getAccountReport(Carbon $start, Carbon $end, Collection $accounts): AccountCollection
public function getAccountReport(Collection $accounts, Carbon $start, Carbon $end): AccountCollection
{
$startAmount = '0';
$endAmount = '0';
@ -190,35 +161,6 @@ class AccountTasker implements AccountTaskerInterface
return $object;
}
/**
* @param Collection $accounts
* @param Collection $excluded
* @param Carbon $start
* @param Carbon $end
*
* @see AccountTasker::financialReport()
*
* @return Collection
*
*/
public function incomeReport(Collection $accounts, Collection $excluded, Carbon $start, Carbon $end): Collection
{
$idList = [
'accounts' => $accounts->pluck('id')->toArray(),
'exclude' => $excluded->pluck('id')->toArray(),
];
Log::debug(
'Now calling expenseReport.',
['accounts' => $idList['accounts'], 'excluded' => $idList['exclude'],
'start' => $start->format('Y-m-d'),
'end' => $end->format('Y-m-d'),
]
);
return $this->financialReport($idList, $start, $end, true);
}
/**
* Will return how much money has been going out (ie. spent) by the given account(s).
* Alternatively, will return how much money has been coming in (ie. earned) by the given accounts.
@ -249,21 +191,20 @@ class AccountTasker implements AccountTaskerInterface
$joinModifier = $incoming ? '<' : '>';
$selection = $incoming ? '>' : '<';
$query = Transaction
::distinct()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin(
'transactions as other_side', function (JoinClause $join) use ($joinModifier) {
$join->on('transaction_journals.id', '=', 'other_side.transaction_journal_id')->where('other_side.amount', $joinModifier, 0);
}
)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_journals.user_id', $this->user->id)
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->whereIn('transactions.account_id', $accounts['accounts'])
->where('transactions.amount', $selection, 0);
$query = Transaction::distinct()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin(
'transactions as other_side', function (JoinClause $join) use ($joinModifier) {
$join->on('transaction_journals.id', '=', 'other_side.transaction_journal_id')->where('other_side.amount', $joinModifier, 0);
}
)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_journals.user_id', $this->user->id)
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->whereIn('transactions.account_id', $accounts['accounts'])
->where('transactions.amount', $selection, 0);
if (count($accounts['exclude']) > 0) {
$query->whereNotIn('other_side.account_id', $accounts['exclude']);
}
@ -279,91 +220,4 @@ class AccountTasker implements AccountTaskerInterface
return $sum;
}
/**
*
* This method will determin how much has flown (in the given period) from OR to $accounts to/from anywhere else,
* except $excluded. This could be a list of incomes, or a list of expenses. This method shows
* the name, the amount and the number of transactions. It is a summary, and only used in some reports.
*
* $incoming=true a list of incoming money (earnings)
* $incoming=false a list of outgoing money (expenses).
*
* @param array $accounts
* @param Carbon $start
* @param Carbon $end
* @param bool $incoming
*
* Opening balances are ignored.
*
* @return Collection
*/
protected function financialReport(array $accounts, Carbon $start, Carbon $end, bool $incoming): Collection
{
$collection = new Collection;
$joinModifier = $incoming ? '<' : '>';
$selection = $incoming ? '>' : '<';
$query = Transaction
::distinct()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->leftJoin(
'transactions as other_side', function (JoinClause $join) use ($joinModifier) {
$join->on('transaction_journals.id', '=', 'other_side.transaction_journal_id')->where('other_side.amount', $joinModifier, 0);
}
)
->leftJoin('accounts as other_account', 'other_account.id', '=', 'other_side.account_id')
->where('transaction_types.type', '!=', TransactionType::OPENING_BALANCE)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_journals.user_id', $this->user->id)
->whereNull('transactions.deleted_at')
->whereNull('other_side.deleted_at')
->whereNull('transaction_journals.deleted_at')
->whereIn('transactions.account_id', $accounts['accounts'])
->where('other_side.amount', '=', DB::raw('transactions.amount * -1'))
->where('transactions.amount', $selection, 0)
->orderBy('transactions.amount');
if (count($accounts['exclude']) > 0) {
$query->whereNotIn('other_side.account_id', $accounts['exclude']);
}
$set = $query->get(
[
'transaction_journals.id',
'other_side.account_id',
'other_account.name',
'other_account.encrypted',
'transactions.amount',
]
);
// summarize ourselves:
$temp = [];
foreach ($set as $entry) {
// save into $temp:
$id = intval($entry->account_id);
if (isset($temp[$id])) {
$temp[$id]['count']++;
$temp[$id]['amount'] = bcadd($temp[$id]['amount'], $entry->amount);
}
if (!isset($temp[$id])) {
$temp[$id] = [
'name' => intval($entry->encrypted) === 1 ? Crypt::decrypt($entry->name) : $entry->name,
'amount' => $entry->amount,
'count' => 1,
];
}
}
// loop $temp and create collection:
foreach ($temp as $key => $entry) {
$object = new stdClass();
$object->id = $key;
$object->name = $entry['name'];
$object->count = $entry['count'];
$object->amount = $entry['amount'];
$collection->push($object);
}
return $collection;
}
}

View File

@ -51,37 +51,11 @@ interface AccountTaskerInterface
/**
* @param Collection $accounts
* @param Collection $excluded
* @param Carbon $start
* @param Carbon $end
*
* @see AccountTasker::financialReport()
*
* @return Collection
*
*/
public function expenseReport(Collection $accounts, Collection $excluded, Carbon $start, Carbon $end): Collection;
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return AccountCollection
*/
public function getAccountReport(Carbon $start, Carbon $end, Collection $accounts): AccountCollection;
/**
* @param Collection $accounts
* @param Collection $excluded
* @param Carbon $start
* @param Carbon $end
*
* @see AccountTasker::financialReport()
*
* @return Collection
*
*/
public function incomeReport(Collection $accounts, Collection $excluded, Carbon $start, Carbon $end): Collection;
public function getAccountReport(Collection $accounts, Carbon $start, Carbon $end): AccountCollection;
}

View File

@ -66,7 +66,7 @@ class BillRepository implements BillRepositoryInterface
*
* @return Bill
*/
public function find(int $billId) : Bill
public function find(int $billId): Bill
{
$bill = $this->user->bills()->find($billId);
if (is_null($bill)) {
@ -83,7 +83,7 @@ class BillRepository implements BillRepositoryInterface
*
* @return Bill
*/
public function findByName(string $name) : Bill
public function findByName(string $name): Bill
{
$bills = $this->user->bills()->get(['bills.*']);

View File

@ -40,7 +40,7 @@ interface BillRepositoryInterface
*
* @return Bill
*/
public function find(int $billId) : Bill;
public function find(int $billId): Bill;
/**
* Find a bill by name.
@ -49,7 +49,7 @@ interface BillRepositoryInterface
*
* @return Bill
*/
public function findByName(string $name) : Bill;
public function findByName(string $name): Bill;
/**
* @return Collection

View File

@ -212,10 +212,8 @@ class BudgetRepository implements BudgetRepositoryInterface
}
/**
* This method is being used to generate the budget overview in the year/multi-year report. More specifically, this
* method runs the query and returns the result that is used for this report.
*
* The query is used in both the year/multi-year budget overview AND in the accompanying chart.
* This method is being used to generate the budget overview in the year/multi-year report. Its used
* in both the year/multi-year budget overview AND in the accompanying chart.
*
* @param Collection $budgets
* @param Collection $accounts
@ -226,54 +224,31 @@ class BudgetRepository implements BudgetRepositoryInterface
*/
public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
$data = [];
// prep data array:
/** @var Budget $budget */
foreach ($budgets as $budget) {
$data[$budget->id] = [
'name' => $budget->name,
'sum' => '0',
'entries' => [],
];
}
// get all transactions:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setBudgets($budgets);
$transactions = $collector->getJournals();
// this is the date format we need:
// define period to group on:
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
// this is the set of transactions for this period
// in these budgets. Now they must be grouped (manually)
// id, period => amount
$data = [];
// loop transactions:
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$budgetId = max(intval($transaction->transaction_journal_budget_id), intval($transaction->transaction_budget_id));
$date = $transaction->date->format($carbonFormat);
if (!isset($data[$budgetId])) {
$data[$budgetId]['name'] = $this->getBudgetName($budgetId, $budgets);
$data[$budgetId]['sum'] = '0';
$data[$budgetId]['entries'] = [];
}
if (!isset($data[$budgetId]['entries'][$date])) {
$data[$budgetId]['entries'][$date] = '0';
}
$data[$budgetId]['entries'][$date] = bcadd($data[$budgetId]['entries'][$date], $transaction->transaction_amount);
}
// and now the same for stuff without a budget:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end);
$collector->setTypes([TransactionType::WITHDRAWAL]);
$collector->withoutBudget();
$transactions = $collector->getJournals();
$data[0]['entries'] = [];
$data[0]['name'] = strval(trans('firefly.no_budget'));
$data[0]['sum'] = '0';
foreach ($transactions as $transaction) {
$date = $transaction->date->format($carbonFormat);
if (!isset($data[0]['entries'][$date])) {
$data[0]['entries'][$date] = '0';
}
$data[0]['entries'][$date] = bcadd($data[0]['entries'][$date], $transaction->transaction_amount);
$budgetId = max(intval($transaction->transaction_journal_budget_id), intval($transaction->transaction_budget_id));
$date = $transaction->date->format($carbonFormat);
$data[$budgetId]['entries'][$date] = bcadd($data[$budgetId]['entries'][$date] ?? '0', $transaction->transaction_amount);
}
return $data;
@ -314,6 +289,40 @@ class BudgetRepository implements BudgetRepositoryInterface
return $set;
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getNoBudgetPeriodReport(Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setTypes([TransactionType::WITHDRAWAL]);
$collector->withoutBudget();
$transactions = $collector->getJournals();
$result = [
'entries' => [],
'name' => strval(trans('firefly.no_budget')),
'sum' => '0',
];
foreach ($transactions as $transaction) {
$date = $transaction->date->format($carbonFormat);
if (!isset($result['entries'][$date])) {
$result['entries'][$date] = '0';
}
$result['entries'][$date] = bcadd($result['entries'][$date], $transaction->transaction_amount);
}
return $result;
}
/**
* @param Collection $budgets
* @param Collection $accounts
@ -332,20 +341,23 @@ class BudgetRepository implements BudgetRepositoryInterface
Log::debug('spentInPeriod: and these accounts: ', $accountIds);
Log::debug(sprintf('spentInPeriod: Start date is "%s", end date is "%s"', $start->format('Y-m-d'), $end->format('Y-m-d')));
$fromJournalsQuery = TransactionJournal
::leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0);
}
)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->whereNull('transaction_journals.deleted_at')
->whereNull('transactions.deleted_at')
->where('transaction_journals.user_id', $this->user->id)
->where('transaction_types.type', 'Withdrawal');
$fromJournalsQuery = TransactionJournal::leftJoin(
'budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where(
'transactions.amount', '<', 0
);
}
)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->whereNull('transaction_journals.deleted_at')
->whereNull('transactions.deleted_at')
->where('transaction_journals.user_id', $this->user->id)
->where('transaction_types.type', 'Withdrawal');
// add budgets:
if ($budgets->count() > 0) {
@ -368,17 +380,16 @@ class BudgetRepository implements BudgetRepositoryInterface
* and budget_transaction.budget_id in (1,61)
* and transactions.account_id in (2)
*/
$fromTransactionsQuery = Transaction
::leftJoin('budget_transaction', 'budget_transaction.transaction_id', '=', 'transactions.id')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transactions.amount', '<', 0)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_journals.user_id', $this->user->id)
->where('transaction_types.type', 'Withdrawal');
$fromTransactionsQuery = Transaction::leftJoin('budget_transaction', 'budget_transaction.transaction_id', '=', 'transactions.id')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transactions.amount', '<', 0)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_journals.user_id', $this->user->id)
->where('transaction_types.type', 'Withdrawal');
// add budgets:
if ($budgets->count() > 0) {
@ -550,25 +561,4 @@ class BudgetRepository implements BudgetRepositoryInterface
return $limit;
}
/**
* @param int $budgetId
* @param Collection $budgets
*
* @return string
*/
private function getBudgetName(int $budgetId, Collection $budgets): string
{
$first = $budgets->filter(
function (Budget $budget) use ($budgetId) {
return $budgetId === $budget->id;
}
);
if (!is_null($first->first())) {
return $first->first()->name;
}
return '(unknown)';
}
}

View File

@ -111,6 +111,14 @@ interface BudgetRepositoryInterface
*/
public function getInactiveBudgets(): Collection;
/**
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getNoBudgetPeriodReport(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $budgets
* @param Collection $accounts
@ -119,7 +127,7 @@ interface BudgetRepositoryInterface
*
* @return string
*/
public function spentInPeriod(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end) : string;
public function spentInPeriod(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): string;
/**
* @param Collection $accounts
@ -143,7 +151,7 @@ interface BudgetRepositoryInterface
*
* @return Budget
*/
public function update(Budget $budget, array $data) : Budget;
public function update(Budget $budget, array $data): Budget;
/**
* @param Budget $budget
@ -154,6 +162,6 @@ interface BudgetRepositoryInterface
*
* @return BudgetLimit
*/
public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $range, int $amount) : BudgetLimit;
public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $range, int $amount): BudgetLimit;
}

View File

@ -15,12 +15,16 @@ namespace FireflyIII\Repositories\Category;
use Carbon\Carbon;
use DB;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\User;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Log;
use Navigation;
/**
* Class CategoryRepository
@ -221,6 +225,178 @@ class CategoryRepository implements CategoryRepositoryInterface
return $last;
}
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodExpenses(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
$data = [];
// prep data array:
/** @var Category $category */
foreach ($categories as $category) {
$data[$category->id] = [
'name' => $category->name,
'sum' => '0',
'entries' => [],
];
}
// get all transactions:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setCategories($categories)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->withOpposingAccount()
->enableInternalFilter();
$transactions = $collector->getJournals();
// loop transactions:
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
// if positive, skip:
if (bccomp($transaction->transaction_amount, '0') === 1) {
continue;
}
$categoryId = max(intval($transaction->transaction_journal_category_id), intval($transaction->transaction_category_id));
$date = $transaction->date->format($carbonFormat);
$data[$categoryId]['entries'][$date] = bcadd($data[$categoryId]['entries'][$date] ?? '0', $transaction->transaction_amount);
}
return $data;
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodExpensesNoCategory(Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->withOpposingAccount();
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])->enableInternalFilter();
$collector->withoutCategory();
$transactions = $collector->getJournals();
$result = [
'entries' => [],
'name' => strval(trans('firefly.no_category')),
'sum' => '0',
];
foreach ($transactions as $transaction) {
// if positive, skip:
if (bccomp($transaction->transaction_amount, '0') === 1) {
continue;
}
$date = $transaction->date->format($carbonFormat);
if (!isset($result['entries'][$date])) {
$result['entries'][$date] = '0';
}
$result['entries'][$date] = bcadd($result['entries'][$date], $transaction->transaction_amount);
}
return $result;
}
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodIncome(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
$data = [];
// prep data array:
/** @var Category $category */
foreach ($categories as $category) {
$data[$category->id] = [
'name' => $category->name,
'sum' => '0',
'entries' => [],
];
}
// get all transactions:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setCategories($categories)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->withOpposingAccount()
->enableInternalFilter();
$transactions = $collector->getJournals();
// loop transactions:
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
// if negative, skip:
if (bccomp($transaction->transaction_amount, '0') === -1) {
continue;
}
$categoryId = max(intval($transaction->transaction_journal_category_id), intval($transaction->transaction_category_id));
$date = $transaction->date->format($carbonFormat);
$data[$categoryId]['entries'][$date] = bcadd($data[$categoryId]['entries'][$date] ?? '0', $transaction->transaction_amount);
}
return $data;
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodIncomeNoCategory(Collection $accounts, Carbon $start, Carbon $end): array
{
Log::debug('Now in periodIncomeNoCategory()');
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->withOpposingAccount();
$collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])->enableInternalFilter();
$collector->withoutCategory();
$transactions = $collector->getJournals();
$result = [
'entries' => [],
'name' => strval(trans('firefly.no_category')),
'sum' => '0',
];
Log::debug('Looping transactions..');
foreach ($transactions as $transaction) {
// if negative, skip:
if (bccomp($transaction->transaction_amount, '0') === -1) {
continue;
}
$date = $transaction->date->format($carbonFormat);
if (!isset($result['entries'][$date])) {
$result['entries'][$date] = '0';
}
$result['entries'][$date] = bcadd($result['entries'][$date], $transaction->transaction_amount);
}
Log::debug('Done looping transactions..');
Log::debug('Finished periodIncomeNoCategory()');
return $result;
}
/**
* @param Collection $categories
* @param Collection $accounts
@ -233,6 +409,7 @@ class CategoryRepository implements CategoryRepositoryInterface
{
$sum = $this->sumInPeriod($categories, $accounts, TransactionType::WITHDRAWAL, $start, $end);
$sum = bcmul($sum, '-1');
return $sum;
}
@ -404,5 +581,4 @@ class CategoryRepository implements CategoryRepositoryInterface
return $sum;
}
}

View File

@ -24,7 +24,6 @@ use Illuminate\Support\Collection;
*/
interface CategoryRepositoryInterface
{
/**
* @param Category $category
*
@ -49,7 +48,7 @@ interface CategoryRepositoryInterface
*
* @return string
*/
public function earnedInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end) :string;
public function earnedInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end): string;
/**
* Find a category
@ -58,7 +57,7 @@ interface CategoryRepositoryInterface
*
* @return Category
*/
public function find(int $categoryId) : Category;
public function find(int $categoryId): Category;
/**
* Find a category
@ -67,7 +66,7 @@ interface CategoryRepositoryInterface
*
* @return Category
*/
public function findByName(string $name) : Category;
public function findByName(string $name): Category;
/**
* @param Category $category
@ -93,6 +92,44 @@ interface CategoryRepositoryInterface
*/
public function lastUseDate(Category $category, Collection $accounts): Carbon;
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodExpenses(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodExpensesNoCategory(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodIncome(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodIncomeNoCategory(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $categories
* @param Collection $accounts
@ -110,7 +147,7 @@ interface CategoryRepositoryInterface
*
* @return string
*/
public function spentInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end) : string;
public function spentInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end): string;
/**
* @param array $data

View File

@ -43,7 +43,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
*
* @return TransactionCurrency
*/
public function find(int $currencyId) : TransactionCurrency
public function find(int $currencyId): TransactionCurrency
{
$currency = TransactionCurrency::find($currencyId);
if (is_null($currency)) {
@ -61,7 +61,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
*
* @return TransactionCurrency
*/
public function findByCode(string $currencyCode) : TransactionCurrency
public function findByCode(string $currencyCode): TransactionCurrency
{
$currency = TransactionCurrency::whereCode($currencyCode)->first();
if (is_null($currency)) {
@ -78,7 +78,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
*
* @return TransactionCurrency
*/
public function findByName(string $currencyName) : TransactionCurrency
public function findByName(string $currencyName): TransactionCurrency
{
$preferred = TransactionCurrency::whereName($currencyName)->first();
if (is_null($preferred)) {
@ -95,7 +95,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
*
* @return TransactionCurrency
*/
public function findBySymbol(string $currencySymbol) : TransactionCurrency
public function findBySymbol(string $currencySymbol): TransactionCurrency
{
$currency = TransactionCurrency::whereSymbol($currencySymbol)->first();
if (is_null($currency)) {

View File

@ -39,7 +39,7 @@ interface CurrencyRepositoryInterface
*
* @return TransactionCurrency
*/
public function find(int $currencyId) : TransactionCurrency;
public function find(int $currencyId): TransactionCurrency;
/**
* Find by currency code
@ -48,7 +48,7 @@ interface CurrencyRepositoryInterface
*
* @return TransactionCurrency
*/
public function findByCode(string $currencyCode) : TransactionCurrency;
public function findByCode(string $currencyCode): TransactionCurrency;
/**
* Find by currency name
@ -57,7 +57,7 @@ interface CurrencyRepositoryInterface
*
* @return TransactionCurrency
*/
public function findByName(string $currencyName) : TransactionCurrency;
public function findByName(string $currencyName): TransactionCurrency;
/**
* Find by currency symbol
@ -66,7 +66,7 @@ interface CurrencyRepositoryInterface
*
* @return TransactionCurrency
*/
public function findBySymbol(string $currencySymbol) : TransactionCurrency;
public function findBySymbol(string $currencySymbol): TransactionCurrency;
/**
* @return Collection

View File

@ -105,7 +105,7 @@ class JournalRepository implements JournalRepositoryInterface
*
* @return TransactionJournal
*/
public function find(int $journalId) : TransactionJournal
public function find(int $journalId): TransactionJournal
{
$journal = $this->user->transactionJournals()->where('id', $journalId)->first();
if (is_null($journal)) {

View File

@ -52,7 +52,7 @@ interface JournalRepositoryInterface
*
* @return TransactionJournal
*/
public function find(int $journalId) : TransactionJournal;
public function find(int $journalId): TransactionJournal;
/**
* Get users very first transaction journal

View File

@ -171,39 +171,37 @@ class JournalTasker implements JournalTaskerInterface
$identifier = intval($transaction->identifier);
// go!
$sum
= Transaction
::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('account_id', $transaction->account_id)
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transactions.id', '!=', $transactionId)
->where(
function (Builder $q1) use ($date, $order, $journalId, $identifier) {
$q1->where('transaction_journals.date', '<', $date); // date
$q1->orWhere(
function (Builder $q2) use ($date, $order) { // function 1
$q2->where('transaction_journals.date', $date);
$q2->where('transaction_journals.order', '>', $order);
}
);
$q1->orWhere(
function (Builder $q3) use ($date, $order, $journalId) { // function 2
$q3->where('transaction_journals.date', $date);
$q3->where('transaction_journals.order', $order);
$q3->where('transaction_journals.id', '<', $journalId);
}
);
$q1->orWhere(
function (Builder $q4) use ($date, $order, $journalId, $identifier) { // function 3
$q4->where('transaction_journals.date', $date);
$q4->where('transaction_journals.order', $order);
$q4->where('transaction_journals.id', $journalId);
$q4->where('transactions.identifier', '>', $identifier);
}
);
}
)->sum('transactions.amount');
$sum = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('account_id', $transaction->account_id)
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transactions.id', '!=', $transactionId)
->where(
function (Builder $q1) use ($date, $order, $journalId, $identifier) {
$q1->where('transaction_journals.date', '<', $date); // date
$q1->orWhere(
function (Builder $q2) use ($date, $order) { // function 1
$q2->where('transaction_journals.date', $date);
$q2->where('transaction_journals.order', '>', $order);
}
);
$q1->orWhere(
function (Builder $q3) use ($date, $order, $journalId) { // function 2
$q3->where('transaction_journals.date', $date);
$q3->where('transaction_journals.order', $order);
$q3->where('transaction_journals.id', '<', $journalId);
}
);
$q1->orWhere(
function (Builder $q4) use ($date, $order, $journalId, $identifier) { // function 3
$q4->where('transaction_journals.date', $date);
$q4->where('transaction_journals.order', $order);
$q4->where('transaction_journals.id', $journalId);
$q4->where('transactions.identifier', '>', $identifier);
}
);
}
)->sum('transactions.amount');
return strval($sum);
}

View File

@ -117,7 +117,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
*
* @return Collection
*/
public function getPiggyBanksWithAmount() : Collection
public function getPiggyBanksWithAmount(): Collection
{
$set = $this->getPiggyBanks();
foreach ($set as $piggy) {

View File

@ -58,7 +58,7 @@ interface PiggyBankRepositoryInterface
*
* @return Collection
*/
public function getEvents(PiggyBank $piggyBank) : Collection;
public function getEvents(PiggyBank $piggyBank): Collection;
/**
* Highest order of all piggy banks.
@ -72,14 +72,14 @@ interface PiggyBankRepositoryInterface
*
* @return Collection
*/
public function getPiggyBanks() : Collection;
public function getPiggyBanks(): Collection;
/**
* Also add amount in name.
*
* @return Collection
*/
public function getPiggyBanksWithAmount() : Collection;
public function getPiggyBanksWithAmount(): Collection;
/**
* Set all piggy banks to order 0.

View File

@ -93,7 +93,7 @@ class TagRepository implements TagRepositoryInterface
*
* @return Tag
*/
public function find(int $tagId) : Tag
public function find(int $tagId): Tag
{
$tag = $this->user->tags()->find($tagId);
if (is_null($tag)) {
@ -108,7 +108,7 @@ class TagRepository implements TagRepositoryInterface
*
* @return Tag
*/
public function findByTag(string $tag) : Tag
public function findByTag(string $tag): Tag
{
$tags = $this->user->tags()->get();
/** @var Tag $tag */

View File

@ -49,14 +49,14 @@ interface TagRepositoryInterface
*
* @return Tag
*/
public function find(int $tagId) : Tag;
public function find(int $tagId): Tag;
/**
* @param string $tag
*
* @return Tag
*/
public function findByTag(string $tag) : Tag;
public function findByTag(string $tag): Tag;
/**
* This method returns all the user's tags.

View File

@ -113,12 +113,11 @@ class UserRepository implements UserRepositoryInterface
$return['bills'] = $user->bills()->count();
$return['categories'] = $user->categories()->count();
$return['budgets'] = $user->budgets()->count();
$return['budgets_with_limits'] = BudgetLimit
::distinct()
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->where('amount', '>', 0)
->whereNull('budgets.deleted_at')
->where('budgets.user_id', $user->id)->get(['budget_limits.budget_id'])->count();
$return['budgets_with_limits'] = BudgetLimit::distinct()
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->where('amount', '>', 0)
->whereNull('budgets.deleted_at')
->where('budgets.user_id', $user->id)->get(['budget_limits.budget_id'])->count();
$return['export_jobs'] = $user->exportJobs()->count();
$return['export_jobs_success'] = $user->exportJobs()->where('status', 'export_downloaded')->count();
$return['import_jobs'] = $user->exportJobs()->count();

View File

@ -40,20 +40,7 @@ class ExpandedForm
*/
public function amount(string $name, $value = null, array $options = []): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$options['min'] = '0.01';
$defaultCurrency = isset($options['currency']) ? $options['currency'] : Amt::getDefaultCurrency();
$currencies = Amt::getAllCurrencies();
unset($options['currency']);
unset($options['placeholder']);
$html = view('form.amount', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
return $html;
return $this->currencyField($name, 'amount', $value, $options);
}
/**
@ -65,20 +52,7 @@ class ExpandedForm
*/
public function amountSmall(string $name, $value = null, array $options = []): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$options['min'] = '0.01';
$defaultCurrency = isset($options['currency']) ? $options['currency'] : Amt::getDefaultCurrency();
$currencies = Amt::getAllCurrencies();
unset($options['currency']);
unset($options['placeholder']);
$html = view('form.amount-small', compact('defaultCurrency', 'currencies', 'classes', 'name', 'value', 'options'))->render();
return $html;
return $this->currencyField($name, 'amount-small', $value, $options);
}
/**
@ -90,18 +64,7 @@ class ExpandedForm
*/
public function balance(string $name, $value = null, array $options = []): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = round($this->fillFieldValue($name, $value), 2);
$options['step'] = 'any';
$defaultCurrency = isset($options['currency']) ? $options['currency'] : Amt::getDefaultCurrency();
$currencies = Amt::getAllCurrencies();
unset($options['currency']);
unset($options['placeholder']);
$html = view('form.balance', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
return $html;
return $this->currencyField($name, 'balance', $value, $options);
}
/**
@ -320,7 +283,6 @@ class ExpandedForm
return $html;
}
/**
* @param $name
* @param array $list
@ -500,4 +462,29 @@ class ExpandedForm
return strval(trans('form.' . $name));
}
/**
* @param string $name
* @param string $view
* @param null $value
* @param array $options
*
* @return string
*/
private function currencyField(string $name, string $view, $value = null, array $options = []): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$options['min'] = '0.01';
$defaultCurrency = isset($options['currency']) ? $options['currency'] : Amt::getDefaultCurrency();
$currencies = Amt::getAllCurrencies();
unset($options['currency']);
unset($options['placeholder']);
$html = view('form.' . $view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
return $html;
}
}

View File

@ -246,8 +246,8 @@ class Navigation
* If the date difference between start and end is less than a month, method returns "Y-m-d". If the difference is less than a year,
* method returns "Y-m". If the date difference is larger, method returns "Y".
*
* @param Carbon $start
* @param Carbon $end
* @param \Carbon\Carbon $start
* @param \Carbon\Carbon $end
*
* @return string
*/
@ -270,8 +270,8 @@ class Navigation
* If the date difference between start and end is less than a month, method returns "1D". If the difference is less than a year,
* method returns "1M". If the date difference is larger, method returns "1Y".
*
* @param Carbon $start
* @param Carbon $end
* @param \Carbon\Carbon $start
* @param \Carbon\Carbon $end
*
* @return string
*/

View File

@ -109,8 +109,7 @@ class Transaction extends Twig_Extension
'optionalJournalAmount', function (int $journalId, string $transactionAmount, string $code, string $type): string {
$amount = strval(
TransactionModel
::where('transaction_journal_id', $journalId)
TransactionModel::where('transaction_journal_id', $journalId)
->whereNull('deleted_at')
->where('amount', '<', 0)
->sum('amount')
@ -193,8 +192,7 @@ class Transaction extends Twig_Extension
// name is present in object, use that one:
if (bccomp($transaction->transaction_amount, '0') === -1 && !is_null($transaction->opposing_account_id)) {
$name = intval($transaction->opposing_account_encrypted) === 1 ? Crypt::decrypt($transaction->opposing_account_name)
: $transaction->opposing_account_name;
$name = $transaction->opposing_account_name;
$id = intval($transaction->opposing_account_id);
$type = intval($transaction->opposing_account_type);
}
@ -204,8 +202,7 @@ class Transaction extends Twig_Extension
// if the amount is negative, find the opposing account and use that one:
$journalId = $transaction->journal_id;
/** @var TransactionModel $other */
$other = TransactionModel
::where('transaction_journal_id', $journalId)->where('transactions.id', '!=', $transaction->id)
$other = TransactionModel::where('transaction_journal_id', $journalId)->where('transactions.id', '!=', $transaction->id)
->where('amount', '=', bcmul($transaction->transaction_amount, '-1'))->where('identifier', $transaction->identifier)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
@ -278,8 +275,7 @@ class Transaction extends Twig_Extension
if (bccomp($transaction->transaction_amount, '0') === 1 && is_null($transaction->opposing_account_id)) {
$journalId = $transaction->journal_id;
/** @var TransactionModel $other */
$other = TransactionModel
::where('transaction_journal_id', $journalId)->where('transactions.id', '!=', $transaction->id)
$other = TransactionModel::where('transaction_journal_id', $journalId)->where('transactions.id', '!=', $transaction->id)
->where('amount', '=', bcmul($transaction->transaction_amount, '-1'))->where('identifier', $transaction->identifier)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')

View File

@ -57,8 +57,6 @@ class FireflyValidator extends Validator
* @param $value
*
* @return bool
* @internal param $parameters
*
*
*/
public function validate2faCode($attribute, $value): bool
@ -95,6 +93,27 @@ class FireflyValidator extends Validator
}
/**
* @param $attribute
* @param $value
*
* @return bool
*
*/
public function validateBic($attribute, $value): bool
{
$regex = '/^[a-z]{6}[0-9a-z]{2}([0-9a-z]{3})?\z/i';
$result = preg_match($regex, $value);
if ($result === false) {
return false;
}
if ($result === 0) {
return false;
}
return true;
}
/**
* @param $attribute
* @param $value
@ -455,7 +474,6 @@ class FireflyValidator extends Validator
* @param $value
*
* @return bool
* @internal param $parameters
*
*/
private function validateByAccountId($value): bool

106
composer.lock generated
View File

@ -105,20 +105,20 @@
},
{
"name": "classpreloader/classpreloader",
"version": "3.0.0",
"version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/ClassPreloader/ClassPreloader.git",
"reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a"
"reference": "bc7206aa892b5a33f4680421b69b191efd32b096"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/9b10b913c2bdf90c3d2e0d726b454fb7f77c552a",
"reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a",
"url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/bc7206aa892b5a33f4680421b69b191efd32b096",
"reference": "bc7206aa892b5a33f4680421b69b191efd32b096",
"shasum": ""
},
"require": {
"nikic/php-parser": "^1.0|^2.0",
"nikic/php-parser": "^1.0|^2.0|^3.0",
"php": ">=5.5.9"
},
"require-dev": {
@ -127,7 +127,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
"dev-master": "3.1-dev"
}
},
"autoload": {
@ -155,7 +155,7 @@
"class",
"preload"
],
"time": "2015-11-09 22:51:51"
"time": "2016-09-16 12:50:15"
},
{
"name": "davejamesmiller/laravel-breadcrumbs",
@ -445,16 +445,16 @@
},
{
"name": "doctrine/common",
"version": "v2.6.1",
"version": "v2.6.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/common.git",
"reference": "a579557bc689580c19fee4e27487a67fe60defc0"
"reference": "7bce00698899aa2c06fe7365c76e4d78ddb15fa3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0",
"reference": "a579557bc689580c19fee4e27487a67fe60defc0",
"url": "https://api.github.com/repos/doctrine/common/zipball/7bce00698899aa2c06fe7365c76e4d78ddb15fa3",
"reference": "7bce00698899aa2c06fe7365c76e4d78ddb15fa3",
"shasum": ""
},
"require": {
@ -514,7 +514,7 @@
"persistence",
"spl"
],
"time": "2015-12-25 13:18:31"
"time": "2016-11-30 16:50:46"
},
{
"name": "doctrine/dbal",
@ -797,20 +797,20 @@
},
{
"name": "jeremeamia/SuperClosure",
"version": "2.2.0",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/jeremeamia/super_closure.git",
"reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938"
"reference": "443c3df3207f176a1b41576ee2a66968a507b3db"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/29a88be2a4846d27c1613aed0c9071dfad7b5938",
"reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938",
"url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/443c3df3207f176a1b41576ee2a66968a507b3db",
"reference": "443c3df3207f176a1b41576ee2a66968a507b3db",
"shasum": ""
},
"require": {
"nikic/php-parser": "^1.2|^2.0",
"nikic/php-parser": "^1.2|^2.0|^3.0",
"php": ">=5.4",
"symfony/polyfill-php56": "^1.0"
},
@ -820,7 +820,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
"dev-master": "2.3-dev"
}
},
"autoload": {
@ -851,7 +851,7 @@
"serialize",
"tokenizer"
],
"time": "2015-12-05 17:17:57"
"time": "2016-12-07 09:37:55"
},
{
"name": "laravel/framework",
@ -2060,16 +2060,16 @@
},
{
"name": "symfony/event-dispatcher",
"version": "v3.1.7",
"version": "v3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "28b0832b2553ffb80cabef6a7a812ff1e670c0bc"
"reference": "e8f47a327c2f0fd5aa04fa60af2b693006ed7283"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/28b0832b2553ffb80cabef6a7a812ff1e670c0bc",
"reference": "28b0832b2553ffb80cabef6a7a812ff1e670c0bc",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/e8f47a327c2f0fd5aa04fa60af2b693006ed7283",
"reference": "e8f47a327c2f0fd5aa04fa60af2b693006ed7283",
"shasum": ""
},
"require": {
@ -2089,7 +2089,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
"dev-master": "3.2-dev"
}
},
"autoload": {
@ -2116,7 +2116,7 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2016-10-13 06:28:43"
"time": "2016-10-13 06:29:04"
},
{
"name": "symfony/finder",
@ -3578,16 +3578,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "4.0.2",
"version": "4.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "6cba06ff75a1a63a71033e1a01b89056f3af1e8d"
"reference": "903fd6318d0a90b4770a009ff73e4a4e9c437929"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6cba06ff75a1a63a71033e1a01b89056f3af1e8d",
"reference": "6cba06ff75a1a63a71033e1a01b89056f3af1e8d",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/903fd6318d0a90b4770a009ff73e4a4e9c437929",
"reference": "903fd6318d0a90b4770a009ff73e4a4e9c437929",
"shasum": ""
},
"require": {
@ -3637,7 +3637,7 @@
"testing",
"xunit"
],
"time": "2016-11-01 05:06:24"
"time": "2016-11-28 16:00:31"
},
{
"name": "phpunit/php-file-iterator",
@ -3822,16 +3822,16 @@
},
{
"name": "phpunit/phpunit",
"version": "5.6.5",
"version": "5.7.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "875145fabfa261fa9c1aea663dd29ddce92dca8f"
"reference": "336aff0ac52e306c98e7455bc3e8d7b0bf777a5e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/875145fabfa261fa9c1aea663dd29ddce92dca8f",
"reference": "875145fabfa261fa9c1aea663dd29ddce92dca8f",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/336aff0ac52e306c98e7455bc3e8d7b0bf777a5e",
"reference": "336aff0ac52e306c98e7455bc3e8d7b0bf777a5e",
"shasum": ""
},
"require": {
@ -3843,14 +3843,14 @@
"myclabs/deep-copy": "~1.3",
"php": "^5.6 || ^7.0",
"phpspec/prophecy": "^1.3.1",
"phpunit/php-code-coverage": "^4.0.1",
"phpunit/php-code-coverage": "^4.0.3",
"phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": "^1.0.6",
"phpunit/phpunit-mock-objects": "^3.2",
"sebastian/comparator": "~1.2.2",
"sebastian/diff": "~1.2",
"sebastian/environment": "^1.3 || ^2.0",
"sebastian/environment": "^1.3.4 || ^2.0",
"sebastian/exporter": "~2.0",
"sebastian/global-state": "~1.0",
"sebastian/object-enumerator": "~2.0",
@ -3874,7 +3874,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6.x-dev"
"dev-master": "5.7.x-dev"
}
},
"autoload": {
@ -3900,7 +3900,7 @@
"testing",
"xunit"
],
"time": "2016-11-21 15:23:34"
"time": "2016-12-03 08:33:00"
},
{
"name": "phpunit/phpunit-mock-objects",
@ -4476,16 +4476,16 @@
},
{
"name": "symfony/class-loader",
"version": "v3.1.7",
"version": "v3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/class-loader.git",
"reference": "61de6c27f9d4efe988ea8274f19c2d4e331dd4e4"
"reference": "87cd4e69435d98de01d0162c5f9c0ac017075c63"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/class-loader/zipball/61de6c27f9d4efe988ea8274f19c2d4e331dd4e4",
"reference": "61de6c27f9d4efe988ea8274f19c2d4e331dd4e4",
"url": "https://api.github.com/repos/symfony/class-loader/zipball/87cd4e69435d98de01d0162c5f9c0ac017075c63",
"reference": "87cd4e69435d98de01d0162c5f9c0ac017075c63",
"shasum": ""
},
"require": {
@ -4501,7 +4501,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
"dev-master": "3.2-dev"
}
},
"autoload": {
@ -4528,7 +4528,7 @@
],
"description": "Symfony ClassLoader Component",
"homepage": "https://symfony.com",
"time": "2016-11-15 12:07:16"
"time": "2016-11-29 08:26:13"
},
{
"name": "symfony/css-selector",
@ -4641,25 +4641,31 @@
},
{
"name": "symfony/yaml",
"version": "v3.1.7",
"version": "v3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "9da375317228e54f4ea1b013b30fa47417e84943"
"reference": "f2300ba8fbb002c028710b92e1906e7457410693"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/9da375317228e54f4ea1b013b30fa47417e84943",
"reference": "9da375317228e54f4ea1b013b30fa47417e84943",
"url": "https://api.github.com/repos/symfony/yaml/zipball/f2300ba8fbb002c028710b92e1906e7457410693",
"reference": "f2300ba8fbb002c028710b92e1906e7457410693",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"require-dev": {
"symfony/console": "~2.8|~3.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
"dev-master": "3.2-dev"
}
},
"autoload": {
@ -4686,7 +4692,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2016-11-18 21:05:29"
"time": "2016-11-18 21:17:59"
},
{
"name": "webmozart/assert",

View File

@ -24,7 +24,7 @@ return [
'must_confirm_account' => false,
],
'chart' => 'chartjs',
'version' => '4.2.0',
'version' => '4.2.1',
'csv_import_enabled' => true,
'maxUploadSize' => 5242880,
'allowedMimes' => ['image/png', 'image/jpeg', 'application/pdf'],

View File

@ -87,7 +87,7 @@ class CreateMainTables extends Migration
$table->integer('user_id', false, true);
$table->integer('account_type_id', false, true);
$table->string('name', 1024);
$table->decimal('virtual_balance', 10, 4)->nullable();
$table->decimal('virtual_balance', 14, 4)->nullable();
$table->string('iban', 255)->nullable();
$table->boolean('active')->default(1);
@ -165,8 +165,8 @@ class CreateMainTables extends Migration
$table->integer('user_id', false, true);
$table->string('name', 1024);
$table->string('match', 1024);
$table->decimal('amount_min', 10, 4);
$table->decimal('amount_max', 10, 4);
$table->decimal('amount_min', 14, 4);
$table->decimal('amount_max', 14, 4);
$table->date('date');
$table->string('repeat_freq', 30);
$table->smallInteger('skip', false, true)->default(0);
@ -215,7 +215,7 @@ class CreateMainTables extends Migration
$table->timestamps();
$table->integer('budget_id', false, true);
$table->date('startdate');
$table->decimal('amount', 10, 4);
$table->decimal('amount', 14, 4);
$table->string('repeat_freq', 30);
$table->boolean('repeats')->default(0);
@ -233,7 +233,7 @@ class CreateMainTables extends Migration
$table->integer('budget_limit_id', false, true);
$table->date('startdate');
$table->date('enddate');
$table->decimal('amount', 10, 4);
$table->decimal('amount', 14, 4);
// link budget limit id to budget_limitss table
$table->foreign('budget_limit_id')->references('id')->on('budget_limits')->onDelete('cascade');
@ -313,7 +313,7 @@ class CreateMainTables extends Migration
$table->softDeletes();
$table->integer('account_id', false, true);
$table->string('name', 1024);
$table->decimal('targetamount', 10, 4);
$table->decimal('targetamount', 14, 4);
$table->date('startdate')->nullable();
$table->date('targetdate')->nullable();
$table->integer('order', false, true)->default(0);
@ -334,7 +334,7 @@ class CreateMainTables extends Migration
$table->integer('piggy_bank_id', false, true);
$table->date('startdate')->nullable();
$table->date('targetdate')->nullable();
$table->decimal('currentamount', 10, 4);
$table->decimal('currentamount', 14, 4);
$table->foreign('piggy_bank_id')->references('id')->on('piggy_banks')->onDelete('cascade');
@ -606,7 +606,7 @@ class CreateMainTables extends Migration
$table->integer('piggy_bank_id', false, true);
$table->integer('transaction_journal_id', false, true)->nullable();
$table->date('date');
$table->decimal('amount', 10, 4);
$table->decimal('amount', 14, 4);
$table->foreign('piggy_bank_id')->references('id')->on('piggy_banks')->onDelete('cascade');
$table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('set null');
@ -623,7 +623,7 @@ class CreateMainTables extends Migration
$table->integer('account_id', false, true);
$table->integer('transaction_journal_id', false, true);
$table->string('description', 1024)->nullable();
$table->decimal('amount', 10, 4);
$table->decimal('amount', 14, 4);
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade');

View File

@ -1,4 +1,13 @@
<?php
/**
* 2016_10_09_150037_expand_transactions_table.php
* Copyright (C) 2016 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.
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

View File

@ -1,4 +1,13 @@
<?php
/**
* 2016_10_22_075804_changes_for_v410.php
* Copyright (C) 2016 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.
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

View File

@ -1,4 +1,13 @@
<?php
/**
* 2016_11_24_210552_changes_for_v420.php
* Copyright (C) 2016 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.
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

View File

@ -28,6 +28,7 @@ class TransactionCurrencySeeder extends Seeder
TransactionCurrency::create(['code' => 'HUF', 'name' => 'Hungarian forint', 'symbol' => 'Ft']);
TransactionCurrency::create(['code' => 'BRL', 'name' => 'Real', 'symbol' => 'R$']);
TransactionCurrency::create(['code' => 'GBP', 'name' => 'British Pound', 'symbol' => '£']);
TransactionCurrency::create(['code' => 'IDR', 'name' => 'Indonesian rupiah', 'symbol' => 'Rp']);
}
}

View File

@ -6,9 +6,6 @@
* of the MIT license. See the LICENSE file for details.
*/
/* global $, lineChart, dateString, accountID, token, incomeByCategoryUri, expenseByCategoryUri, expenseByBudgetUri */
// Return a helper with preserved width of cells
var fixHelper = function (e, tr) {
"use strict";
@ -24,11 +21,11 @@ var fixHelper = function (e, tr) {
$(function () {
"use strict";
lineChart('chart/account/' + accountID + '/' + dateString, 'period-specific-account');
lineChart(periodUri, 'period-specific-account');
pieChart(incomeByCategoryUri, 'account-cat-in');
pieChart(expenseByCategoryUri, 'account-cat-out');
pieChart(expenseByBudgetUri, 'account-budget-out');
pieChart(incomeCategoryUri, 'account-cat-in');
pieChart(expenseCategoryUri, 'account-cat-out');
pieChart(expenseBudgetUri, 'account-budget-out');
// sortable!

View File

@ -15,10 +15,10 @@ var fixHelper = function (e, tr) {
$(function () {
"use strict";
lineChart('chart/account/' + accountID, 'overview-chart');
pieChart(incomeByCategoryUri, 'account-cat-in');
pieChart(expenseByCategoryUri, 'account-cat-out');
pieChart(expenseByBudgetUri, 'account-budget-out');
lineChart(singleUri, 'overview-chart');
pieChart(incomeCategoryUri, 'account-cat-in');
pieChart(expenseCategoryUri, 'account-cat-out');
pieChart(expenseBudgetUri, 'account-budget-out');
// sortable!

View File

@ -2,8 +2,6 @@
$(function () {
"use strict";
if (typeof(columnChart) === 'function' && typeof(billID) !== 'undefined') {
columnChart('chart/bill/' + billID, 'bill-overview');
}
columnChart(billUri, 'bill-overview');
}
);

View File

@ -1,117 +1,6 @@
/* globals $, budgeted:true, currencySymbol, budgetIncomeTotal, columnChart, budgetedMuch, budgetedPercentage, token, budgetID, repetitionID, spent, lineChart */
function drawSpentBar() {
"use strict";
if ($('.spentBar').length > 0) {
var overspent = spent > budgeted;
var pct;
if (overspent) {
// draw overspent bar
pct = (budgeted / spent) * 100;
$('.spentBar .progress-bar-warning').css('width', pct + '%');
$('.spentBar .progress-bar-danger').css('width', (100 - pct) + '%');
} else {
// draw normal bar:
pct = (spent / budgeted) * 100;
$('.spentBar .progress-bar-info').css('width', pct + '%');
}
}
}
function drawBudgetedBar() {
"use strict";
if ($('.budgetedBar').length > 0) {
var budgetedMuch = budgeted > budgetIncomeTotal;
// recalculate percentage:
var pct;
if (budgetedMuch) {
// budgeted too much.
pct = (budgetIncomeTotal / budgeted) * 100;
$('.budgetedBar .progress-bar-warning').css('width', pct + '%');
$('.budgetedBar .progress-bar-danger').css('width', (100 - pct) + '%');
$('.budgetedBar .progress-bar-info').css('width', 0);
} else {
pct = (budgeted / budgetIncomeTotal) * 100;
$('.budgetedBar .progress-bar-warning').css('width', 0);
$('.budgetedBar .progress-bar-danger').css('width', 0);
$('.budgetedBar .progress-bar-info').css('width', pct + '%');
}
$('#budgetedAmount').html(currencySymbol + ' ' + budgeted.toFixed(2));
}
}
function updateBudgetedAmounts(e) {
"use strict";
var target = $(e.target);
var id = target.data('id');
var value = target.val();
var original = target.data('original');
var difference = value - original;
if (difference !== 0) {
// add difference to 'budgeted' var
budgeted = budgeted + difference;
// update original:
target.data('original', value);
// run drawBudgetedBar() again:
drawBudgetedBar();
// send a post to Firefly to update the amount:
$.post('budgets/amount/' + id, {amount: value, _token: token}).done(function (data) {
// update the link if relevant:
if (data.repetition > 0) {
$('.budget-link[data-id="' + id + '"]').attr('href', 'budgets/show/' + id + '/' + data.repetition);
} else {
$('.budget-link[data-id="' + id + '"]').attr('href', 'budgets/show/' + id);
}
});
}
console.log('Budget id is ' + id);
console.log('Difference = ' + (value - original ));
}
$(function () {
"use strict";
$('.updateIncome').on('click', updateIncome);
/*
On start, fill the "spent"-bar using the content from the page.
*/
drawSpentBar();
drawBudgetedBar();
/*
When the input changes, update the percentages for the budgeted bar:
*/
$('input[type="number"]').on('input', updateBudgetedAmounts);
/*
Draw the charts, if necessary:
*/
if (typeof budgetID !== 'undefined' && typeof repetitionID === 'undefined') {
columnChart('chart/budget/' + budgetID, 'budgetOverview');
}
if (typeof budgetID !== 'undefined' && typeof repetitionID !== 'undefined') {
lineChart('chart/budget/' + budgetID + '/' + repetitionID, 'budgetOverview');
}
columnChart(budgetChartUri, 'budgetOverview');
});
function updateIncome() {
"use strict";
$('#defaultModal').empty().load('budgets/income', function () {
$('#defaultModal').modal('show');
});
return false;
}

View File

@ -1,19 +1,4 @@
/* globals $, categoryID, columnChart, categoryDate */
$(function () {
"use strict";
if (typeof categoryID !== 'undefined') {
// more splits:
if ($('#all').length > 0) {
columnChart('chart/category/' + categoryID + '/all', 'all');
}
if ($('#period').length > 0) {
columnChart('chart/category/' + categoryID + '/period', 'period');
}
}
if (typeof categoryID !== 'undefined' && typeof categoryDate !== 'undefined') {
columnChart('chart/category/' + categoryID + '/period/' + categoryDate, 'period-specific-period');
}
});

View File

@ -0,0 +1,4 @@
$(function () {
"use strict";
columnChart(specific, 'period-specific-period');
});

View File

@ -1,19 +1,5 @@
/* globals $, categoryID, columnChart, categoryDate */
$(function () {
"use strict";
if (typeof categoryID !== 'undefined') {
// more splits:
if ($('#all').length > 0) {
columnChart('chart/category/' + categoryID + '/all', 'all');
}
if ($('#period').length > 0) {
columnChart('chart/category/' + categoryID + '/period', 'period');
}
}
if (typeof categoryID !== 'undefined' && typeof categoryDate !== 'undefined') {
columnChart('chart/category/' + categoryID + '/period/' + categoryDate, 'period-specific-period');
}
columnChart(all, 'all');
columnChart(current, 'period');
});

View File

@ -1,19 +0,0 @@
/* globals $, categoryID, columnChart, categoryDate */
$(function () {
"use strict";
if (typeof categoryID !== 'undefined') {
// more splits:
if ($('#all').length > 0) {
columnChart('chart/category/' + categoryID + '/all', 'all');
}
if ($('#period').length > 0) {
columnChart('chart/category/' + categoryID + '/period', 'period');
}
}
if (typeof categoryID !== 'undefined' && typeof categoryDate !== undefined) {
columnChart('chart/category/' + categoryID + '/period/' + categoryDate, 'period-specific-period');
}
});

View File

@ -32,14 +32,14 @@ function endTheTour() {
function drawChart() {
"use strict";
lineChart('chart/account/frontpage', 'accounts-chart');
lineChart(accountFrontpageUri, 'accounts-chart');
if (billCount > 0) {
pieChart('chart/bill/frontpage', 'bills-chart');
}
stackedColumnChart('chart/budget/frontpage', 'budgets-chart');
columnChart('chart/category/frontpage', 'categories-chart');
columnChart('chart/account/expense', 'expense-accounts-chart');
columnChart('chart/account/revenue', 'revenue-accounts-chart');
columnChart(accountExpenseUri, 'expense-accounts-chart');
columnChart(accountRevenueUri, 'revenue-accounts-chart');
getBoxAmounts();

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