Merge branch 'release/3.3.2'

This commit is contained in:
James Cole 2015-03-14 22:06:11 +01:00
commit 6dd1b4537a
167 changed files with 5431 additions and 6191 deletions

View File

@ -1,3 +1,3 @@
src_dir: .
coverage_clover: tests/_output/coverage.xml
json_path: tests/_output/coveralls-upload.json
coverage_clover: storage/coverage/clover.xml
json_path: storage/coverage/coveralls-upload.json

1
.gitignore vendored
View File

@ -25,3 +25,4 @@ c3.php
db.sqlite-journal
tests/_output/*
.env
clover.xml

View File

@ -15,12 +15,7 @@ install:
- mv -v .env.testing .env
script:
- ./tests/_data/db.sh
- php vendor/bin/codecept build
- php vendor/bin/codecept run --coverage --coverage-xml --no-exit
- phpunit
after_script:
- cp -v tests/_output/coverage.xml build/logs/clover.xml
- php vendor/bin/coveralls
- vendor/bin/test-reporter --stdout > codeclimate.json
- "curl -X POST -d @codeclimate.json -H 'Content-Type: application/json' -H 'User-Agent: Code Climate (PHP Test Reporter v0.1.1)' https://codeclimate.com/test_reports"

View File

@ -1,4 +1,4 @@
Firefly III (v3.3.1)
Firefly III (v3.3.2)
===========
[![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=develop)](https://travis-ci.org/JC5/firefly-iii)

View File

@ -0,0 +1,31 @@
<?php namespace FireflyIII\Events;
use FireflyIII\Events\Event;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Queue\SerializesModels;
class JournalCreated extends Event {
use SerializesModels;
public $journal;
public $piggyBankId;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(TransactionJournal $journal, $piggyBankId)
{
//
$this->journal = $journal;
$this->piggyBankId = $piggyBankId;
}
}

View File

@ -0,0 +1,25 @@
<?php namespace FireflyIII\Events;
use FireflyIII\Events\Event;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Queue\SerializesModels;
class JournalSaved extends Event {
use SerializesModels;
public $journal;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(TransactionJournal $journal)
{
//
$this->journal = $journal;
}
}

View File

@ -0,0 +1,85 @@
<?php namespace FireflyIII\Handlers\Events;
use Auth;
use FireflyIII\Events\JournalCreated;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use Log;
/**
* Class ConnectJournalToPiggyBank
*
* @package FireflyIII\Handlers\Events
*/
class ConnectJournalToPiggyBank
{
/**
* Create the event handler.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event when journal is saved.
*
* @param JournalCreated $event
*
* @return void
*/
public function handle(JournalCreated $event)
{
/** @var TransactionJournal $journal */
$journal = $event->journal;
$piggyBankId = $event->piggyBankId;
Log::debug('JournalCreated event: ' . $journal->id . ', ' . $piggyBankId);
/** @var PiggyBank $piggyBank */
$piggyBank = Auth::user()->piggybanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
if (is_null($piggyBank) || $journal->transactionType->type != 'Transfer') {
return;
}
Log::debug('Found a piggy bank');
$amount = 0;
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($transaction->account_id === $piggyBank->account_id) {
// this transaction is the relevant one.
$amount = floatval($transaction->amount);
}
}
Log::debug('Amount: ' . $amount);
if ($amount == 0) {
return;
}
// update piggy bank rep for date of transaction journal.
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
if (is_null($repetition)) {
return;
}
Log::debug('Found rep! ' . $repetition->id);
$repetition->currentamount += $amount;
$repetition->save();
PiggyBankEvent::create(
[
'piggy_bank_id' => $piggyBank->id,
'transaction_journal_id' => $journal->id,
'date' => $journal->date,
'amount' => $amount
]
);
}
}

View File

@ -0,0 +1,53 @@
<?php namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\JournalSaved;
use Log;
use App;
/**
* Class RescanJournal
*
* @package FireflyIII\Handlers\Events
*/
class RescanJournal
{
/**
* Create the event handler.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param JournalSaved $event
*
* @return void
*/
public function handle(JournalSaved $event)
{
$journal = $event->journal;
Log::debug('Triggered saved event for journal #' . $journal->id . ' (' . $journal->description . ')');
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Bill\BillRepositoryInterface');
$list = $journal->user->bills()->where('active', 1)->where('automatch', 1)->get();
Log::debug('Found ' . $list->count() . ' bills to check.');
/** @var Bill $bill */
foreach ($list as $bill) {
Log::debug('Now calling bill #' . $bill->id . ' (' . $bill->name . ')');
$repository->scan($bill, $journal);
}
Log::debug('Done!');
}
}

View File

@ -0,0 +1,64 @@
<?php namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\JournalSaved;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
class UpdateJournalConnection
{
/**
* Create the event handler.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param JournalSaved $event
*
* @return void
*/
public function handle(JournalSaved $event)
{
$journal = $event->journal;
// get the event connected to this journal:
/** @var PiggyBankEvent $event */
$event = PiggyBankEvent::where('transaction_journal_id', $journal->id)->first();
if(is_null($event)) {
return;
}
$piggyBank = $event->piggyBank()->first();
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
if (is_null($repetition)) {
return;
}
$amount = 0;
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($transaction->account_id === $piggyBank->account_id) {
// this transaction is the relevant one.
$amount = floatval($transaction->amount);
}
}
// update current repetition:
$diff = $amount - $event->amount;
$repetition->currentamount += $diff;
$repetition->save();
$event->amount = $amount;
$event->save();
}
}

View File

@ -0,0 +1,148 @@
<?php
namespace FireflyIII\Helpers\Reminders;
use Amount;
use Auth;
use Carbon\Carbon;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Reminder;
use Navigation;
/**
* Class ReminderHelper
*
* @package FireflyIII\Helpers\Reminders
*/
class ReminderHelper implements ReminderHelperInterface
{
/**
* @param PiggyBank $piggyBank
* @param Carbon $start
* @param Carbon $end
*
* @return Reminder
*/
public function createReminder(PiggyBank $piggyBank, Carbon $start, Carbon $end)
{
$reminder = Auth::user()->reminders()
->where('remindersable_id', $piggyBank->id)
->onDates($start, $end)
->first();
if (is_null($reminder)) {
if (!is_null($piggyBank->targetdate)) {
// get ranges again, but now for the start date
$ranges = $this->getReminderRanges($piggyBank, $start);
$currentRep = $piggyBank->currentRelevantRep();
$left = $piggyBank->targetamount - $currentRep->currentamount;
$perReminder = $left / count($ranges);
} else {
$perReminder = null;
$ranges = [];
$left = 0;
}
$metaData = [
'perReminder' => $perReminder,
'rangesCount' => count($ranges),
'ranges' => $ranges,
'leftToSave' => $left,
];
// create one:
$reminder = new Reminder;
$reminder->user()->associate(Auth::user());
$reminder->startdate = $start;
$reminder->enddate = $end;
$reminder->active = true;
$reminder->metadata = $metaData;
$reminder->notnow = false;
$reminder->remindersable()->associate($piggyBank);
$reminder->save();
return $reminder;
} else {
return $reminder;
}
}
/**
* This routine will return an array consisting of two dates which indicate the start
* and end date for each reminder that this piggy bank will have, if the piggy bank has
* any reminders. For example:
*
* [12 mar - 15 mar]
* [15 mar - 18 mar]
*
* etcetera.
*
* Array is filled with tiny arrays with Carbon objects in them.
*
* @param PiggyBank $piggyBank
* @param Carbon $date ;
*
* @return array
*/
public function getReminderRanges(PiggyBank $piggyBank, Carbon $date = null)
{
$ranges = [];
if (is_null($date)) {
$date = new Carbon;
}
if ($piggyBank->remind_me === false) {
return $ranges;
}
if (!is_null($piggyBank->targetdate)) {
// count back until now.
// echo 'Count back!<br>';
$start = $piggyBank->targetdate;
$end = $piggyBank->startdate;
while ($start > $end) {
$currentEnd = clone $start;
$start = Navigation::subtractPeriod($start, $piggyBank->reminder, 1);
$currentStart = clone $start;
$ranges[] = ['start' => clone $currentStart, 'end' => clone $currentEnd];
}
} else {
$start = clone $piggyBank->startdate;
while ($start < $date) {
$currentStart = clone $start;
$start = Navigation::addPeriod($start, $piggyBank->reminder, 0);
$currentEnd = clone $start;
$ranges[] = ['start' => clone $currentStart, 'end' => clone $currentEnd];
}
}
return $ranges;
}
/**
* Takes a reminder, finds the piggy bank and tells you what to do now.
* Aka how much money to put in.
*
*
* @param Reminder $reminder
*
* @return string
*/
public function getReminderText(Reminder $reminder)
{
/** @var PiggyBank $piggyBank */
$piggyBank = $reminder->remindersable;
if(is_null($piggyBank)) {
return 'Piggy bank no longer exists.';
}
if (is_null($piggyBank->targetdate)) {
return 'Add money to this piggy bank to reach your target of ' . Amount::format($piggyBank->targetamount);
}
return 'Add ' . Amount::format($reminder->metadata->perReminder) . ' to fill this piggy bank on ' . $piggyBank->targetdate->format('jS F Y');
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace FireflyIII\Helpers\Reminders;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\PiggyBank;
use Carbon\Carbon;
/**
* Interface ReminderHelperInterface
*
* @package FireflyIII\Helpers\Reminders
*/
interface ReminderHelperInterface {
/**
* Takes a reminder, finds the piggy bank and tells you what to do now.
* Aka how much money to put in.
*
* @param Reminder $reminder
*
* @return string
*/
public function getReminderText(Reminder $reminder);
/**
* This routine will return an array consisting of two dates which indicate the start
* and end date for each reminder that this piggy bank will have, if the piggy bank has
* any reminders. For example:
*
* [12 mar - 15 mar]
* [15 mar - 18 mar]
*
* etcetera.
*
* Array is filled with tiny arrays with Carbon objects in them.
*
* @param PiggyBank $piggyBank
*
* @return array
*/
public function getReminderRanges(PiggyBank $piggyBank);
/**
* @param PiggyBank $piggyBank
* @param Carbon $start
* @param Carbon $end
*
* @return Reminder
*/
public function createReminder(PiggyBank $piggyBank, Carbon $start, Carbon $end);
}

View File

@ -7,6 +7,7 @@ use Carbon\Carbon;
use FireflyIII\Models\Account;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Steam;
/**
* Class ReportHelper
@ -35,19 +36,6 @@ class ReportHelper implements ReportHelperInterface
}
/**
* @return Carbon
*/
public function firstDate()
{
$journal = Auth::user()->transactionjournals()->orderBy('date', 'ASC')->first();
if ($journal) {
return $journal->date;
}
return Carbon::now();
}
/**
* This method gets some kind of list for a monthly overview.
*
@ -62,7 +50,7 @@ class ReportHelper implements ReportHelperInterface
$end = clone $date;
$end->endOfMonth();
// all budgets
$set = \Auth::user()->budgets()
$set = Auth::user()->budgets()
->leftJoin(
'budget_limits', function (JoinClause $join) use ($date) {
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
@ -99,7 +87,8 @@ class ReportHelper implements ReportHelperInterface
$end = Carbon::now();
$months = [];
while ($start <= $end) {
$months[] = [
$year = $start->format('Y');
$months[$year][] = [
'formatted' => $start->format('F Y'),
'month' => intval($start->format('m')),
'year' => intval($start->format('Y')),
@ -130,43 +119,47 @@ class ReportHelper implements ReportHelperInterface
/**
* @param Carbon $date
* @param bool $showSharedReports
*
* @return array
*/
public function yearBalanceReport(Carbon $date)
public function yearBalanceReport(Carbon $date, $showSharedReports = false)
{
$start = clone $date;
$end = clone $date;
$sharedAccounts = [];
$sharedCollection = \Auth::user()->accounts()
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
->where('account_meta.name', '=', 'accountRole')
->where('account_meta.data', '=', json_encode('sharedExpense'))
->get(['accounts.id']);
$start = clone $date;
$end = clone $date;
$sharedAccounts = [];
if ($showSharedReports === false) {
$sharedCollection = \Auth::user()->accounts()
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
->where('account_meta.name', '=', 'accountRole')
->where('account_meta.data', '=', json_encode('sharedAsset'))
->get(['accounts.id']);
foreach ($sharedCollection as $account) {
$sharedAccounts[] = $account->id;
foreach ($sharedCollection as $account) {
$sharedAccounts[] = $account->id;
}
}
$accounts = \Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])->filter(
function (Account $account) use ($sharedAccounts) {
if (!in_array($account->id, $sharedAccounts)) {
return $account;
}
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*'])
->filter(
function (Account $account) use ($sharedAccounts) {
if (!in_array($account->id, $sharedAccounts)) {
return $account;
}
return null;
}
);
return null;
}
);
$report = [];
$start->startOfYear()->subDay();
$end->endOfYear();
foreach ($accounts as $account) {
$report[] = [
'start' => \Steam::balance($account, $start),
'end' => \Steam::balance($account, $end),
'start' => Steam::balance($account, $start),
'end' => Steam::balance($account, $end),
'account' => $account,
'shared' => $account->accountRole == 'sharedExpense'
'shared' => $account->accountRole == 'sharedAsset'
];
}

View File

@ -14,32 +14,6 @@ interface ReportHelperInterface
{
/**
* @return Carbon
*/
public function firstDate();
/**
* @param Carbon $date
*
* @return array
*/
public function listOfMonths(Carbon $date);
/**
* @param Carbon $date
*
* @return array
*/
public function listOfYears(Carbon $date);
/**
* @param Carbon $date
*
* @return array
*/
public function yearBalanceReport(Carbon $date);
/**
* This methods fails to take in account transfers FROM shared accounts.
*
@ -59,4 +33,26 @@ interface ReportHelperInterface
* @return Collection
*/
public function getBudgetsForMonth(Carbon $date);
/**
* @param Carbon $date
*
* @return array
*/
public function listOfMonths(Carbon $date);
/**
* @param Carbon $date
*
* @return array
*/
public function listOfYears(Carbon $date);
/**
* @param Carbon $date
* @param bool $showSharedReports
*
* @return array
*/
public function yearBalanceReport(Carbon $date, $showSharedReports = false);
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 22/02/15
* Time: 18:30
*/
namespace FireflyIII\Helpers\Report;
@ -29,26 +23,33 @@ class ReportQuery implements ReportQueryInterface
/**
* This query retrieves a list of accounts that are active and not shared.
*
* @param bool $showSharedReports
*
* @return Collection
*/
public function accountList()
public function accountList($showSharedReports = false)
{
return Auth::user()->accounts()
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', "accountRole");
}
)
->whereIn('account_types.type', ['Default account', 'Cash account', 'Asset account'])
->where('active', 1)
->where(
function (Builder $query) {
$query->where('account_meta.data', '!=', '"sharedExpense"');
$query->orWhereNull('account_meta.data');
}
)
->get(['accounts.*']);
$query = Auth::user()->accounts();
if ($showSharedReports === false) {
$query->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', "accountRole");
}
)->where(
function (Builder $query) {
$query->where('account_meta.data', '!=', '"sharedAsset"');
$query->orWhereNull('account_meta.data');
}
);
}
$query->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', ['Default account', 'Cash account', 'Asset account'])
->where('active', 1)
->orderBy('accounts.name', 'ASC');
return $query->get(['accounts.*']);
}
/**
@ -82,19 +83,37 @@ class ReportQuery implements ReportQueryInterface
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'otherJournals.id')
->before($end)->after($start)
->where('transaction_types.type', 'Withdrawal')
->where('transaction_journals.user_id', \Auth::user()->id)
->where('transaction_journals.user_id', Auth::user()->id)
->whereNull('budget_transaction_journal.budget_id')->whereNull('transaction_journals.deleted_at')
->whereNull('otherJournals.deleted_at')
->where('transactions.account_id', $account->id)
->whereNotNull('transaction_group_transaction_journal.transaction_group_id')
->first(
->get(
[
DB::Raw('SUM(`transactions`.`amount`) as `amount`')
'transaction_journals.*',
'transactions.amount'
]
);
return $set;
}
/**
* This method will get the sum of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function balancedTransactionsSum(Account $account, Carbon $start, Carbon $end)
{
$set = $this->balancedTransactionsList($account, $start, $end);
$sum = 0;
if (!is_null($set)) {
$sum = floatval($set->amount);
foreach ($set as $entry) {
$sum += floatval($entry->amount);
}
return $sum;
@ -105,25 +124,31 @@ class ReportQuery implements ReportQueryInterface
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function getAllAccounts(Carbon $start, Carbon $end)
public function getAllAccounts(Carbon $start, Carbon $end, $showSharedReports = false)
{
$set = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')
->accountTypeIn(['Default account', 'Asset account', 'Cash account'])
->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->where(
function (Builder $query) {
$query->where('account_meta.data', '!=', '"sharedExpense"');
$query->orWhereNull('account_meta.data');
}
)
->get(['accounts.*']);
$query = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')
->accountTypeIn(['Default account', 'Asset account', 'Cash account']);
if ($showSharedReports === false) {
$query->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->orderBy('accounts.name', 'ASC')
->where(
function (Builder $query) use ($showSharedReports) {
$query->where('account_meta.data', '!=', '"sharedAsset"');
$query->orWhereNull('account_meta.data');
}
);
}
$set = $query->get(['accounts.*']);
$set->each(
function (Account $account) use ($start, $end) {
/** @noinspection PhpParamsInspection */
@ -167,7 +192,40 @@ class ReportQuery implements ReportQueryInterface
return $set;
}
/**
* Get a list of transaction journals that have no budget, filtered for the specified account
* and the specified date range.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getTransactionsWithoutBudget(Account $account, Carbon $start, Carbon $end)
{
$set = TransactionJournal::
leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budgets', 'budgets.id', '=', 'budget_transaction_journal.budget_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);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->before($end)
->after($start)
->where('accounts.id', $account->id)
->where('transaction_journals.user_id', Auth::user()->id)
->where('transaction_types.type', 'Withdrawal')
->whereNull('budgets.id')
->orderBy('transaction_journals.date', 'ASC')
->get(['budgets.name', 'transactions.amount', 'transaction_journals.*']);
return $set;
}
/**
@ -177,62 +235,73 @@ class ReportQuery implements ReportQueryInterface
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function incomeByPeriod(Carbon $start, Carbon $end)
public function incomeByPeriod(Carbon $start, Carbon $end, $showSharedReports = false)
{
return TransactionJournal::
$query = TransactionJournal::
leftJoin(
'transactions as t_from', function (JoinClause $join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
}
)
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin(
'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin(
'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->where(
function ($query) {
$query->where(
function ($q) {
$q->where('transaction_types.type', 'Deposit');
$q->where('acm_to.data', '!=', '"sharedExpense"');
}
);
$query->orWhere(
function ($q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_from.data', '=', '"sharedExpense"');
}
);
}
)
->before($end)->after($start)
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('t_from.account_id')->orderBy('transaction_journals.date')
->get(
['transaction_journals.id',
'transaction_journals.description',
'transaction_journals.encrypted',
'transaction_types.type',
't_to.amount', 'transaction_journals.date', 't_from.account_id as account_id',
'ac_from.name as name']
);
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin(
'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin(
'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
if ($showSharedReports === false) {
// only get deposits not to a shared account
// and transfers to a shared account.
$query->where(
function ($query) {
$query->where(
function ($q) {
$q->where('transaction_types.type', 'Deposit');
$q->where('acm_to.data', '!=', '"sharedAsset"');
}
);
$query->orWhere(
function ($q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_from.data', '=', '"sharedAsset"');
}
);
}
);
} else {
// any deposit is fine.
$query->where('transaction_types.type', 'Deposit');
}
$query->before($end)->after($start)
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('t_from.account_id')->orderBy('transaction_journals.date');
return $query->get(
['transaction_journals.id',
'transaction_journals.description',
'transaction_journals.encrypted',
'transaction_types.type',
DB::Raw('SUM(`t_to`.`amount`) as `amount`'),
'transaction_journals.date',
't_from.account_id as account_id',
'ac_from.name as name']
);
}
/**
@ -240,33 +309,37 @@ class ReportQuery implements ReportQueryInterface
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByBudget(Carbon $start, Carbon $end)
public function journalsByBudget(Carbon $start, Carbon $end, $showSharedReports = false)
{
return Auth::user()->transactionjournals()
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('account_meta.data', '!=', '"sharedExpense"')
->where('transaction_types.type', 'Withdrawal')
->groupBy('budgets.id')
->orderBy('budgets.name', 'ASC')
->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) AS `spent`')]);
$query = Auth::user()->transactionjournals()
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id');
if ($showSharedReports === false) {
$query->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)->where('account_meta.data', '!=', '"sharedAsset"');
}
$query->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_types.type', 'Withdrawal')
->groupBy('budgets.id')
->orderBy('budgets.name', 'ASC');
return $query->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) AS `spent`')]);
}
/**
@ -275,35 +348,38 @@ class ReportQuery implements ReportQueryInterface
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByCategory(Carbon $start, Carbon $end)
public function journalsByCategory(Carbon $start, Carbon $end, $showSharedReports = false)
{
return Auth::user()->transactionjournals()
->leftJoin(
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
)
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('account_meta.data', '!=', '"sharedExpense"')
->where('transaction_types.type', 'Withdrawal')
->groupBy('categories.id')
->orderBy('amount')
->get(['categories.id', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `amount`')]);
$query = Auth::user()->transactionjournals()
->leftJoin(
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
)
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id');
if ($showSharedReports === false) {
$query->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)->where('account_meta.data', '!=', '"sharedAsset"');
}
$query->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_types.type', 'Withdrawal')
->groupBy('categories.id')
->orderBy('amount');
return $query->get(['categories.id', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `amount`')]);
}
@ -315,57 +391,65 @@ class ReportQuery implements ReportQueryInterface
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByExpenseAccount(Carbon $start, Carbon $end)
public function journalsByExpenseAccount(Carbon $start, Carbon $end, $showSharedReports = false)
{
return TransactionJournal::
leftJoin(
$query = TransactionJournal::leftJoin(
'transactions as t_from', function (JoinClause $join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
}
)
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin(
'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin(
'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->where(
function ($query) {
$query->where(
function ($q) {
$q->where('transaction_types.type', 'Withdrawal');
$q->where('acm_from.data', '!=', '"sharedExpense"');
}
);
$query->orWhere(
function ($q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_to.data', '=', '"sharedExpense"');
}
);
}
)
->before($end)
->after($start)
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('t_to.account_id')
->orderBy('amount', 'DESC')
->get(['t_to.account_id as id', 'ac_to.name as name', DB::Raw('SUM(t_to.amount) as `amount`')]);
)->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin(
'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin(
'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
if ($showSharedReports === false) {
// get all withdrawals not from a shared accounts
// and all transfers to a shared account
$query->where(
function ($query) {
$query->where(
function ($q) {
$q->where('transaction_types.type', 'Withdrawal');
$q->where('acm_from.data', '!=', '"sharedAsset"');
}
);
$query->orWhere(
function ($q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_to.data', '=', '"sharedAsset"');
}
);
}
);
} else {
// any withdrawal goes:
$query->where('transaction_types.type', 'Withdrawal');
}
$query->before($end)
->after($start)
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('t_to.account_id')
->orderBy('amount', 'DESC');
return $query->get(['t_to.account_id as id', 'ac_to.name as name', DB::Raw('SUM(t_to.amount) as `amount`')]);
}
/**
@ -373,55 +457,65 @@ class ReportQuery implements ReportQueryInterface
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByRevenueAccount(Carbon $start, Carbon $end)
public function journalsByRevenueAccount(Carbon $start, Carbon $end, $showSharedReports = false)
{
return TransactionJournal::
$query = TransactionJournal::
leftJoin(
'transactions as t_from', function (JoinClause $join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
}
)
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin(
'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin(
'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->where(
function ($query) {
$query->where(
function ($q) {
$q->where('transaction_types.type', 'Deposit');
$q->where('acm_to.data', '!=', '"sharedExpense"');
}
);
$query->orWhere(
function ($q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_from.data', '=', '"sharedExpense"');
}
);
}
)
->before($end)->after($start)
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('t_from.account_id')->orderBy('amount')
->get(['t_from.account_id as account_id', 'ac_from.name as name', DB::Raw('SUM(t_from.amount) as `amount`')]);
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin(
'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin(
'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
if ($showSharedReports === false) {
// show queries where transfer type is deposit, and its not to a shared account
// or where its a transfer and its from a shared account (both count as incomes)
$query->where(
function ($query) {
$query->where(
function ($q) {
$q->where('transaction_types.type', 'Deposit');
$q->where('acm_to.data', '!=', '"sharedAsset"');
}
);
$query->orWhere(
function ($q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_from.data', '=', '"sharedAsset"');
}
);
}
);
} else {
// any deposit goes:
$query->where('transaction_types.type', 'Deposit');
}
$query->before($end)->after($start)
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('t_from.account_id')->orderBy('amount');
return $query->get(['t_from.account_id as account_id', 'ac_from.name as name', DB::Raw('SUM(t_from.amount) as `amount`')]);
}
/**
@ -450,7 +544,7 @@ class ReportQuery implements ReportQueryInterface
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->where('account_meta.data', '"sharedExpense"')
->where('account_meta.data', '"sharedAsset"')
->after($start)
->before($end)
->where('transaction_types.type', 'Transfer')
@ -492,7 +586,7 @@ class ReportQuery implements ReportQueryInterface
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
)
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
->where('account_meta.data', '"sharedExpense"')
->where('account_meta.data', '"sharedAsset"')
->after($start)
->before($end)
->where('transaction_types.type', 'Transfer')

View File

@ -17,19 +17,69 @@ interface ReportQueryInterface
/**
* This query retrieves a list of accounts that are active and not shared.
*
* @param bool $showSharedReports
*
* @return Collection
*/
public function accountList();
public function accountList($showSharedReports = false);
/**
* This method will get a list of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function balancedTransactionsList(Account $account, Carbon $start, Carbon $end);
/**
* This method will get the sum of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function balancedTransactionsSum(Account $account, Carbon $start, Carbon $end);
/**
* Get a users accounts combined with various meta-data related to the start and end date.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function getAllAccounts(Carbon $start, Carbon $end);
public function getAllAccounts(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Grabs a summary of all expenses grouped by budget, related to the account.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getBudgetSummary(Account $account, Carbon $start, Carbon $end);
/**
* Get a list of transaction journals that have no budget, filtered for the specified account
* and the specified date range.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getTransactionsWithoutBudget(Account $account, Carbon $start, Carbon $end);
/**
* This method returns all "income" journals in a certain period, which are both transfers from a shared account
@ -38,20 +88,22 @@ interface ReportQueryInterface
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function incomeByPeriod(Carbon $start, Carbon $end);
public function incomeByPeriod(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Gets a list of expenses grouped by the budget they were filed under.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByBudget(Carbon $start, Carbon $end);
public function journalsByBudget(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Gets a list of categories and the expenses therein, grouped by the relevant category.
@ -59,10 +111,11 @@ interface ReportQueryInterface
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByCategory(Carbon $start, Carbon $end);
public function journalsByCategory(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Gets a list of expense accounts and the expenses therein, grouped by that expense account.
@ -72,20 +125,22 @@ interface ReportQueryInterface
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByExpenseAccount(Carbon $start, Carbon $end);
public function journalsByExpenseAccount(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* This method returns all deposits into asset accounts, grouped by the revenue account,
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByRevenueAccount(Carbon $start, Carbon $end);
public function journalsByRevenueAccount(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* With an equally misleading name, this query returns are transfers to shared accounts. These are considered
@ -108,27 +163,4 @@ interface ReportQueryInterface
* @return Collection
*/
public function sharedExpensesByCategory(Carbon $start, Carbon $end);
/**
* Grabs a summary of all expenses grouped by budget, related to the account.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getBudgetSummary(Account $account, Carbon $start, Carbon $end);
/**
* This method will get a list of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function balancedTransactionsList(Account $account, Carbon $start, Carbon $end);
}

View File

@ -1,6 +1,5 @@
<?php namespace FireflyIII\Http\Controllers;
use App;
use Auth;
use Carbon\Carbon;
use Config;
@ -8,9 +7,11 @@ use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\AccountFormRequest;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator;
use Input;
use Redirect;
use Session;
use Steam;
use View;
/**
@ -74,6 +75,12 @@ class AccountController extends Controller
return Redirect::route('accounts.index', $typeName);
}
/**
* @param Account $account
* @param AccountRepositoryInterface $repository
*
* @return View
*/
public function edit(Account $account, AccountRepositoryInterface $repository)
{
$what = Config::get('firefly.shortNamesByFullName')[$account->accountType->type];
@ -110,29 +117,59 @@ class AccountController extends Controller
$subTitle = Config::get('firefly.subTitlesByIdentifier.' . $what);
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
$types = Config::get('firefly.accountTypesByIdentifier.' . $what);
$accounts = Auth::user()->accounts()->accountTypeIn($types)->get(['accounts.*']);
$size = 50;
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$offset = ($page - 1) * $size;
// move to repository:
$set = Auth::user()->accounts()->with(
['accountmeta' => function ($query) {
$query->where('name', 'accountRole');
}]
)->accountTypeIn($types)->take($size)->offset($offset)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$total = Auth::user()->accounts()->accountTypeIn($types)->count();
// last activity:
$start = clone Session::get('start');
$start->subDay();
$set->each(
function (Account $account) use ($start) {
$lastTransaction = $account->transactions()->leftJoin(
'transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id'
)->orderBy('transaction_journals.date', 'DESC')->first(['transactions.*', 'transaction_journals.date']);
if ($lastTransaction) {
$account->lastActivityDate = $lastTransaction->transactionjournal->date;
} else {
$account->lastActivityDate = null;
}
$account->startBalance = Steam::balance($account, $start);
$account->endBalance = Steam::balance($account, Session::get('end'));
}
);
$accounts = new LengthAwarePaginator($set, $total, $size, $page);
$accounts->setPath(route('accounts.index', $what));
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
}
/**
* @param Account $account
* @param string $range
* @param AccountRepositoryInterface $repository
*
* @return \Illuminate\View\View
* @return View
*/
public function show(Account $account, $range = 'session')
public function show(Account $account, AccountRepositoryInterface $repository)
{
/** @var \FireflyIII\Repositories\Account\AccountRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Account\AccountRepositoryInterface');
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $account->accountType->type);
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
$journals = $repository->getJournals($account, $page, $range);
$journals = $repository->getJournals($account, $page);
$subTitle = 'Details for ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
return view('accounts.show', compact('account', 'what', 'range', 'subTitleIcon', 'journals', 'subTitle'));
return view('accounts.show', compact('account', 'what', 'subTitleIcon', 'journals', 'subTitle'));
}
/**
@ -158,6 +195,10 @@ class AccountController extends Controller
Session::flash('success', 'New account "' . $account->name . '" stored!');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('accounts.create', $request->input('what'));
}
return Redirect::route('accounts.index', $request->input('what'));
}
@ -186,6 +227,10 @@ class AccountController extends Controller
Session::flash('success', 'Account "' . $account->name . '" updated.');
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('accounts.edit', $account->id);
}
return Redirect::route('accounts.index', $what);
}

View File

@ -4,6 +4,9 @@ use FireflyIII\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\Registrar;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Http\Request;
use Mail;
use Session;
/**
* Class AuthController
@ -43,4 +46,40 @@ class AuthController extends Controller
$this->middleware('guest', ['except' => 'getLogout']);
}
/**
* Handle a registration request for the application.
*
* @param Request $request
*
* @return \Illuminate\Http\Response
*/
public function postRegister(Request $request)
{
$validator = $this->registrar->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$this->auth->login($this->registrar->create($request->all()));
// get the email address
$email = $this->auth->user()->email;
// send email.
Mail::send(
'emails.registered', [], function ($message) use ($email) {
$message->to($email, $email)->subject('Welcome to Firefly III!');
}
);
// set flash message
Session::flash('success', 'You have registered successfully!');
return redirect($this->redirectPath());
}
}

View File

@ -8,6 +8,7 @@ use FireflyIII\Models\Bill;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Input;
use Redirect;
use Session;
use URL;
@ -80,7 +81,7 @@ class BillController extends Controller
*/
public function index(BillRepositoryInterface $repository)
{
$bills = Auth::user()->bills()->get();
$bills = Auth::user()->bills()->orderBy('name', 'ASC')->get();
$bills->each(
function (Bill $bill) use ($repository) {
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
@ -108,7 +109,9 @@ class BillController extends Controller
return Redirect::intended('/');
}
$set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)->get(['transaction_journal_id']);
$set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)->get(
['transaction_journal_id']
);
$ids = [];
/** @var Transaction $entry */
@ -116,7 +119,7 @@ class BillController extends Controller
$ids[] = intval($entry->transaction_journal_id);
}
if (count($ids) > 0) {
$journals = Auth::user()->transactionjournals()->whereIn('id',$ids)->get();
$journals = Auth::user()->transactionjournals()->whereIn('id', $ids)->get();
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$repository->scan($bill, $journal);
@ -168,6 +171,10 @@ class BillController extends Controller
$bill = $repository->store($billData);
Session::flash('success', 'Bill "' . e($bill->name) . '" stored.');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('bills.create')->withInput();
}
return Redirect::route('bills.index');
}
@ -195,6 +202,10 @@ class BillController extends Controller
$bill = $repository->update($bill, $billData);
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('bills.edit', $bill->id);
}
Session::flash('success', 'Bill "' . e($bill->name) . '" updated.');
return Redirect::route('bills.index');

View File

@ -7,10 +7,10 @@ use FireflyIII\Http\Requests\CategoryFormRequest;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator;
use Input;
use Redirect;
use Session;
use View;
use Input;
/**
@ -38,44 +38,6 @@ class CategoryController extends Controller
return view('categories.create')->with('subTitle', 'Create a new category');
}
/**
* @param Category $category
*
* @return $this
*/
public function show(Category $category, CategoryRepositoryInterface $repository)
{
$hideCategory = true; // used in list.
$page = intval(Input::get('page'));
$offset = $page > 0 ? $page * 50 : 0;
$set = $category->transactionJournals()->withRelevantData()->take(50)->offset($offset)->orderBy('date', 'DESC')->get(['transaction_journals.*']);
$count = $category->transactionJournals()->count();
$journals = new LengthAwarePaginator($set, $count, 50, $page);
return view('categories.show', compact('category', 'journals', 'hideCategory'));
}
/**
* @return \Illuminate\View\View
*/
public function noCategory()
{
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->startOfMonth());
$list = Auth::user()
->transactionjournals()
->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->whereNull('category_transaction_journal.id')
->before($end)
->after($start)
->orderBy('transaction_journals.date')
->get(['transaction_journals.*']);
$subTitle = 'Transactions without a category in ' . $start->format('F Y');
return view('categories.noCategory', compact('list', 'subTitle'));
}
/**
* @param Category $category
*
@ -122,11 +84,61 @@ class CategoryController extends Controller
*/
public function index()
{
$categories = Auth::user()->categories()->get();
$categories = Auth::user()->categories()->orderBy('name', 'ASC')->get();
$categories->each(
function (Category $category) {
$latest = $category->transactionjournals()->orderBy('date', 'DESC')->first();
if ($latest) {
$category->lastActivity = $latest->date;
}
}
);
return view('categories.index', compact('categories'));
}
/**
* @return \Illuminate\View\View
*/
public function noCategory()
{
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->startOfMonth());
$list = Auth::user()
->transactionjournals()
->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->whereNull('category_transaction_journal.id')
->before($end)
->after($start)
->orderBy('transaction_journals.date')
->get(['transaction_journals.*']);
$subTitle = 'Transactions without a category between ' . $start->format('jS F Y') . ' and ' . $end->format('jS F Y');
return view('categories.noCategory', compact('list', 'subTitle'));
}
/**
* @param Category $category
*
* @return $this
*/
public function show(Category $category, CategoryRepositoryInterface $repository)
{
$hideCategory = true; // used in list.
$page = intval(Input::get('page'));
$offset = $page > 0 ? $page * 50 : 0;
$set = $category->transactionJournals()->withRelevantData()->take(50)->offset($offset)->orderBy('date', 'DESC')->get(
['transaction_journals.*']
);
$count = $category->transactionJournals()->count();
$journals = new LengthAwarePaginator($set, $count, 50, $page);
return view('categories.show', compact('category', 'journals', 'hideCategory'));
}
/**
* @param CategoryFormRequest $request
* @param CategoryRepositoryInterface $repository

View File

@ -1,14 +1,16 @@
<?php namespace FireflyIII\Http\Controllers;
use Cache;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\CurrencyFormRequest;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use Input;
use Preferences;
use Redirect;
use Session;
use View;
use Cache;
/**
* Class CurrencyController
@ -145,6 +147,10 @@ class CurrencyController extends Controller
Session::flash('success', 'Currency "' . $currency->name . '" created');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('currency.create');
}
return Redirect::route('currency.index');
@ -163,7 +169,12 @@ class CurrencyController extends Controller
$currency->name = $request->get('name');
$currency->save();
Session::flash('success', 'Currency "' . e($currency->namename) . '" updated.');
Session::flash('success', 'Currency "' . e($currency->name) . '" updated.');
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('currency.edit', $currency->id);
}
return Redirect::route('currency.index');

View File

@ -3,7 +3,7 @@
use App;
use Auth;
use Carbon\Carbon;
use Crypt;
use DB;
use Exception;
use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Http\Requests;
@ -13,17 +13,19 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Grumpydictator\Gchart\GChart;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Navigation;
use Preferences;
use Response;
use Session;
use DB;
use Steam;
/**
@ -41,27 +43,14 @@ class GoogleChartController extends Controller
*
* @return \Illuminate\Http\JsonResponse
*/
public function accountBalanceChart(Account $account, $view = 'session', GChart $chart)
public function accountBalanceChart(Account $account, GChart $chart)
{
$chart->addColumn('Day of month', 'date');
$chart->addColumn('Balance for ' . $account->name, 'number');
$chart->addCertainty(1);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$count = $account->transactions()->count();
if ($view == 'all' && $count > 0) {
$first = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy(
'date', 'ASC'
)->first(['transaction_journals.date']);
$last = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy(
'date', 'DESC'
)->first(['transaction_journals.date']);
$start = new Carbon($first->date);
$end = new Carbon($last->date);
}
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$current = clone $start;
while ($end >= $current) {
@ -89,9 +78,9 @@ class GoogleChartController extends Controller
$end = Session::get('end', Carbon::now()->endOfMonth());
if ($frontPage->data == []) {
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']);
$accounts = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']);
} else {
$accounts = Auth::user()->accounts()->whereIn('id', $frontPage->data)->get(['accounts.*']);
$accounts = Auth::user()->accounts()->whereIn('id', $frontPage->data)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
}
$index = 1;
/** @var Account $account */
@ -177,27 +166,35 @@ class GoogleChartController extends Controller
/** @var Budget $budget */
foreach ($budgets as $budget) {
/** @var \LimitRepetition $repetition */
$repetition = LimitRepetition::
/** @var Collection $repetitions */
$repetitions = LimitRepetition::
leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00'))
->where('budget_limits.budget_id', $budget->id)
->first(['limit_repetitions.*']);
if (is_null($repetition)) { // use the session start and end for our search query
$searchStart = $start;
$searchEnd = $end;
$limit = 0; // the limit is zero:
->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00'))
->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00'))
->where('budget_limits.budget_id', $budget->id)
->get(['limit_repetitions.*']);
// no results? search entire range for expenses and list those.
if ($repetitions->count() == 0) {
$expenses = floatval($budget->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
if ($expenses > 0) {
$chart->addRow($budget->name, 0, $expenses);
}
} else {
// use the limit's start and end for our search query
$searchStart = $repetition->startdate;
$searchEnd = $repetition->enddate;
$limit = floatval($repetition->amount); // the limit is the repetitions limit:
// add with foreach:
/** @var LimitRepetition $repetition */
foreach ($repetitions as $repetition) {
$expenses
=
floatval($budget->transactionjournals()->before($repetition->enddate)->after($repetition->startdate)->lessThan(0)->sum('amount')) * -1;
if ($expenses > 0) {
$chart->addRow($budget->name . ' (' . $repetition->startdate->format('j M Y') . ')', floatval($repetition->amount), $expenses);
}
}
}
$expenses = floatval($budget->transactionjournals()->before($searchEnd)->after($searchStart)->lessThan(0)->sum('amount')) * -1;
if ($expenses > 0) {
$chart->addRow($budget->name, $limit, $expenses);
}
}
$noBudgetSet = Auth::user()
@ -209,7 +206,8 @@ class GoogleChartController extends Controller
->from('transaction_journals')
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'));
->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'))
->whereNotNull('budget_transaction_journal.budget_id');
}
)
->before($end)
@ -315,49 +313,45 @@ class GoogleChartController extends Controller
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function billsOverview(GChart $chart)
public function billsOverview(GChart $chart, BillRepositoryInterface $repository)
{
$chart->addColumn('Name', 'string');
$chart->addColumn('Amount', 'number');
$paid = ['items' => [], 'amount' => 0];
$unpaid = ['items' => [], 'amount' => 0];
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$chart->addColumn('Name', 'string');
$chart->addColumn('Amount', 'number');
$bills = Auth::user()->bills()->where('active', 1)->get();
$set = Bill::
leftJoin(
'transaction_journals', function (JoinClause $join) use ($start, $end) {
$join->on('bills.id', '=', 'transaction_journals.bill_id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'));
}
)
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '>', 0);
}
)
->where('active', 1)
->groupBy('bills.id')
->get(
['bills.id', 'bills.name', 'transaction_journals.description',
'transaction_journals.encrypted',
'transaction_journals.id as journalId',
\DB::Raw('SUM(`bills`.`amount_min` + `bills`.`amount_max`) / 2 as `averageAmount`'),
'transactions.amount AS actualAmount']
);
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
if ($count == 0) {
$unpaid['items'][] = $bill->name . ' (' . $range['start']->format('jS M Y') . ')';
$unpaid['amount'] += ($bill->amount_max + $bill->amount_min / 2);
} else {
$journal = $bill->transactionjournals()->with('transactions')->before($range['end'])->after($range['start'])->first();
$paid['items'][] = $journal->description;
$amount = 0;
foreach ($journal->transactions as $t) {
if (floatval($t->amount) > 0) {
$amount = floatval($t->amount);
}
}
$paid['amount'] += $amount;
}
foreach ($set as $entry) {
if (intval($entry->journalId) == 0) {
$unpaid['items'][] = $entry->name;
$unpaid['amount'] += floatval($entry->averageAmount);
} else {
$description = intval($entry->encrypted) == 1 ? Crypt::decrypt($entry->description) : $entry->description;
$paid['items'][] = $description;
$paid['amount'] += floatval($entry->actualAmount);
}
}
$chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
$chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
$chart->generate();
@ -463,36 +457,32 @@ class GoogleChartController extends Controller
/**
*
* @param Category $category
* @param $year
* @param Category $category
*
* @return \Illuminate\Http\JsonResponse
*/
public function categoriesAndSpending(Category $category, $year, GChart $chart)
public function categoryOverviewChart(Category $category, GChart $chart)
{
try {
new Carbon('01-01-' . $year);
} catch (Exception $e) {
return view('error')->with('message', 'Invalid year.');
}
// oldest transaction in category:
/** @var TransactionJournal $first */
$first = $category->transactionjournals()->orderBy('date', 'ASC')->first();
$start = $first->date;
/** @var Preference $range */
$range = Preferences::get('viewRange', '1M');
// jump to start of week / month / year / etc (TODO).
$start = Navigation::startOfPeriod($start, $range->data);
$chart->addColumn('Month', 'date');
$chart->addColumn('Budgeted', 'number');
$chart->addColumn('Period', 'date');
$chart->addColumn('Spent', 'number');
$start = new Carbon('01-01-' . $year);
$end = clone $start;
$end->endOfYear();
$end = new Carbon;
while ($start <= $end) {
$currentEnd = clone $start;
$currentEnd->endOfMonth();
$spent = floatval($category->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
$budgeted = null;
$currentEnd = Navigation::endOfPeriod($start, $range->data);
$spent = floatval($category->transactionjournals()->before($currentEnd)->after($start)->lessThan(0)->sum('amount')) * -1;
$chart->addRow(clone $start, $spent);
$chart->addRow(clone $start, $budgeted, $spent);
$start->addMonth();
$start = Navigation::addPeriod($start, $range->data, 0);
}
@ -503,6 +493,35 @@ class GoogleChartController extends Controller
}
/**
*
* @param Category $category
*
* @return \Illuminate\Http\JsonResponse
*/
public function categoryPeriodChart(Category $category, GChart $chart)
{
// oldest transaction in category:
/** @var TransactionJournal $first */
$start = Session::get('start');
$chart->addColumn('Period', 'date');
$chart->addColumn('Spent', 'number');
$end = Session::get('end');
while ($start <= $end) {
$spent = floatval($category->transactionjournals()->onDate($start)->lessThan(0)->sum('amount')) * -1;
$chart->addRow(clone $start, $spent);
$start->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param PiggyBank $piggyBank
*
@ -542,6 +561,9 @@ class GoogleChartController extends Controller
$chart->addColumn('Income', 'number');
$chart->addColumn('Expenses', 'number');
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
// get report query interface.
$end = clone $start;
@ -550,14 +572,14 @@ class GoogleChartController extends Controller
$currentEnd = clone $start;
$currentEnd->endOfMonth();
// total income:
$income = $query->incomeByPeriod($start, $currentEnd);
$income = $query->incomeByPeriod($start, $currentEnd, $showSharedReports);
$incomeSum = 0;
foreach ($income as $entry) {
$incomeSum += floatval($entry->amount);
}
// total expenses:
$expense = $query->journalsByExpenseAccount($start, $currentEnd);
$expense = $query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports);
$expenseSum = 0;
foreach ($expense as $entry) {
$expenseSum += floatval($entry->amount);
@ -591,6 +613,9 @@ class GoogleChartController extends Controller
$chart->addColumn('Income', 'number');
$chart->addColumn('Expenses', 'number');
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
$income = 0;
$expense = 0;
$count = 0;
@ -601,14 +626,14 @@ class GoogleChartController extends Controller
$currentEnd = clone $start;
$currentEnd->endOfMonth();
// total income:
$incomeResult = $query->incomeByPeriod($start, $currentEnd);
$incomeResult = $query->incomeByPeriod($start, $currentEnd, $showSharedReports);
$incomeSum = 0;
foreach ($incomeResult as $entry) {
$incomeSum += floatval($entry->amount);
}
// total expenses:
$expenseResult = $query->journalsByExpenseAccount($start, $currentEnd);
$expenseResult = $query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports);
$expenseSum = 0;
foreach ($expenseResult as $entry) {
$expenseSum += floatval($entry->amount);

View File

@ -1,21 +1,19 @@
<?php namespace FireflyIII\Http\Controllers;
use Cache;
use ErrorException;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Http\Request;
use League\CommonMark\CommonMarkConverter;
use Route;
use Response;
use Cache;
use Route;
/**
* Class HelpController
*
* @package FireflyIII\Http\Controllers
*/
class HelpController extends Controller {
class HelpController extends Controller
{
/**
* @param $route
@ -83,7 +81,7 @@ class HelpController extends Controller {
if (strlen(trim($content['text'])) == 0) {
$content['text'] = '<p>There is no help for this route.</p>';
}
$converter = new CommonMarkConverter();
$converter = new CommonMarkConverter();
$content['text'] = $converter->convertToHtml($content['text']);
return $content;

View File

@ -3,11 +3,11 @@
use Auth;
use Cache;
use Carbon\Carbon;
use Navigation;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Input;
use Preferences;
use Redirect;
use Session;
use URL;
/**
* Class HomeController
@ -24,6 +24,21 @@ class HomeController extends Controller
{
}
public function dateRange()
{
$start = new Carbon(Input::get('start'));
$end = new Carbon(Input::get('end'));
$diff = $start->diffInDays($end);
if ($diff > 50) {
Session::flash('warning', $diff . ' days of data may take a while to load.');
}
Session::put('start', $start);
Session::put('end', $end);
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
@ -37,9 +52,10 @@ class HomeController extends Controller
/**
* @return \Illuminate\View\View
*/
public function index()
public function index(AccountRepositoryInterface $repository)
{
$count = Auth::user()->accounts()->accountTypeIn(['Asset account', 'Default account'])->count();
$count = $repository->countAssetAccounts();
$title = 'Firefly';
$subTitle = 'What\'s playing?';
$mainTitleIcon = 'fa-fire';
@ -47,25 +63,10 @@ class HomeController extends Controller
$frontPage = Preferences::get('frontPageAccounts', []);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
if ($frontPage->data == []) {
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']);
} else {
$accounts = Auth::user()->accounts()->whereIn('id', $frontPage->data)->get(['accounts.*']);
}
$accounts = $repository->getFrontpageAccounts($frontPage);
foreach ($accounts as $account) {
$set = Auth::user()
->transactionjournals()
->with(['transactions', 'transactioncurrency', 'transactiontype'])
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id)
->where('date', '>=', $start->format('Y-m-d'))
->where('date', '<=', $end->format('Y-m-d'))
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC')
->take(10)
->get(['transaction_journals.*']);
$set = $repository->getFrontpageTransactions($account, $start, $end);
if (count($set) > 0) {
$transactions[] = [$set, $account];
}
@ -76,49 +77,5 @@ class HomeController extends Controller
return view('index', compact('count', 'title', 'subTitle', 'mainTitleIcon', 'transactions'));
}
/**
* @param string $range
*
* @return mixed
*/
public function rangeJump($range)
{
$valid = ['1D', '1W', '1M', '3M', '6M', '1Y',];
if (in_array($range, $valid)) {
Preferences::set('viewRange', $range);
Session::forget('range');
}
return Redirect::to(URL::previous());
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function sessionNext()
{
$range = Session::get('range');
$start = Session::get('start');
Session::put('start', Navigation::jumpToNext($range, clone $start));
return Redirect::to(URL::previous());
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function sessionPrev()
{
$range = Session::get('range');
$start = Session::get('start');
Session::put('start', Navigation::jumpToPrevious($range, clone $start));
return Redirect::to(URL::previous());
}
}

View File

@ -1,20 +1,113 @@
<?php namespace FireflyIII\Http\Controllers;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Response;
use Amount;
use Auth;
use DB;
use FireflyIII\Http\Requests;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Input;
use Preferences;
use Response;
use Session;
/**
* Class JsonController
*
* @package FireflyIII\Http\Controllers
*/
class JsonController extends Controller {
class JsonController extends Controller
{
/**
*
*/
public function box(BillRepositoryInterface $repository)
{
$amount = 0;
$start = Session::get('start');
$end = Session::get('end');
$box = 'empty';
switch (Input::get('box')) {
case 'in':
$box = Input::get('box');
$in = Auth::user()->transactionjournals()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->before($end)
->after($start)
->transactionTypes(['Deposit'])
->where('transactions.amount', '>', 0)
->first([DB::Raw('SUM(transactions.amount) as `amount`')]);
if (!is_null($in)) {
$amount = floatval($in->amount);
}
break;
case 'out':
$box = Input::get('box');
$in = Auth::user()->transactionjournals()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->before($end)
->after($start)
->transactionTypes(['Withdrawal'])
->where('transactions.amount', '>', 0)
->first([DB::Raw('SUM(transactions.amount) as `amount`')]);
if (!is_null($in)) {
$amount = floatval($in->amount);
}
break;
case 'bills-unpaid':
$box = 'bills-unpaid';
$bills = Auth::user()->bills()->where('active', 1)->get();
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
if ($count == 0) {
$amount += floatval($bill->amount_max + $bill->amount_min / 2);
}
}
}
break;
case 'bills-paid':
$box = 'bills-paid';
// these two functions are the same as the chart TODO
$bills = Auth::user()->bills()->where('active', 1)->get();
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
if ($count != 0) {
$journal = $bill->transactionjournals()->with('transactions')->before($range['end'])->after($range['start'])->first();
$paid['items'][] = $journal->description;
$currentAmount = 0;
foreach ($journal->transactions as $t) {
if (floatval($t->amount) > 0) {
$currentAmount = floatval($t->amount);
}
}
$amount += $currentAmount;
}
}
}
}
return Response::json(['box' => $box, 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
}
/**
* Returns a list of categories.
*
@ -22,15 +115,13 @@ class JsonController extends Controller {
*/
public function categories()
{
$list = Auth::user()->categories()->orderBy('name','ASC')->get();
$return = [];
$list = Auth::user()->categories()->orderBy('name', 'ASC')->get();
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
}
return Response::json($return);
}
/**
@ -40,8 +131,8 @@ class JsonController extends Controller {
*/
public function expenseAccounts()
{
$list = Auth::user()->accounts()->accountTypeIn(['Expense account', 'Beneficiary account'])->get();
$return = [];
$list = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Expense account', 'Beneficiary account'])->get();
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
}
@ -55,8 +146,8 @@ class JsonController extends Controller {
*/
public function revenueAccounts()
{
$list = Auth::user()->accounts()->accountTypeIn(['Revenue account'])->get();
$return = [];
$list = Auth::user()->accounts()->accountTypeIn(['Revenue account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
}
@ -65,4 +156,27 @@ class JsonController extends Controller {
}
/**
* @return \Symfony\Component\HttpFoundation\Response
*/
public function showSharedReports()
{
$pref = Preferences::get('showSharedReports', false);
return Response::json(['value' => $pref->data]);
}
/**
* @return \Symfony\Component\HttpFoundation\Response
*/
public function setSharedReports()
{
$pref = Preferences::get('showSharedReports', false);
$new = !$pref->data;
Preferences::set('showSharedReports', $new);
return Response::json(['value' => $new]);
}
}

View File

@ -9,6 +9,7 @@ use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\PiggyBankFormRequest;
use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Support\Collection;
@ -62,7 +63,9 @@ class PiggyBankController extends Controller
{
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']));
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
);
$subTitle = 'Create new piggy bank';
$subTitleIcon = 'fa-plus';
@ -78,7 +81,7 @@ class PiggyBankController extends Controller
{
$subTitle = 'Delete "' . e($piggyBank->name) . '"';
return view('piggy_banks.delete', compact('piggyBank', 'subTitle'));
return view('piggy-banks.delete', compact('piggyBank', 'subTitle'));
}
/**
@ -90,9 +93,9 @@ class PiggyBankController extends Controller
{
Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.');
$this->_repository->destroy($piggyBank);
$piggyBank->delete();
return Redirect::route('piggy_banks.index');
return Redirect::route('piggy-banks.index');
}
/**
@ -106,7 +109,9 @@ class PiggyBankController extends Controller
{
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']));
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
);
$subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"';
$subTitleIcon = 'fa-pencil';
@ -124,7 +129,7 @@ class PiggyBankController extends Controller
'targetamount' => $piggyBank->targetamount,
'targetdate' => $targetDate,
'reminder' => $piggyBank->reminder,
'remind_me' => intval($piggyBank->remind_me) == 1 || !is_null($piggyBank->reminder) ? true : false
'remind_me' => intval($piggyBank->remind_me) == 1 && !is_null($piggyBank->reminder) ? true : false
];
Session::flash('preFilled', $preFilled);
@ -191,6 +196,9 @@ class PiggyBankController extends Controller
$repetition->currentamount += $amount;
$repetition->save();
// create event.
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
/*
* Create event!
*/
@ -220,6 +228,8 @@ class PiggyBankController extends Controller
$repetition->currentamount -= $amount;
$repetition->save();
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount * -1, 'piggy_bank_id' => $piggyBank->id]);
/*
* Create event!
*/
@ -278,12 +288,18 @@ class PiggyBankController extends Controller
'targetamount' => floatval($request->get('targetamount')),
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
'reminder' => $request->get('reminder'),
'remind_me' => $request->get('remind_me'),
];
$piggyBank = $repository->store($piggyBankData);
Session::flash('success', 'Stored piggy bank "' . e($piggyBank->name) . '".');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('piggy-banks.create')->withInput();
}
return Redirect::route('piggy-banks.index');
}
@ -299,21 +315,28 @@ class PiggyBankController extends Controller
$piggyBankData = [
'repeats' => false,
'name' => $request->get('name'),
'startdate' => is_null($piggyBank->startdate) ? $piggyBank->created_at : $piggyBank->startdate,
'account_id' => intval($request->get('account_id')),
'targetamount' => floatval($request->get('targetamount')),
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
'reminder' => $request->get('reminder'),
'remind_me' => $request->get('remind_me')
];
$piggyBank = $repository->update($piggyBank, $piggyBankData);
Session::flash('success', 'Updated piggy bank "' . e($piggyBank->name) . '".');
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('piggy-banks.edit', $piggyBank->id);
}
return Redirect::route('piggy-banks.index');
}
}

View File

@ -1,21 +1,20 @@
<?php namespace FireflyIII\Http\Controllers;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Http\Request;
use View;
use Auth;
use Preferences;
use FireflyIII\Http\Requests;
use Input;
use Session;
use Preferences;
use Redirect;
use Session;
use View;
/**
* Class PreferencesController
*
* @package FireflyIII\Http\Controllers
*/
class PreferencesController extends Controller {
class PreferencesController extends Controller
{
/**
*
@ -32,7 +31,7 @@ class PreferencesController extends Controller {
*/
public function index()
{
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']);
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$viewRange = Preferences::get('viewRange', '1M');
$viewRangeValue = $viewRange->data;
$frontPage = Preferences::get('frontPageAccounts', []);

View File

@ -1,15 +1,16 @@
<?php namespace FireflyIII\Http\Controllers;
use Amount;
use Auth;
use FireflyIII\Http\Requests;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Support\Collection;
use Response;
use Input;
use Redirect;
use Response;
use URL;
/**
* Class RelatedController
@ -37,11 +38,12 @@ class RelatedController extends Controller
}
}
}
$unique = array_unique($ids);
$unique = array_unique($ids);
$journals = new Collection;
if (count($unique) > 0) {
$set = Auth::user()->transactionjournals()->whereIn('id', $unique)->get();
$set->each(
$journals = Auth::user()->transactionjournals()->whereIn('id', $unique)->get();
$journals->each(
function (TransactionJournal $journal) {
/** @var Transaction $t */
foreach ($journal->transactions()->get() as $t) {
@ -52,11 +54,38 @@ class RelatedController extends Controller
}
);
return Response::json($set->toArray());
} else {
return Response::json((new Collection)->toArray());
}
$parent = $journal;
return view('related.alreadyRelated', compact('parent', 'journals'));
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param TransactionJournal $parentJournal
* @param TransactionJournal $childJournal
*
* @return \Illuminate\Http\JsonResponse
* @throws Exception
*/
public function getRemoveRelation(TransactionJournal $parentJournal, TransactionJournal $childJournal)
{
$groups = $parentJournal->transactiongroups()->get();
/** @var TransactionGroup $group */
foreach ($groups as $group) {
foreach ($group->transactionjournals()->get() as $loopJournal) {
if ($loopJournal->id == $childJournal->id) {
// remove from group:
$group->transactionjournals()->detach($childJournal);
}
}
if ($group->transactionjournals()->count() == 1) {
$group->delete();
}
}
return Redirect::to(URL::previous());
}
/**
@ -137,20 +166,12 @@ class RelatedController extends Controller
{
$search = e(trim(Input::get('searchValue')));
$parent = $journal;
$result = $repository->searchRelated($search, $journal);
$result->each(
function (TransactionJournal $journal) {
/** @var Transaction $t */
foreach ($journal->transactions()->get() as $t) {
if ($t->amount > 0) {
$journal->amount = $t->amount;
}
}
}
);
$journals = $repository->searchRelated($search, $journal);
return view('related.searchResult', compact('journals', 'search', 'parent'));
return Response::json($result->toArray());
}
}

View File

@ -0,0 +1,128 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use FireflyIII\Helpers\Reminders\ReminderHelperInterface;
use FireflyIII\Http\Requests;
use FireflyIII\Models\Reminder;
use Redirect;
use Session;
use URL;
/**
* Class ReminderController
*
* @package FireflyIII\Http\Controllers
*/
class ReminderController extends Controller
{
/**
* @param Reminder $reminder
*/
public function act(Reminder $reminder)
{
$data = [
'description' => 'Money for piggy bank "' . $reminder->remindersable->name . '"',
'amount' => round($reminder->metadata->perReminder, 2),
'account_to_id' => $reminder->remindersable->account_id,
'piggy_bank_id' => $reminder->remindersable_id,
'reminder_id' => $reminder->id,
];
Session::flash('_old_input', $data);
return Redirect::route('transactions.create', 'transfer');
}
/**
* @param Reminder $reminder
*/
public function dismiss(Reminder $reminder)
{
$reminder->notnow = true;
$reminder->save();
return Redirect::to(URL::previous());
}
/**
*
*/
public function index(ReminderHelperInterface $helper)
{
$reminders = Auth::user()->reminders()->get();
$reminders->each(
function (Reminder $reminder) use ($helper) {
$reminder->description = $helper->getReminderText($reminder);
}
);
$today = new Carbon;
// active reminders:
$active = $reminders->filter(
function (Reminder $reminder) use ($today) {
if ($reminder->notnow === false && $reminder->active === true && $reminder->startdate <= $today && $reminder->enddate >= $today) {
return $reminder;
}
}
);
// expired reminders:
$expired = $reminders->filter(
function (Reminder $reminder) use ($today) {
if ($reminder->notnow === false && $reminder->active === true && $reminder->startdate > $today || $reminder->enddate < $today) {
return $reminder;
}
}
);
// inactive reminders
$inactive = $reminders->filter(
function (Reminder $reminder) use ($today) {
if ($reminder->active === false) {
return $reminder;
}
}
);
// dismissed reminders
$dismissed = $reminders->filter(
function (Reminder $reminder) use ($today) {
if ($reminder->notnow === true) {
return $reminder;
}
}
);
$title = 'Reminders';
$mainTitleIcon = 'fa-clock-o';
return view('reminders.index', compact('dismissed', 'expired', 'inactive', 'active', 'title', 'mainTitleIcon'));
}
/**
* @param Reminder $reminder
*/
public function show(Reminder $reminder)
{
$title = 'Reminder';
$mainTitleIcon = 'fa-clock-o';
if ($reminder->notnow === true) {
$subTitle = 'Dismissed reminder';
} else {
$subTitle = 'Reminder';
}
$subTitle .= ' for piggy bank "' . $reminder->remindersable->name . '"';
return view('reminders.show', compact('reminder', 'title', 'subTitle', 'mainTitleIcon'));
}
}

View File

@ -36,7 +36,9 @@ class RepeatedExpenseController extends Controller
public function create()
{
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']));
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
);
return view('repeatedExpense.create', compact('accounts', 'periods'))->with('subTitle', 'Create new repeated expense')->with(
'subTitleIcon', 'fa-plus'
@ -79,7 +81,9 @@ class RepeatedExpenseController extends Controller
{
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']));
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
);
$subTitle = 'Edit repeated expense "' . e($repeatedExpense->name) . '"';
$subTitleIcon = 'fa-pencil';
@ -183,7 +187,7 @@ class RepeatedExpenseController extends Controller
'rep_length' => $request->get('rep_length'),
'rep_every' => intval($request->get('rep_every')),
'rep_times' => intval($request->get('rep_times')),
'remind_me' => intval($request->get('remind_me')) == 1 ? true : false ,
'remind_me' => intval($request->get('remind_me')) == 1 ? true : false,
'reminder' => $request->get('reminder'),
];

View File

@ -7,7 +7,10 @@ use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Http\Requests;
use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Database\Query\JoinClause;
use Preferences;
use Session;
use Steam;
use View;
@ -49,17 +52,22 @@ class ReportController extends Controller
$end->endOfMonth();
$start->subDay();
// shared accounts preference:
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
$dayEarly = clone $date;
$subTitle = 'Budget report for ' . $date->format('F Y');
$subTitleIcon = 'fa-calendar';
$dayEarly = $dayEarly->subDay();
$accounts = $query->getAllAccounts($start, $end);
$accounts = $query->getAllAccounts($start, $end, $showSharedReports);
$start->addDay();
$accounts->each(
function (Account $account) use ($start, $end, $query) {
$budgets = $query->getBudgetSummary($account, $start, $end);
$balancedAmount = $query->balancedTransactionsList($account, $start, $end);
$balancedAmount = $query->balancedTransactionsSum($account, $start, $end);
$array = [];
foreach ($budgets as $budget) {
$id = intval($budget->id);
@ -87,24 +95,27 @@ class ReportController extends Controller
)
->get(['budgets.*', 'budget_limits.amount as amount']);
$budgets = Steam::makeArray($set);
$amountSet = $query->journalsByBudget($start, $end);
$amountSet = $query->journalsByBudget($start, $end, $showSharedReports);
$amounts = Steam::makeArray($amountSet);
$budgets = Steam::mergeArrays($budgets, $amounts);
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
$budgets[0]['amount'] = isset($budgets[0]['amount']) ? $budgets[0]['amount'] : 0.0;
$budgets[0]['name'] = 'No budget';
// find transactions to shared expense accounts, which are without a budget by default:
$transfers = $query->sharedExpenses($start, $end);
foreach ($transfers as $transfer) {
$budgets[0]['spent'] += floatval($transfer->amount) * -1;
// find transactions to shared asset accounts, which are without a budget by default:
// which is only relevant when shared asset accounts are hidden.
if ($showSharedReports === false) {
$transfers = $query->sharedExpenses($start, $end);
foreach ($transfers as $transfer) {
$budgets[0]['spent'] += floatval($transfer->amount) * -1;
}
}
/**
* End getBudgetsForMonth DONE
*/
return view('reports.budget', compact('subTitle', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly'));
return view('reports.budget', compact('subTitle', 'year', 'month', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly'));
}
@ -115,7 +126,7 @@ class ReportController extends Controller
*/
public function index(ReportHelperInterface $helper)
{
$start = $helper->firstDate();
$start = Session::get('first');
$months = $helper->listOfMonths($start);
$years = $helper->listOfYears($start);
$title = 'Reports';
@ -124,6 +135,87 @@ class ReportController extends Controller
return view('reports.index', compact('years', 'months', 'title', 'mainTitleIcon'));
}
/**
* @param Account $account
* @param string $year
* @param string $month
*
* @return \Illuminate\View\View
*/
public function modalBalancedTransfers(Account $account, $year = '2014', $month = '1', ReportQueryInterface $query)
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return view('error')->with('message', 'Invalid date');
}
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
$journals = $query->balancedTransactionsList($account, $start, $end);
return view('reports.modal-journal-list', compact('journals'));
}
/**
* @param Account $account
* @param string $year
* @param string $month
* @param ReportQueryInterface $query
*
* @return View
*/
public function modalLeftUnbalanced(Account $account, $year = '2014', $month = '1', ReportQueryInterface $query)
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return view('error')->with('message', 'Invalid date');
}
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
$set = $query->getTransactionsWithoutBudget($account, $start, $end);
$journals = $set->filter(
function (TransactionJournal $journal) {
$count = $journal->transactiongroups()->where('relation', 'balance')->count();
if ($count == 0) {
return $journal;
}
}
);
return view('reports.modal-journal-list', compact('journals'));
}
/**
* @param Account $account
* @param string $year
* @param string $month
*
* @return \Illuminate\View\View
*/
public function modalNoBudget(Account $account, $year = '2014', $month = '1', ReportQueryInterface $query)
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return view('error')->with('message', 'Invalid date');
}
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
$journals = $query->getTransactionsWithoutBudget($account, $start, $end);
return view('reports.modal-journal-list', compact('journals'));
}
/**
* @param string $year
* @param string $month
@ -142,6 +234,9 @@ class ReportController extends Controller
$subTitleIcon = 'fa-calendar';
$displaySum = true; // to show sums in report.
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
/**
*
@ -157,14 +252,14 @@ class ReportController extends Controller
/**
* Start getIncomeForMonth DONE
*/
$income = $query->incomeByPeriod($start, $end);
$income = $query->incomeByPeriod($start, $end, $showSharedReports);
/**
* End getIncomeForMonth DONE
*/
/**
* Start getExpenseGroupedForMonth DONE
*/
$set = $query->journalsByExpenseAccount($start, $end);
$set = $query->journalsByExpenseAccount($start, $end, $showSharedReports);
$expenses = Steam::makeArray($set);
$expenses = Steam::sortArray($expenses);
$expenses = Steam::limitArray($expenses, 10);
@ -182,7 +277,7 @@ class ReportController extends Controller
)
->get(['budgets.*', 'budget_limits.amount as amount']);
$budgets = Steam::makeArray($set);
$amountSet = $query->journalsByBudget($start, $end);
$amountSet = $query->journalsByBudget($start, $end, $showSharedReports);
$amounts = Steam::makeArray($amountSet);
$budgets = Steam::mergeArrays($budgets, $amounts);
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
@ -190,9 +285,11 @@ class ReportController extends Controller
$budgets[0]['name'] = 'No budget';
// find transactions to shared expense accounts, which are without a budget by default:
$transfers = $query->sharedExpenses($start, $end);
foreach ($transfers as $transfer) {
$budgets[0]['spent'] += floatval($transfer->amount) * -1;
if ($showSharedReports === false) {
$transfers = $query->sharedExpenses($start, $end);
foreach ($transfers as $transfer) {
$budgets[0]['spent'] += floatval($transfer->amount) * -1;
}
}
/**
@ -206,9 +303,13 @@ class ReportController extends Controller
$categories = Steam::makeArray($result);
// all transfers
$result = $query->sharedExpensesByCategory($start, $end);
$transfers = Steam::makeArray($result);
$merged = Steam::mergeArrays($categories, $transfers);
if ($showSharedReports === false) {
$result = $query->sharedExpensesByCategory($start, $end);
$transfers = Steam::makeArray($result);
$merged = Steam::mergeArrays($categories, $transfers);
} else {
$merged = $categories;
}
// sort.
$sorted = Steam::sortNegativeArray($merged);
@ -221,7 +322,7 @@ class ReportController extends Controller
/**
* Start getAccountsForMonth
*/
$list = $query->accountList();
$list = $query->accountList($showSharedReports);
$accounts = [];
/** @var Account $account */
foreach ($list as $account) {
@ -262,16 +363,19 @@ class ReportController extends Controller
} catch (Exception $e) {
return view('error')->with('message', 'Invalid date.');
}
$date = new Carbon('01-01-' . $year);
$end = clone $date;
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
$date = new Carbon('01-01-' . $year);
$end = clone $date;
$end->endOfYear();
$title = 'Reports';
$subTitle = $year;
$subTitleIcon = 'fa-bar-chart';
$mainTitleIcon = 'fa-line-chart';
$balances = $helper->yearBalanceReport($date);
$groupedIncomes = $query->journalsByRevenueAccount($date, $end);
$groupedExpenses = $query->journalsByExpenseAccount($date, $end);
$balances = $helper->yearBalanceReport($date, $showSharedReports);
$groupedIncomes = $query->journalsByRevenueAccount($date, $end, $showSharedReports);
$groupedExpenses = $query->journalsByExpenseAccount($date, $end, $showSharedReports);
//$groupedExpenses = $helper-> expensesGroupedByAccount($date, $end, 15);

View File

@ -1,10 +1,7 @@
<?php namespace FireflyIII\Http\Controllers;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Support\Search\SearchInterface;
use Illuminate\Http\Request;
use Input;
/**
@ -12,7 +9,8 @@ use Input;
*
* @package FireflyIII\Http\Controllers
*/
class SearchController extends Controller {
class SearchController extends Controller
{
/**
* Results always come in the form of an array [results, count, fullCount]
*/

View File

@ -3,13 +3,14 @@
use Auth;
use Carbon\Carbon;
use ExpandedForm;
use FireflyIII\Events\JournalCreated;
use FireflyIII\Events\JournalSaved;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\JournalFormRequest;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Input;
use Redirect;
use Session;
@ -41,7 +42,9 @@ class TransactionController extends Controller
public function create($what = 'deposit')
{
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->where('active', 1)->orderBy('name', 'DESC')->get(['accounts.*'])
Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->orderBy('name', 'ASC')->where(
'active', 1
)->orderBy('name', 'DESC')->get(['accounts.*'])
);
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = '(no budget)';
@ -118,7 +121,9 @@ class TransactionController extends Controller
{
$what = strtolower($journal->transactiontype->type);
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->where('active', 1)->orderBy('name', 'DESC')->get(['accounts.*'])
Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->where('active', 1)->orderBy(
'name', 'DESC'
)->get(['accounts.*'])
);
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = '(no budget)';
@ -143,7 +148,7 @@ class TransactionController extends Controller
}
if ($journal->piggyBankEvents()->count() > 0) {
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->first()->piggy_bank_id;
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->orderBy('date', 'DESC')->first()->piggy_bank_id;
}
$preFilled['amount'] = 0;
@ -227,25 +232,15 @@ class TransactionController extends Controller
$t->after = $t->before + $t->amount;
}
);
$members = new Collection;
/** @var TransactionGroup $group */
foreach ($journal->transactiongroups()->get() as $group) {
/** @var TransactionJournal $loopJournal */
foreach ($group->transactionjournals()->get() as $loopJournal) {
if ($loopJournal->id != $journal->id) {
$members->push($loopJournal);
}
}
}
return view('transactions.show', compact('journal', 'members'))->with(
return view('transactions.show', compact('journal'))->with(
'subTitle', e($journal->transactiontype->type) . ' "' . e($journal->description) . '"'
);
}
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository)
{
$journalData = [
'what' => $request->get('what'),
'description' => $request->get('description'),
@ -264,8 +259,21 @@ class TransactionController extends Controller
$journal = $repository->store($journalData);
event(new JournalSaved($journal));
event(new JournalCreated($journal, intval($request->get('piggy_bank_id'))));
if (intval($request->get('reminder_id')) > 0) {
$reminder = Auth::user()->reminders()->find($request->get('reminder_id'));
$reminder->active = 0;
$reminder->save();
}
Session::flash('success', 'New transaction "' . $journal->description . '" stored!');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('transactions.create', $request->input('what'))->withInput();
}
return Redirect::route('transactions.index', $request->input('what'));
}
@ -281,6 +289,7 @@ class TransactionController extends Controller
public function update(TransactionJournal $journal, JournalFormRequest $request, JournalRepositoryInterface $repository)
{
$journalData = [
'what' => $request->get('what'),
'description' => $request->get('description'),
@ -298,8 +307,16 @@ class TransactionController extends Controller
];
$repository->update($journal, $journalData);
event(new JournalSaved($journal));
// update, get events by date and sort DESC
Session::flash('success', 'Transaction "' . e($journalData['description']) . '" updated.');
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('transactions.edit', $journal->id);
}
return Redirect::route('transactions.index', $journalData['what']);
}

View File

@ -36,6 +36,7 @@ class Kernel extends HttpKernel
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'FireflyIII\Http\Middleware\RedirectIfAuthenticated',
'range' => 'FireflyIII\Http\Middleware\Range',
'reminders' => 'FireflyIII\Http\Middleware\Reminders',
];
}

View File

@ -9,6 +9,7 @@ use Illuminate\Contracts\Auth\Guard;
use Navigation;
use Preferences;
use Session;
use View;
/**
* Class SessionFilter
@ -46,25 +47,36 @@ class Range
public function handle($request, Closure $theNext)
{
if ($this->auth->check()) {
// user's view range comes from preferences, gets set in session:
/** @var \FireflyIII\Models\Preference $viewRange */
$viewRange = Preferences::get('viewRange', '1M');
// ignore preference. set the range to be the current month:
if (!Session::has('start') && !Session::has('end')) {
// the start and end date are checked and stored:
$start = Session::has('start') ? Session::get('start') : new Carbon;
$start = Navigation::updateStartDate($viewRange->data, $start);
$end = Navigation::updateEndDate($viewRange->data, $start);
$period = Navigation::periodName($viewRange->data, $start);
$prev = Navigation::jumpToPrevious($viewRange->data, clone $start);
$next = Navigation::jumpToNext($viewRange->data, clone $start);
/** @var \FireflyIII\Models\Preference $viewRange */
$viewRange = Preferences::get('viewRange', '1M');
$start = Session::has('start') ? Session::get('start') : new Carbon;
$start = Navigation::updateStartDate($viewRange->data, $start);
$end = Navigation::updateEndDate($viewRange->data, $start);
Session::put('start', $start);
Session::put('end', $end);
}
if (!Session::has('first')) {
$journal = $this->auth->user()->transactionjournals()->orderBy('date', 'ASC')->first(['transaction_journals.*']);
if ($journal) {
Session::put('first', $journal->date);
} else {
Session::put('first', Carbon::now());
}
}
// set current / next / prev month.
$current = Carbon::now()->format('F Y');
$next = Carbon::now()->endOfMonth()->addDay()->format('F Y');
$prev = Carbon::now()->startOfMonth()->subDay()->format('F Y');
View::share('currentMonthName', $current);
View::share('previousMonthName', $prev);
View::share('nextMonthName', $next);
Session::put('range', $viewRange->data);
Session::put('start', $start);
Session::put('end', $end);
Session::put('period', $period);
Session::put('prev', Navigation::periodName($viewRange->data, $prev));
Session::put('next', Navigation::periodName($viewRange->data, $next));
}

View File

@ -0,0 +1,91 @@
<?php
namespace FireflyIII\Http\Middleware;
use App;
use Carbon\Carbon;
use Closure;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Reminder;
use Illuminate\Contracts\Auth\Guard;
use View;
/**
* Class Reminders
*
* @package FireflyIII\Http\Middleware
*/
class Reminders
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->check()) {
// do reminders stuff.
$piggyBanks = $this->auth->user()->piggyBanks()->where('remind_me', 1)->get();
$today = new Carbon;
/** @var \FireflyIII\Helpers\Reminders\ReminderHelperInterface $helper */
$helper = App::make('FireflyIII\Helpers\Reminders\ReminderHelperInterface');
/** @var PiggyBank $piggyBank */
foreach ($piggyBanks as $piggyBank) {
$ranges = $helper->getReminderRanges($piggyBank);
foreach ($ranges as $range) {
if ($today < $range['end'] && $today > $range['start']) {
// create a reminder here!
$helper->createReminder($piggyBank, $range['start'], $range['end']);
// stop looping, we're done.
break;
}
}
}
// delete invalid reminders
$reminders = $this->auth->user()->reminders()->get();
foreach($reminders as $reminder) {
if(is_null($reminder->remindersable)) {
$reminder->delete();
}
}
// get and list active reminders:
$reminders = $this->auth->user()->reminders()->today()->get();
$reminders->each(
function (Reminder $reminder) use ($helper) {
$reminder->description = $helper->getReminderText($reminder);
}
);
View::share('reminders', $reminders);
}
return $next($request);
}
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 25/02/15
* Time: 12:29
*/
namespace FireflyIII\Http\Requests;
@ -33,8 +27,8 @@ class BillFormRequest extends Request
public function rules()
{
$nameRule = 'required|between:1,255|uniqueForUser:bills,name';
if(intval(Input::get('id')) > 0) {
$nameRule .= ','.intval(Input::get('id'));
if (intval(Input::get('id')) > 0) {
$nameRule = 'required|between:1,255';
}
$rules = [

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 25/02/15
* Time: 12:29
*/
namespace FireflyIII\Http\Requests;

View File

@ -35,6 +35,7 @@ class JournalFormRequest extends Request
'what' => 'required|in:withdrawal,deposit,transfer|exists:transaction_types,type',
'amount' => 'numeric|required|min:0.01',
'date' => 'required|date',
'reminder_id' => 'numeric|exists:reminders,id',
'amount_currency_id' => 'required|exists:transaction_currencies,id',
];

View File

@ -51,7 +51,7 @@ class PiggyBankFormRequest extends Request
'rep_times' => 'integer|min:0|max:99',
'reminder' => 'in:day,week,quarter,month,year',
'reminder_skip' => 'integer|min:0|max:99',
'remind_me' => 'boolean',
'remind_me' => 'boolean|piggyBankReminder',
'order' => 'integer|min:1',
];

View File

@ -7,6 +7,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Category;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank;
@ -239,8 +240,17 @@ Breadcrumbs::register(
// reminders
Breadcrumbs::register(
'reminders.show', function (Generator $breadcrumbs, Reminder $reminder) {
'reminders.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Reminders', route('reminders.index'));
}
);
// reminders
Breadcrumbs::register(
'reminders.show', function (Generator $breadcrumbs, Reminder $reminder) {
$breadcrumbs->parent('reminders.index');
$breadcrumbs->push('Reminder #' . $reminder->id, route('reminders.show', $reminder->id));
}

View File

@ -4,9 +4,10 @@ use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\PiggyBank;
// models
@ -89,6 +90,16 @@ Route::bind(
}
);
Route::bind(
'reminder', function ($value, $route) {
if (Auth::check()) {
return Reminder::where('id', $value)->where('user_id', Auth::user()->id)->first();
}
return null;
}
);
Route::bind(
'limitrepetition', function ($value, $route) {
if (Auth::check()) {
@ -135,7 +146,7 @@ Route::get('/register', ['uses' => 'Auth\AuthController@getRegister', 'as' => 'r
Route::controllers(
[
'auth' => 'Auth\AuthController',
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]
);
@ -145,12 +156,10 @@ Route::controllers(
* Home Controller
*/
Route::group(
['middleware' => ['auth', 'range']], function () {
['middleware' => ['auth', 'range', 'reminders']], function () {
Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']);
Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']);
Route::get('/prev', ['uses' => 'HomeController@sessionPrev', 'as' => 'sessionPrev']);
Route::get('/next', ['uses' => 'HomeController@sessionNext', 'as' => 'sessionNext']);
Route::get('/jump/{range}', ['uses' => 'HomeController@rangeJump', 'as' => 'rangeJump']);
Route::post('/daterange', ['uses' => 'HomeController@dateRange', 'as' => 'daterange']);
Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']);
/**
* Account Controller
@ -232,11 +241,12 @@ Route::group(
Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']);
Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending']);
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']);
Route::get('/chart/category/{category}/spending/{year}', ['uses' => 'GoogleChartController@categoriesAndSpending']);
Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']);
Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']);
Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']);
Route::get('/chart/piggy-history/{piggyBank}', ['uses' => 'GoogleChartController@piggyBankHistory']);
Route::get('/chart/category/{category}/period', ['uses' => 'GoogleChartController@categoryPeriodChart']);
Route::get('/chart/category/{category}/overview', ['uses' => 'GoogleChartController@categoryOverviewChart']);
/**
* Help Controller
@ -249,14 +259,17 @@ Route::group(
Route::get('/json/expense-accounts', ['uses' => 'JsonController@expenseAccounts', 'as' => 'json.expense-accounts']);
Route::get('/json/revenue-accounts', ['uses' => 'JsonController@revenueAccounts', 'as' => 'json.revenue-accounts']);
Route::get('/json/categories', ['uses' => 'JsonController@categories', 'as' => 'json.categories']);
Route::get('/json/box', ['uses' => 'JsonController@box', 'as' => 'json.box']);
Route::get('/json/show-shared-reports', 'JsonController@showSharedReports');
Route::get('/json/show-shared-reports/set', 'JsonController@setSharedReports');
/**
* Piggy Bank Controller
*/
Route::get('/piggy-banks', ['uses' => 'PiggyBankController@index', 'as' => 'piggy-banks.index']);
Route::get('/piggy-banks/add/{piggyBank}', ['uses' => 'PiggyBankController@add']); # add money
Route::get('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove']); #remove money
Route::get('/piggy-banks/add/{piggyBank}', ['uses' => 'PiggyBankController@add', 'as' => 'piggy-banks.addMoney']); # add money
Route::get('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove', 'as' => 'piggy-banks.removeMoney']); #remove money
Route::get('/piggy-banks/create', ['uses' => 'PiggyBankController@create', 'as' => 'piggy-banks.create']);
Route::get('/piggy-banks/edit/{piggyBank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy-banks.edit']);
Route::get('/piggy-banks/delete/{piggyBank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy-banks.delete']);
@ -278,7 +291,7 @@ Route::group(
*/
Route::get('/profile', ['uses' => 'ProfileController@index', 'as' => 'profile']);
Route::get('/profile/change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']);
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword','as' => 'change-password-post']);
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword', 'as' => 'change-password-post']);
/**
* Related transactions controller
@ -286,9 +299,19 @@ Route::group(
Route::get('/related/alreadyRelated/{tj}', ['uses' => 'RelatedController@alreadyRelated', 'as' => 'related.alreadyRelated']);
Route::post('/related/relate/{tj}/{tjSecond}', ['uses' => 'RelatedController@relate', 'as' => 'related.relate']);
Route::post('/related/removeRelation/{tj}/{tjSecond}', ['uses' => 'RelatedController@removeRelation', 'as' => 'related.removeRelation']);
Route::get('/related/remove/{tj}/{tjSecond}', ['uses' => 'RelatedController@getRemoveRelation', 'as' => 'related.getRemoveRelation']);
Route::get('/related/related/{tj}', ['uses' => 'RelatedController@related', 'as' => 'related.related']);
Route::post('/related/search/{tj}', ['uses' => 'RelatedController@search', 'as' => 'related.search']);
/**
* Reminder Controller
*/
Route::get('/reminders', ['uses' => 'ReminderController@index', 'as' => 'reminders.index']);
Route::get('/reminder/dismiss/{reminder}', ['uses' => 'ReminderController@dismiss', 'as' => 'reminders.dismiss']);
Route::get('/reminder/act/{reminder}', ['uses' => 'ReminderController@act', 'as' => 'reminders.act']);
Route::get('/reminder/{reminder}', ['uses' => 'ReminderController@show', 'as' => 'reminders.show']);
/**
* Repeated Expenses Controller
*/
@ -309,6 +332,16 @@ Route::group(
Route::get('/reports/{year}/{month}', ['uses' => 'ReportController@month', 'as' => 'reports.month']);
Route::get('/reports/budget/{year}/{month}', ['uses' => 'ReportController@budget', 'as' => 'reports.budget']);
// pop ups for budget report:
Route::get('/reports/modal/{account}/{year}/{month}/no-budget', ['uses' => 'ReportController@modalNoBudget', 'as' => 'reports.no-budget']);
Route::get(
'/reports/modal/{account}/{year}/{month}/balanced-transfers',
['uses' => 'ReportController@modalBalancedTransfers', 'as' => 'reports.balanced-transfers']
);
Route::get(
'/reports/modal/{account}/{year}/{month}/left-unbalanced', ['uses' => 'ReportController@modalLeftUnbalanced', 'as' => 'reports.left-unbalanced']
);
/**
* Search Controller
*/

View File

@ -4,7 +4,7 @@ use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
use Crypt;
/**
* Class Account
*
@ -18,7 +18,7 @@ class Account extends Model
= [
'user_id' => 'required|exists:users,id',
'account_type_id' => 'required|exists:account_types,id',
'name' => 'required|between:1,100|uniqueForUser:accounts,name',
'name' => 'required|between:1,1024|uniqueForUser:accounts,name',
'active' => 'required|boolean'
];
@ -41,6 +41,22 @@ class Account extends Model
}
/**
* @param $value
*
* @return string
*/
public function getNameAttribute($value)
{
if ($this->encrypted) {
return Crypt::decrypt($value);
}
// @codeCoverageIgnoreStart
return $value;
// @codeCoverageIgnoreEnd
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/

View File

@ -14,7 +14,7 @@ class PiggyBank extends Model
{
use SoftDeletes;
protected $fillable = ['repeats', 'name', 'account_id','rep_every', 'rep_times', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder',];
protected $fillable = ['repeats', 'name', 'account_id','rep_every', 'rep_times', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder','remind_me'];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
@ -24,6 +24,15 @@ class PiggyBank extends Model
return $this->belongsTo('FireflyIII\Models\Account');
}
/**
* @param $value
*
* @return int
*/
public function getRemindMeAttribute($value) {
return intval($value) == 1;
}
/**
* Grabs the PiggyBankRepetition that's currently relevant / active
*

View File

@ -10,6 +10,8 @@ use Illuminate\Database\Eloquent\Model;
class PiggyBankEvent extends Model
{
protected $fillable = ['piggy_bank_id', 'transaction_journal_id', 'date', 'amount'];
/**
* @return array
*/

View File

@ -1,7 +1,8 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Carbon\Carbon;
/**
* Class PiggyBankRepetition
*
@ -26,4 +27,25 @@ class PiggyBankRepetition extends Model
return $this->belongsTo('FireflyIII\Models\PiggyBank');
}
/**
* @param EloquentBuilder $query
* @param Carbon $date
*
* @return mixed
*/
public function scopeRelevantOnDate(EloquentBuilder $query, Carbon $date)
{
return $query->where(
function($q) use ($date) {
$q->where('startdate', '>=', $date->format('Y-m-d 00:00:00'));
$q->orWhereNull('startdate');
})
->where(function($q) use ($date) {
$q->where('targetdate', '<=', $date->format('Y-m-d 00:00:00'));
$q->orWhereNull('targetdate');
});
}
}

View File

@ -1,5 +1,7 @@
<?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
/**
@ -10,6 +12,19 @@ use Illuminate\Database\Eloquent\Model;
class Reminder extends Model
{
protected $fillable = ['user_id', 'startdate', 'metadata', 'enddate', 'active', 'notnow', 'remindersable_id', 'remindersable_type',];
/**
* @param $value
*
* @return int
*/
public function getActiveAttribute($value)
{
return intval($value) == 1;
}
/**
* @return array
*/
@ -18,6 +33,26 @@ class Reminder extends Model
return ['created_at', 'updated_at', 'startdate', 'enddate'];
}
/**
* @param $value
*
* @return mixed
*/
public function getMetadataAttribute($value)
{
return json_decode($value);
}
/**
* @param $value
*
* @return bool
*/
public function getNotnowAttribute($value)
{
return intval($value) == 1;
}
/**
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
@ -26,6 +61,34 @@ class Reminder extends Model
return $this->morphTo();
}
/**
* @param EloquentBuilder $query
* @param Carbon $start
* @param Carbon $end
*
* @return $this
*/
public function scopeOnDates(EloquentBuilder $query, Carbon $start, Carbon $end)
{
return $query->where('reminders.startdate', '=', $start->format('Y-m-d 00:00:00'))->where('reminders.enddate', '=', $end->format('Y-m-d 00:00:00'));
}
public function scopeToday(EloquentBuilder $query)
{
$today = new Carbon;
return $query->where('startdate', '<=', $today->format('Y-m-d 00:00:00'))->where('enddate', '>=', $today->format('Y-m-d 00:00:00'))->where('active', 1)
->where('notnow', 0);
}
/**
* @param $value
*/
public function setMetadataAttribute($value)
{
$this->attributes['metadata'] = json_encode($value);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/

View File

@ -1,17 +1,19 @@
<?php namespace FireflyIII\Providers;
use App;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\Facades\Navigation;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Log;
/**
* Class EventServiceProvider
@ -28,12 +30,14 @@ class EventServiceProvider extends ServiceProvider
*/
protected $listen
= [
'event.name' => [
'EventListener',
],
'App\Events\JournalDeleted' => [
'App\Handlers\Events\JournalDeletedHandler@handle',
'FireflyIII\Events\JournalSaved' => [
'FireflyIII\Handlers\Events\RescanJournal',
'FireflyIII\Handlers\Events\UpdateJournalConnection',
],
'FireflyIII\Events\JournalCreated' => [
'FireflyIII\Handlers\Events\ConnectJournalToPiggyBank',
]
];
/**
@ -57,6 +61,8 @@ class EventServiceProvider extends ServiceProvider
}
);
Account::deleted(
function (Account $account) {
@ -68,14 +74,16 @@ class EventServiceProvider extends ServiceProvider
}
);
PiggyBank::created(function(PiggyBank $piggyBank) {
PiggyBank::created(
function (PiggyBank $piggyBank) {
$repetition = new PiggyBankRepetition;
$repetition->piggyBank()->associate($piggyBank);
$repetition->startdate = $piggyBank->startdate;
$repetition->targetdate = $piggyBank->targetdate;
$repetition->startdate = is_null($piggyBank->startdate) ? null : $piggyBank->startdate;
$repetition->targetdate = is_null($piggyBank->targetdate) ? null : $piggyBank->targetdate;
$repetition->currentamount = 0;
$repetition->save();
});
}
);
BudgetLimit::saved(
function (BudgetLimit $budgetLimit) {

View File

@ -64,6 +64,8 @@ class FireflyServiceProvider extends ServiceProvider
$this->app->bind('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface', 'FireflyIII\Repositories\PiggyBank\PiggyBankRepository');
$this->app->bind('FireflyIII\Support\Search\SearchInterface', 'FireflyIII\Support\Search\Search');
$this->app->bind('FireflyIII\Helpers\Reminders\ReminderHelperInterface', 'FireflyIII\Helpers\Reminders\ReminderHelper');
$this->app->bind('FireflyIII\Helpers\Report\ReportHelperInterface', 'FireflyIII\Helpers\Report\ReportHelper');
$this->app->bind('FireflyIII\Helpers\Report\ReportQueryInterface', 'FireflyIII\Helpers\Report\ReportQuery');

View File

@ -10,10 +10,12 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Log;
use Session;
@ -25,6 +27,14 @@ use Session;
class AccountRepository implements AccountRepositoryInterface
{
/**
* @return int
*/
public function countAssetAccounts()
{
return Auth::user()->accounts()->accountTypeIn(['Asset account', 'Default account'])->count();
}
/**
* @param Account $account
*
@ -37,16 +47,53 @@ class AccountRepository implements AccountRepositoryInterface
return true;
}
/**
* @param Preference $preference
*
* @return Collection
*/
public function getFrontpageAccounts(Preference $preference)
{
if ($preference->data == []) {
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
} else {
$accounts = Auth::user()->accounts()->whereIn('id', $preference->data)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
}
return $accounts;
}
/**
* @param Account $account
* @param int $page
* @param string $range
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getJournals(Account $account, $page, $range = 'session')
public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end)
{
$offset = $page * 50;
return Auth::user()
->transactionjournals()
->with(['transactions', 'transactioncurrency', 'transactiontype'])
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id)
->before($end)
->after($start)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC')
->take(10)
->get(['transaction_journals.*']);
}
/**
* @param Account $account
* @param int $page
*
* @return mixed
*/
public function getJournals(Account $account, $page)
{
$offset = ($page - 1) * 50;
$query = Auth::user()
->transactionJournals()
->withRelevantData()
@ -54,10 +101,8 @@ class AccountRepository implements AccountRepositoryInterface
->where('transactions.account_id', $account->id)
->orderBy('date', 'DESC');
if ($range == 'session') {
$query->before(Session::get('end', Carbon::now()->startOfMonth()));
$query->after(Session::get('start', Carbon::now()->startOfMonth()));
}
$query->before(Session::get('end', Carbon::now()->endOfMonth()));
$query->after(Session::get('start', Carbon::now()->startOfMonth()));
$count = $query->count();
$set = $query->take(50)->offset($offset)->get(['transaction_journals.*']);
$paginator = new LengthAwarePaginator($set, $count, 50, $page);
@ -69,6 +114,23 @@ class AccountRepository implements AccountRepositoryInterface
}
/**
* @param Account $account
*
* @return float
*/
public function leftOnAccount(Account $account)
{
$balance = \Steam::balance($account);
/** @var PiggyBank $p */
foreach ($account->piggybanks()->get() as $p) {
$balance -= $p->currentRelevantRep()->currentamount;
}
return $balance;
}
/**
* @param Account $account
*
@ -123,13 +185,7 @@ class AccountRepository implements AccountRepositoryInterface
$account->save();
// update meta data:
/** @var AccountMeta $meta */
foreach ($account->accountMeta()->get() as $meta) {
if ($meta->name == 'accountRole') {
$meta->data = $data['accountRole'];
$meta->save();
}
}
$this->_updateMetadata($account, $data);
$openingBalance = $this->openingBalanceTransaction($account);
@ -285,6 +341,40 @@ class AccountRepository implements AccountRepositoryInterface
}
/**
* @param Account $account
* @param array $data
*/
protected function _updateMetadata(Account $account, array $data)
{
$metaEntries = $account->accountMeta()->get();
$updated = false;
/** @var AccountMeta $entry */
foreach ($metaEntries as $entry) {
if ($entry->name == 'accountRole') {
$entry->data = $data['accountRole'];
$updated = true;
$entry->save();
}
}
if ($updated === false) {
$metaData = new AccountMeta(
[
'account_id' => $account->id,
'name' => 'accountRole',
'data' => $data['accountRole']
]
);
if (!$metaData->isValid()) {
App::abort(500);
}
$metaData->save();
}
}
/**
* @param Account $account
* @param TransactionJournal $journal
@ -310,21 +400,4 @@ class AccountRepository implements AccountRepositoryInterface
return $journal;
}
/**
* @param Account $account
*
* @return float
*/
public function leftOnAccount(Account $account)
{
$balance = \Steam::balance($account);
/** @var PiggyBank $p */
foreach ($account->piggybanks()->get() as $p) {
$balance -= $p->currentRelevantRep()->currentamount;
}
return $balance;
}
}

View File

@ -4,7 +4,9 @@ namespace FireflyIII\Repositories\Account;
use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Preference;
use Illuminate\Support\Collection;
use Carbon\Carbon;
/**
* Interface AccountRepositoryInterface
*
@ -19,14 +21,34 @@ interface AccountRepositoryInterface
*/
public function destroy(Account $account);
/**
* @return int
*/
public function countAssetAccounts();
/**
* @param Preference $preference
*
* @return Collection
*/
public function getFrontpageAccounts(Preference $preference);
/**
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end);
/**
* @param Account $account
* @param int $page
* @param string $range
*
* @return mixed
*/
public function getJournals(Account $account, $page, $range = 'session');
public function getJournals(Account $account, $page);
/**
* @param Account $account

View File

@ -1,18 +1,12 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 25/02/15
* Time: 07:40
*/
namespace FireflyIII\Repositories\Bill;
use Carbon\Carbon;
use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionJournal;
use Navigation;
use Log;
use Navigation;
/**
* Class BillRepository
@ -21,6 +15,54 @@ use Log;
*/
class BillRepository implements BillRepositoryInterface
{
/**
* Every bill repeats itself weekly, monthly or yearly (or whatever). This method takes a date-range (usually the view-range of Firefly itself)
* and returns date ranges that fall within the given range; those ranges are the bills expected. When a bill is due on the 14th of the month and
* you give 1st and the 31st of that month as argument, you'll get one response, matching the range of your bill.
*
* @param Bill $bill
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getRanges(Bill $bill, Carbon $start, Carbon $end)
{
$startOfBill = $bill->date;
$startOfBill = Navigation::startOfPeriod($startOfBill, $bill->repeat_freq);
// all periods of this bill up until the current period:
$billStarts = [];
while ($startOfBill < $end) {
$endOfBill = Navigation::endOfPeriod($startOfBill, $bill->repeat_freq);
$billStarts[] = [
'start' => clone $startOfBill,
'end' => clone $endOfBill,
];
// actually the next one:
$startOfBill = Navigation::addPeriod($startOfBill, $bill->repeat_freq, $bill->skip);
}
// for each
$validRanges = [];
foreach ($billStarts as $dateEntry) {
if ($dateEntry['end'] > $start && $dateEntry['start'] < $end) {
// count transactions for bill in this range (not relevant yet!):
// $count = $bill->transactionjournals()->before($dateEntry['end'])->after($dateEntry['start'])->count();
// if ($count == 0) {
$validRanges[] = $dateEntry;
// }
}
}
return $validRanges;
// echo $bill->name;
// var_dump($validRanges);
}
/**
* @param Bill $bill
*
@ -28,6 +70,7 @@ class BillRepository implements BillRepositoryInterface
*/
public function nextExpectedMatch(Bill $bill)
{
$finalDate = null;
if ($bill->active == 0) {
return $finalDate;
@ -113,7 +156,7 @@ class BillRepository implements BillRepositoryInterface
$wordMatch = true;
Log::debug('word match is true');
} else {
Log::debug('Count: ' . $count.', count(matches): ' . count($matches));
Log::debug('Count: ' . $count . ', count(matches): ' . count($matches));
}

View File

@ -1,13 +1,8 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 25/02/15
* Time: 07:40
*/
namespace FireflyIII\Repositories\Bill;
use Carbon\Carbon;
use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionJournal;
@ -25,6 +20,19 @@ interface BillRepositoryInterface {
*/
public function nextExpectedMatch(Bill $bill);
/**
* Every bill repeats itself weekly, monthly or yearly (or whatever). This method takes a date-range (usually the view-range of Firefly itself)
* and returns date ranges that fall within the given range; those ranges are the bills expected. When a bill is due on the 14th of the month and
* you give 1st and the 31st of that month as argument, you'll get one response, matching the range of your bill.
*
* @param Bill $bill
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getRanges(Bill $bill, Carbon $start, Carbon $end);
/**
* @param array $data
*

View File

@ -267,13 +267,15 @@ class JournalRepository implements JournalRepositoryInterface
// update the from and to transaction.
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($transaction->account_id === $from->id) {
if (floatval($transaction->amount) < 0) {
// this is the from transaction, negative amount:
$transaction->amount = $data['amount'] * -1;
$transaction->amount = $data['amount'] * -1;
$transaction->account_id = $from->id;
$transaction->save();
}
if ($transaction->account_id === $to->id) {
if (floatval($transaction->amount) > 0) {
$transaction->amount = $data['amount'];
$transaction->account_id = $to->id;
$transaction->save();
}
}

View File

@ -2,8 +2,12 @@
namespace FireflyIII\Repositories\PiggyBank;
use Amount;
use Auth;
use Carbon\Carbon;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\Reminder;
use Illuminate\Support\Collection;
use Navigation;
@ -15,49 +19,6 @@ use Navigation;
class PiggyBankRepository implements PiggyBankRepositoryInterface
{
/**
* @param array $data
*
* @return PiggyBank
*/
public function store(array $data)
{
$piggyBank = PiggyBank::create($data);
return $piggyBank;
}
/**
* @param PiggyBank $account
* @param array $data
*
* @return PiggyBank
*/
public function update(PiggyBank $piggyBank, array $data)
{
/**
'rep_length' => $request->get('rep_length'),
'rep_every' => intval($request->get('rep_every')),
'rep_times' => intval($request->get('rep_times')),
'remind_me' => intval($request->get('remind_me')) == 1 ? true : false ,
'reminder' => $request->get('reminder'),
*/
$piggyBank->name = $data['name'];
$piggyBank->account_id = intval($data['account_id']);
$piggyBank->targetamount = floatval($data['targetamount']);
$piggyBank->targetdate = $data['targetdate'];
$piggyBank->reminder = $data['reminder'];
$piggyBank->rep_length = isset($data['rep_length']) ? $data['rep_length'] : null;
$piggyBank->rep_every =isset($data['rep_every']) ? $data['rep_every'] : null;
$piggyBank->rep_times = isset($data['rep_times']) ? $data['rep_times'] : null;
$piggyBank->remind_me = isset($data['remind_me']) ? $data['remind_me'] : null;
$piggyBank->save();
return $piggyBank;
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
@ -126,4 +87,50 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return $part;
}
/**
* @param array $data
*
* @return PiggyBank
*/
public function store(array $data)
{
$data['remind_me'] = isset($data['remind_me']) && $data['remind_me'] == '1' ? true : false;
$piggyBank = PiggyBank::create($data);
return $piggyBank;
}
/**
* @param PiggyBank $account
* @param array $data
*
* @return PiggyBank
*/
public function update(PiggyBank $piggyBank, array $data)
{
/**
* 'rep_length' => $request->get('rep_length'),
* 'rep_every' => intval($request->get('rep_every')),
* 'rep_times' => intval($request->get('rep_times')),
* 'remind_me' => intval($request->get('remind_me')) == 1 ? true : false ,
* 'reminder' => $request->get('reminder'),
*/
$piggyBank->name = $data['name'];
$piggyBank->account_id = intval($data['account_id']);
$piggyBank->targetamount = floatval($data['targetamount']);
$piggyBank->targetdate = $data['targetdate'];
$piggyBank->reminder = $data['reminder'];
$piggyBank->startdate = $data['startdate'];
$piggyBank->rep_length = isset($data['rep_length']) ? $data['rep_length'] : null;
$piggyBank->rep_every = isset($data['rep_every']) ? $data['rep_every'] : null;
$piggyBank->rep_times = isset($data['rep_times']) ? $data['rep_times'] : null;
$piggyBank->remind_me = isset($data['remind_me']) && $data['remind_me'] == '1' ? 1 : 0;
$piggyBank->save();
return $piggyBank;
}
}

View File

@ -4,31 +4,19 @@ namespace FireflyIII\Repositories\PiggyBank;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\Reminder;
use Illuminate\Support\Collection;
use Carbon\Carbon;
/**
* Interface PiggyBankRepositoryInterface
*
* @package FireflyIII\Repositories\PiggyBank
*/
interface PiggyBankRepositoryInterface {
interface PiggyBankRepositoryInterface
{
/**
* @param array $data
*
* @return PiggyBank
*/
public function store(array $data);
/**
* @param PiggyBank $account
* @param array $data
*
* @return PiggyBank
*/
public function update(PiggyBank $piggyBank, array $data);
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
@ -48,4 +36,21 @@ interface PiggyBankRepositoryInterface {
* @return PiggyBankPart
*/
public function createPiggyBankPart(array $data);
/**
* @param array $data
*
* @return PiggyBank
*/
public function store(array $data);
/**
* @param PiggyBank $account
* @param array $data
*
* @return PiggyBank
*/
public function update(PiggyBank $piggyBank, array $data);
}

View File

@ -8,6 +8,7 @@ use Illuminate\Support\MessageBag;
use Input;
use Session;
use View;
use Amount as Amt;
/**
* Class ExpandedForm
@ -17,46 +18,6 @@ use View;
class ExpandedForm
{
/**
* @param $name
* @param null $value
* @param array $options
*
* @return string
*/
public function integer($name, $value = null, array $options = [])
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = '1';
$html = \View::make('form.integer', compact('classes', 'name', 'label', 'value', 'options'))->render();
return $html;
}
/**
* @param $name
* @param null $value
* @param array $options
*
* @return string
*/
public function tags($name, $value = null, array $options = [])
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['data-role'] = 'tagsinput';
$html = \View::make('form.tags', compact('classes', 'name', 'label', 'value', 'options'))->render();
return $html;
}
/**
* @param $name
* @param null $value
@ -72,7 +33,7 @@ class ExpandedForm
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$options['min'] = '0.01';
$defaultCurrency = isset($options['currency']) ? $options['currency'] : \Amount::getDefaultCurrency();
$defaultCurrency = isset($options['currency']) ? $options['currency'] : Amt::getDefaultCurrency();
$currencies = TransactionCurrency::orderBy('code', 'ASC')->get();
$html = View::make('form.amount', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
@ -91,9 +52,19 @@ class ExpandedForm
if (isset($options['label'])) {
return $options['label'];
}
$labels = ['amount_min' => 'Amount (min)', 'amount_max' => 'Amount (max)', 'match' => 'Matches on', 'repeat_freq' => 'Repetition',
'account_from_id' => 'Account from', 'account_to_id' => 'Account to', 'account_id' => 'Asset account', 'budget_id' => 'Budget'
, 'piggy_bank_id' => 'Piggy bank'];
$labels = [
'amount_min' => 'Amount (min)',
'amount_max' => 'Amount (max)',
'match' => 'Matches on',
'repeat_freq' => 'Repetition',
'account_from_id' => 'Account from',
'account_to_id' => 'Account to',
'account_id' => 'Asset account',
'budget_id' => 'Budget',
'openingBalance' => 'Opening balance',
'accountRole' => 'Account role',
'openingBalanceDate' => 'Opening balance date',
'piggy_bank_id' => 'Piggy bank'];
return isset($labels[$name]) ? $labels[$name] : str_replace('_', ' ', ucfirst($name));
@ -157,7 +128,7 @@ class ExpandedForm
public function fillFieldValue($name, $value)
{
if (Session::has('preFilled')) {
$preFilled = \Session::get('preFilled');
$preFilled = Session::get('preFilled');
$value = isset($preFilled[$name]) && is_null($value) ? $preFilled[$name] : $value;
}
if (!is_null(Input::old($name))) {
@ -181,7 +152,7 @@ class ExpandedForm
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$defaultCurrency = isset($options['currency']) ? $options['currency'] : Amount::getDefaultCurrency();
$defaultCurrency = isset($options['currency']) ? $options['currency'] : Amt::getDefaultCurrency();
$currencies = TransactionCurrency::orderBy('code', 'ASC')->get();
$html = View::make('form.balance', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
@ -229,6 +200,26 @@ class ExpandedForm
return $html;
}
/**
* @param $name
* @param null $value
* @param array $options
*
* @return string
*/
public function integer($name, $value = null, array $options = [])
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = '1';
$html = View::make('form.integer', compact('classes', 'name', 'label', 'value', 'options'))->render();
return $html;
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
@ -246,7 +237,7 @@ class ExpandedForm
$selectList[0] = '(none)';
}
$fields = ['title', 'name', 'description'];
/** @var \Eloquent $entry */
/** @var Eloquent $entry */
foreach ($set as $entry) {
$id = intval($entry->id);
$title = null;
@ -270,9 +261,9 @@ class ExpandedForm
*/
public function optionsList($type, $name)
{
$previousValue = \Input::old('post_submit_action');
$previousValue = Input::old('post_submit_action');
$previousValue = is_null($previousValue) ? 'store' : $previousValue;
$html = \View::make('form.options', compact('type', 'name', 'previousValue'))->render();
$html = View::make('form.options', compact('type', 'name', 'previousValue'))->render();
return $html;
}
@ -291,7 +282,26 @@ class ExpandedForm
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$selected = $this->fillFieldValue($name, $selected);
$html = \View::make('form.select', compact('classes', 'name', 'label', 'selected', 'options', 'list'))->render();
$html = View::make('form.select', compact('classes', 'name', 'label', 'selected', 'options', 'list'))->render();
return $html;
}
/**
* @param $name
* @param null $value
* @param array $options
*
* @return string
*/
public function tags($name, $value = null, array $options = [])
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['data-role'] = 'tagsinput';
$html = View::make('form.tags', compact('classes', 'name', 'label', 'value', 'options'))->render();
return $html;
}

View File

@ -28,20 +28,27 @@ class Navigation
$add = ($skip + 1);
$functionMap = [
'1D' => 'addDays',
'daily' => 'addDays',
'1W' => 'addWeeks',
'weekly' => 'addWeeks',
'week' => 'addWeeks',
'1M' => 'addMonths',
'month' => 'addMonths',
'monthly' => 'addMonths',
'3M' => 'addMonths',
'quarter' => 'addMonths',
'quarterly' => 'addMonths',
'6M' => 'addMonths',
'half-year' => 'addMonths',
'year' => 'addYears',
'yearly' => 'addYears',
];
$modifierMap = [
'quarter' => 3,
'3M' => 3,
'quarterly' => 3,
'6M' => 6,
'half-year' => 6,
];
if (!isset($functionMap[$repeatFreq])) {
@ -68,24 +75,31 @@ class Navigation
$currentEnd = clone $theCurrentEnd;
$functionMap = [
'1D' => 'addDay',
'daily' => 'addDay',
'1W' => 'addWeek',
'week' => 'addWeek',
'weekly' => 'addWeek',
'1M' => 'addMonth',
'month' => 'addMonth',
'monthly' => 'addMonth',
'3M' => 'addMonths',
'quarter' => 'addMonths',
'quarterly' => 'addMonths',
'6M' => 'addMonths',
'half-year' => 'addMonths',
'year' => 'addYear',
'yearly' => 'addYear',
];
$modifierMap = [
'quarter' => 3,
'3M' => 3,
'quarterly' => 3,
'half-year' => 6,
'6M' => 6,
];
$subDay = ['week', 'weekly', 'month', 'monthly', 'quarter', 'quarterly', 'half-year', 'year', 'yearly'];
$subDay = ['week', 'weekly', '1W', 'month', 'monthly', '1M', '3M', 'quarter', 'quarterly', '6M', 'half-year', 'year', 'yearly'];
if (!isset($functionMap[$repeatFreq])) {
throw new FireflyException('Cannot do endOfPeriod for $repeat_freq ' . $repeatFreq);
@ -298,15 +312,19 @@ class Navigation
$date = clone $theDate;
$functionMap = [
'daily' => 'startOfDay',
'week' => 'startOfWeek',
'weekly' => 'startOfWeek',
'month' => 'startOfMonth',
'monthly' => 'startOfMonth',
'quarter' => 'firstOfQuarter',
'quartly' => 'firstOfQuarter',
'year' => 'startOfYear',
'yearly' => 'startOfYear',
'1D' => 'startOfDay',
'daily' => 'startOfDay',
'1W' => 'startOfWeek',
'week' => 'startOfWeek',
'weekly' => 'startOfWeek',
'month' => 'startOfMonth',
'1M' => 'startOfMonth',
'monthly' => 'startOfMonth',
'3M' => 'firstOfQuarter',
'quarter' => 'firstOfQuarter',
'quarterly' => 'firstOfQuarter',
'year' => 'startOfYear',
'yearly' => 'startOfYear',
];
if (isset($functionMap[$repeatFreq])) {
$function = $functionMap[$repeatFreq];
@ -314,7 +332,7 @@ class Navigation
return $date;
}
if ($repeatFreq == 'half-year') {
if ($repeatFreq == 'half-year' || $repeatFreq == '6M') {
$month = intval($date->format('m'));
$date->startOfYear();
if ($month >= 7) {
@ -396,5 +414,47 @@ class Navigation
throw new FireflyException('updateStartDate cannot handle $range ' . $range);
}
/**
* @param Carbon $theDate
* @param $repeatFreq
* @param int $subtract
*
* @return Carbon
* @throws FireflyException
*/
public function subtractPeriod(Carbon $theDate, $repeatFreq, $subtract = 1)
{
$date = clone $theDate;
$functionMap = [
'daily' => 'subDays',
'week' => 'subWeeks',
'weekly' => 'subWeeks',
'month' => 'subMonths',
'monthly' => 'subMonths',
'year' => 'subYears',
'yearly' => 'subYears',
];
$modifierMap = [
'quarter' => 3,
'quarterly' => 3,
'half-year' => 6,
];
if (isset($functionMap[$repeatFreq])) {
$function = $functionMap[$repeatFreq];
$date->$function($subtract);
return $date;
}
if (isset($modifierMap[$repeatFreq])) {
$subtract = $subtract * $modifierMap[$repeatFreq];
$date->subMonths($subtract);
return $date;
}
throw new FireflyException('Cannot do subtractPeriod for $repeat_freq ' . $repeatFreq);
}
}

View File

@ -45,12 +45,12 @@ class Preferences
if (is_null($pref)) {
$pref = new Preference;
$pref->name = $name;
$pref->user()->associate(Auth::user());
}
$pref->data = $value;
$pref->save();
if (!is_null(Auth::user()->id)) {
$pref->user()->associate(Auth::user());
$pref->save();
}
return $pref;

View File

@ -99,12 +99,4 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
return $this->hasMany('FireflyIII\Models\TransactionJournal');
}
/**
* @param $value
*/
public function setPasswordAttribute($value)
{
$this->attributes['password'] = \Hash::make($value);
}
}

View File

@ -3,8 +3,10 @@
namespace FireflyIII\Validation;
use Auth;
use Carbon\Carbon;
use DB;
use Illuminate\Validation\Validator;
use Navigation;
/**
* Class FireflyValidator
@ -32,6 +34,31 @@ class FireflyValidator extends Validator
}
public function validatePiggyBankReminder($attribute, $value, $parameters)
{
$array = $this->data;
// no reminder? dont care.
if (!isset($array['remind_me'])) {
return true;
}
// get or set start date & target date:
$startDate = isset($array['startdate']) ? new Carbon($array['startdate']) : new Carbon;
$targetDate = isset($array['targetdate']) && strlen($array['targetdate']) > 0 ? new Carbon($array['targetdate']) : null;
// target date is null? reminder period is always good.
if ($array['remind_me'] == '1' && is_null($targetDate)) {
return true;
}
$nextReminder = Navigation::addPeriod($startDate, $array['reminder'],0);
// reminder is beyond target?
if($nextReminder > $targetDate) {
return false;
}
return true;
}
/**
* @param $attribute
* @param $value
@ -41,7 +68,11 @@ class FireflyValidator extends Validator
*/
public function validateUniqueForUser($attribute, $value, $parameters)
{
$count = DB::table($parameters[0])->where($parameters[1], $value)->count();
$query = DB::table($parameters[0])->where($parameters[1], $value);
if (isset($paramers[2])) {
$query->where('id', '!=', $parameters[2]);
}
$count = $query->count();
if ($count == 0) {
return true;
}

View File

@ -1,18 +0,0 @@
actor: Tester
paths:
tests: tests
log: tests/_output
data: tests/_data
helpers: tests/_support
settings:
bootstrap: _bootstrap.php
colors: true
memory_limit: 1024M
modules:
config:
coverage:
enabled: true
remote: false
whitelist:
include:
- app/*

View File

@ -26,23 +26,14 @@
"watson/validating": "dev-master",
"doctrine/dbal": "~2.5",
"illuminate/html": "~5.0",
"barryvdh/laravel-ide-helper": "~2.0",
"league/commonmark": "0.7.*"
},
"require-dev": {
"barryvdh/laravel-debugbar": "@stable",
"barryvdh/laravel-ide-helper": "~2.0",
"phpunit/phpunit": "~4.0",
"phpspec/phpspec": "~2.1",
"codeception/codeception": "@stable",
"codeception/c3": "@stable",
"league/factory-muffin": "~2.1",
"codeception/phpbuiltinserver": "*",
"codeception/specify": "*",
"codeception/verify": "*",
"fzaninotto/faker": "1.*",
"codeclimate/php-test-reporter": "dev-master"
"satooshi/php-coveralls": "0.6.1"
},
"autoload": {
"classmap": [
@ -60,14 +51,11 @@
"scripts": {
"post-install-cmd": [
"php artisan clear-compiled",
"php artisan optimize",
"Codeception\\c3\\Installer::copyC3ToRoot"
"php artisan optimize"
],
"post-update-cmd": [
"php artisan clear-compiled",
"php artisan optimize",
"Codeception\\c3\\Installer::copyC3ToRoot"
"php artisan optimize"
],
"post-create-project-cmd": [
"php -r \"copy('.env.example', '.env');\"",

1105
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,8 @@ return [
],
'accountRoles' => [
'defaultExpense' => 'Default expense account',
'sharedExpense' => 'Shared expense account'
'defaultAsset' => 'Default asset account',
'sharedAsset' => 'Shared asset account'
],
'range_to_text' => [

View File

@ -15,7 +15,7 @@ return [
|
*/
'driver' => 'smtp',
'driver' => env('EMAIL_DRIVER', 'smtp'),
/*
|--------------------------------------------------------------------------

View File

@ -1,5 +1,7 @@
<?php
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\Component;
use Illuminate\Database\Migrations\Migration;

View File

@ -23,13 +23,17 @@ class ChangesForV322 extends Migration
// rename fields
Schema::table(
'piggy_bank_events', function (Blueprint $table) {
$table->dropForeign('piggy_bank_events_piggy_bank_id_foreign');
$table->renameColumn('piggy_bank_id', 'piggybank_id');
$table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('cascade');
}
);
Schema::table(
'piggybank_repetitions', function (Blueprint $table) {
$table->dropForeign('piggy_bank_repetitions_piggy_bank_id_foreign');
$table->renameColumn('piggy_bank_id', 'piggybank_id');
$table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('cascade');
}
);
@ -55,11 +59,12 @@ class ChangesForV322 extends Migration
}
);
// drop foreign key from budget_limits:
// drop unique constraint from budget_limits:
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->dropForeign('bid_foreign');
$table->dropUnique('unique_bl_combi');
$table->foreign('budget_id', 'bid_foreign')->references('id')->on('budgets')->onDelete('cascade');
}
);

View File

@ -0,0 +1,46 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
/**
* Class ChangesForV332
*/
class ChangesForV332 extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table(
'accounts', function (Blueprint $table) {
$table->boolean('encrypted');
}
);
Schema::table(
'reminders', function (Blueprint $table) {
$table->text('metadata');
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View File

@ -138,9 +138,9 @@ class TestDataSeeder extends Seeder
$acc_c = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Delete me', 'active' => 1]);
// create account meta:
$meta_a = AccountMeta::create(['account_id' => $acc_a->id, 'name' => 'accountRole', 'data' => 'defaultExpense']);
$meta_b = AccountMeta::create(['account_id' => $acc_b->id, 'name' => 'accountRole', 'data' => 'defaultExpense']);
$meta_c = AccountMeta::create(['account_id' => $acc_c->id, 'name' => 'accountRole', 'data' => 'defaultExpense']);
$meta_a = AccountMeta::create(['account_id' => $acc_a->id, 'name' => 'accountRole', 'data' => 'defaultAsset']);
$meta_b = AccountMeta::create(['account_id' => $acc_b->id, 'name' => 'accountRole', 'data' => 'defaultAsset']);
$meta_c = AccountMeta::create(['account_id' => $acc_c->id, 'name' => 'accountRole', 'data' => 'defaultAsset']);
// var_dump($meta_a->toArray());
// var_dump($meta_b->toArray());
// var_dump($meta_c->toArray());
@ -279,7 +279,6 @@ class TestDataSeeder extends Seeder
);
// and some events!
PiggyBankEvent::create(['piggy_bank_id' => $newCamera->id, 'date' => $this->som, 'amount' => 100]);
PiggyBankRepetition::create(['piggy_bank_id' => $newCamera->id, 'startdate' => $this->som, 'targetdate' => null, 'currentamount' => 100]);
$newClothes = PiggyBank::create(
@ -301,27 +300,51 @@ class TestDataSeeder extends Seeder
);
PiggyBankEvent::create(['piggy_bank_id' => $newClothes->id, 'date' => $this->som, 'amount' => 100]);
PiggyBankRepetition::create(['piggy_bank_id' => $newClothes->id, 'startdate' => $this->som, 'targetdate' => $end, 'currentamount' => 100]);
// weekly reminder piggy bank
$weekly = PiggyBank::create(
[
'account_id' => $savings->id,
'name' => 'Weekly reminder for clothes',
'targetamount' => 2000,
'startdate' => $this->som,
'targetdate' => $next,
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => 'week',
'reminder_skip' => 0,
'remind_me' => 1,
'order' => 0,
]
);
PiggyBankRepetition::create(['piggy_bank_id' => $weekly->id, 'startdate' => $this->som, 'targetdate' => $next, 'currentamount' => 0]);
/*
* New: create no less than eight piggy banks that
* create all sorts of reminders
*/
$list = ['week','quarter','month','year'];
$nextYear = clone $this->_startOfMonth;
$nextYear->addYear();
foreach($list as $entry) {
PiggyBank::create(
[
'account_id' => $savings->id,
'name' => $entry.' piggy bank with target date.',
'targetamount' => 1000,
'startdate' => $this->som,
'targetdate' => $nextYear,
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => $entry,
'reminder_skip' => 0,
'remind_me' => 1,
'order' => 0,
]
);
PiggyBank::create(
[
'account_id' => $savings->id,
'name' => $entry.' piggy bank without target date.',
'targetamount' => 1000,
'startdate' => $this->som,
'targetdate' => null,
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => $entry,
'reminder_skip' => 0,
'remind_me' => 1,
'order' => 0,
]
);
}
}
/**
@ -331,21 +354,7 @@ class TestDataSeeder extends Seeder
{
$user = User::whereEmail('thegrumpydictator@gmail.com')->first();
// for weekly piggy bank (clothes)
$nextWeek = clone $this->_startOfMonth;
$piggyBank = PiggyBank::whereName('New clothes')->orderBy('id', 'DESC')->first();
$nextWeek->addWeek();
$week = $nextWeek->format('Y-m-d');
Reminder::create(
['user_id' => $user->id, 'startdate' => $this->som, 'enddate' => $week, 'active' => 1, 'notnow' => 0,
'remindersable_id' => $piggyBank->id, 'remindersable_type' => 'PiggyBank']
);
// a fake reminder::
Reminder::create(
['user_id' => $user->id, 'startdate' => $this->som, 'enddate' => $week, 'active' => 0, 'notnow' => 0, 'remindersable_id' => 40,
'remindersable_type' => 'Transaction']
);
}
/**
@ -374,14 +383,6 @@ class TestDataSeeder extends Seeder
'order' => 0,
]
);
PiggyBankRepetition::create(['piggy_bank_id' => $recurring->id, 'startdate' => $this->som, 'targetdate' => $this->eom, 'currentamount' => 0]);
PiggyBankRepetition::create(
['piggy_bank_id' => $recurring->id, 'startdate' => $this->nsom, 'targetdate' => $this->neom, 'currentamount' => 0]
);
Reminder::create(
['user_id' => $user->id, 'startdate' => $this->som, 'enddate' => $this->neom, 'active' => 1, 'notnow' => 0,
'remindersable_id' => $recurring->id, 'remindersable_type' => 'PiggyBank']
);
}
/**

View File

@ -11,12 +11,26 @@
syntaxCheck="false">
<testsuites>
<testsuite name="Application Test Suite">
<directory>./tests/</directory>
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<!-- code coverage -->
<!--
<logging>
<log type="coverage-clover" target="./storage/coverage/clover.xml" charset="UTF-8" />
</logging>
-->
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
</php>
</phpunit>
</phpunit>

View File

@ -0,0 +1,319 @@
/*!
* Stylesheet for the Date Range Picker, for use with Bootstrap 3.x
*
* Copyright 2013-2015 Dan Grossman ( http://www.dangrossman.info )
* Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
*
* Built for http://www.improvely.com
*/
.daterangepicker.dropdown-menu {
max-width: none;
z-index: 3000;
}
.daterangepicker.opensleft .ranges, .daterangepicker.opensleft .calendar {
float: left;
margin: 4px;
}
.daterangepicker.opensright .ranges, .daterangepicker.opensright .calendar,
.daterangepicker.openscenter .ranges, .daterangepicker.openscenter .calendar {
float: right;
margin: 4px;
}
.daterangepicker.single .ranges, .daterangepicker.single .calendar {
float: none;
}
.daterangepicker .ranges {
width: 160px;
text-align: left;
}
.daterangepicker .ranges .range_inputs>div {
float: left;
}
.daterangepicker .ranges .range_inputs>div:nth-child(2) {
padding-left: 11px;
}
.daterangepicker .calendar {
display: none;
max-width: 270px;
}
.daterangepicker.show-calendar .calendar {
display: block;
}
.daterangepicker .calendar.single .calendar-date {
border: none;
}
.daterangepicker .calendar th, .daterangepicker .calendar td {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
white-space: nowrap;
text-align: center;
min-width: 32px;
}
.daterangepicker .daterangepicker_start_input label,
.daterangepicker .daterangepicker_end_input label {
color: #333;
display: block;
font-size: 11px;
font-weight: normal;
height: 20px;
line-height: 20px;
margin-bottom: 2px;
text-shadow: #fff 1px 1px 0px;
text-transform: uppercase;
width: 74px;
}
.daterangepicker .ranges input {
font-size: 11px;
}
.daterangepicker .ranges .input-mini {
border: 1px solid #ccc;
border-radius: 4px;
color: #555;
display: block;
font-size: 11px;
height: 30px;
line-height: 30px;
vertical-align: middle;
margin: 0 0 10px 0;
padding: 0 6px;
width: 74px;
}
.daterangepicker .ranges ul {
list-style: none;
margin: 0;
padding: 0;
}
.daterangepicker .ranges li {
font-size: 13px;
background: #f5f5f5;
border: 1px solid #f5f5f5;
color: #08c;
padding: 3px 12px;
margin-bottom: 8px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
cursor: pointer;
}
.daterangepicker .ranges li.active, .daterangepicker .ranges li:hover {
background: #08c;
border: 1px solid #08c;
color: #fff;
}
.daterangepicker .calendar-date {
border: 1px solid #ddd;
padding: 4px;
border-radius: 4px;
background: #fff;
}
.daterangepicker .calendar-time {
text-align: center;
margin: 8px auto 0 auto;
line-height: 30px;
}
.daterangepicker {
position: absolute;
background: #fff;
top: 100px;
left: 20px;
padding: 4px;
margin-top: 1px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.daterangepicker.opensleft:before {
position: absolute;
top: -7px;
right: 9px;
display: inline-block;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-left: 7px solid transparent;
border-bottom-color: rgba(0, 0, 0, 0.2);
content: '';
}
.daterangepicker.opensleft:after {
position: absolute;
top: -6px;
right: 10px;
display: inline-block;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-left: 6px solid transparent;
content: '';
}
.daterangepicker.openscenter:before {
position: absolute;
top: -7px;
left: 0;
right: 0;
width: 0;
margin-left: auto;
margin-right: auto;
display: inline-block;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-left: 7px solid transparent;
border-bottom-color: rgba(0, 0, 0, 0.2);
content: '';
}
.daterangepicker.openscenter:after {
position: absolute;
top: -6px;
left: 0;
right: 0;
width: 0;
margin-left: auto;
margin-right: auto;
display: inline-block;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-left: 6px solid transparent;
content: '';
}
.daterangepicker.opensright:before {
position: absolute;
top: -7px;
left: 9px;
display: inline-block;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-left: 7px solid transparent;
border-bottom-color: rgba(0, 0, 0, 0.2);
content: '';
}
.daterangepicker.opensright:after {
position: absolute;
top: -6px;
left: 10px;
display: inline-block;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-left: 6px solid transparent;
content: '';
}
.daterangepicker table {
width: 100%;
margin: 0;
}
.daterangepicker td, .daterangepicker th {
text-align: center;
width: 20px;
height: 20px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
cursor: pointer;
white-space: nowrap;
}
.daterangepicker td.off {
color: #999;
}
.daterangepicker td.disabled, .daterangepicker option.disabled {
color: #999;
}
.daterangepicker td.available:hover, .daterangepicker th.available:hover {
background: #eee;
}
.daterangepicker td.in-range {
background: #ebf4f8;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.daterangepicker td.start-date {
-webkit-border-radius: 4px 0 0 4px;
-moz-border-radius: 4px 0 0 4px;
border-radius: 4px 0 0 4px;
}
.daterangepicker td.end-date {
-webkit-border-radius: 0 4px 4px 0;
-moz-border-radius: 0 4px 4px 0;
border-radius: 0 4px 4px 0;
}
.daterangepicker td.start-date.end-date {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.daterangepicker td.active, .daterangepicker td.active:hover {
background-color: #357ebd;
border-color: #3071a9;
color: #fff;
}
.daterangepicker td.week, .daterangepicker th.week {
font-size: 80%;
color: #ccc;
}
.daterangepicker select.monthselect, .daterangepicker select.yearselect {
font-size: 12px;
padding: 1px;
height: auto;
margin: 0;
cursor: default;
}
.daterangepicker select.monthselect {
margin-right: 2%;
width: 56%;
}
.daterangepicker select.yearselect {
width: 40%;
}
.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect {
width: 50px;
margin-bottom: 0;
}
.daterangepicker_start_input {
float: left;
}
.daterangepicker_end_input {
float: left;
padding-left: 11px
}
.daterangepicker th.month {
width: auto;
}

2
public/css/firefly.css Normal file
View File

@ -0,0 +1,2 @@
#daterange {cursor:pointer;}
.google-chart-error {height:30px;background:url('/images/error.png') no-repeat center center;}

View File

@ -298,6 +298,9 @@ table.dataTable thead .sorting:after {
.huge {
font-size: 40px;
}
.large {
font-size: 30px;
}
.panel-green {
border-color: #5cb85c;

View File

@ -1,7 +1,7 @@
$(function () {
if (typeof(googleLineChart) === "function" && typeof accountID !== 'undefined' && typeof view !== 'undefined') {
googleLineChart('chart/account/' + accountID + '/' + view, 'overview-chart');
if (typeof(googleLineChart) === "function" && typeof accountID !== 'undefined') {
googleLineChart('chart/account/' + accountID, 'overview-chart');
}
});

View File

@ -1,7 +1,8 @@
$(function () {
if (typeof componentID !== 'undefined' && typeof repetitionID === 'undefined') {
googleColumnChart('chart/category/' + componentID + '/spending/' + year, 'componentOverview');
if (typeof categoryID !== 'undefined') {
googleColumnChart('chart/category/' + categoryID + '/overview', 'componentOverview');
googleColumnChart('chart/category/' + categoryID + '/period', 'periodOverview');
}

1280
public/js/daterangepicker.js Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,46 @@
$(function () {
$('.currencySelect').click(currencySelect)
$('.currencySelect').click(currencySelect);
ranges = {};
ranges[currentMonthName] = [moment().startOf('month'), moment().endOf('month')];
ranges[previousMonthName] = [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')];
ranges[nextMonthName] = [moment().add(1, 'month').startOf('month'), moment().add(1, 'month').endOf('month')];
ranges['Everything'] = [firstDate, moment()];
$('#daterange').daterangepicker(
{
//View::share('currentMonthName', $current);
//View::share('previousMonthName', $prev);
//View::share('nextMonthName', $next);
ranges: ranges
,
opens: 'left',
format: 'DD-MM-YYYY',
startDate: start,
endDate: end
},
function (start, end, label) {
// send post.
$.post(dateRangeURL, {
start: start.format('YYYY-MM-DD'),
end: end.format('YYYY-MM-DD'),
label: label,
_token: token
}).success(function () {
window.location.reload(true);
}).fail(function () {
alert('Could not change date range');
});
//alert('A date range was chosen: ' + start.format('YYYY-MM-DD') + ' to ' + end.format('YYYY-MM-DD'));
}
);
});
@ -21,4 +61,5 @@ function currencySelect(e) {
return false;
}
}

View File

@ -3,7 +3,22 @@ google.setOnLoadCallback(drawChart);
function drawChart() {
googleLineChart('chart/home/account', 'accounts-chart');
googleBarChart('chart/home/budgets','budgets-chart');
googleColumnChart('chart/home/categories','categories-chart');
googlePieChart('chart/home/bills','bills-chart')
googleBarChart('chart/home/budgets', 'budgets-chart');
googleColumnChart('chart/home/categories', 'categories-chart');
googlePieChart('chart/home/bills', 'bills-chart');
getBoxAmounts();
}
function getBoxAmounts() {
var boxes = ['in', 'out','bills-unpaid','bills-paid'];
for (x in boxes) {
var box = boxes[x];
$.getJSON('/json/box', {box: box}).success(function (data) {
if(data.amount_raw != 0) {
$('#box-' + data.box).html(data.amount);
}
}).fail(function () {
console.log('Failed to get box!')
});
}
}

7
public/js/moment.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -9,14 +9,14 @@ $(function () {
function addMoney(e) {
var pigID = parseInt($(e.target).data('id'));
$('#moneyManagementModal').empty().load('piggy-banks/add/' + pigID).modal('show');
$('#moneyManagementModal').empty().load('piggy-banks/add/' + pigID, function() {$('#moneyManagementModal').modal('show');});
return false;
}
function removeMoney(e) {
var pigID = parseInt($(e.target).data('id'));
$('#moneyManagementModal').empty().load('piggy-banks/remove/' + pigID).modal('show');
$('#moneyManagementModal').empty().load('piggy-banks/remove/' + pigID, function() {$('#moneyManagementModal').modal('show');});
return false;
}

View File

@ -1,23 +1,40 @@
$(document).ready(function () {
$('.relateTransaction').click(relateTransaction);
$('.unrelate-checkbox').click(unrelateTransaction);
$('.relateTransaction').click(relateTransactionDialog);
//$('.unrelate-checkbox').click(unrelateTransaction);
});
function unrelateTransaction(e) {
var target = $(e.target);
var id = target.data('id');
var relatedTo = target.data('relatedto');
var parent = target.data('parent');
$.post('related/removeRelation/' + id + '/' + relatedTo, {_token:token}).success(function (data) {
if(typeof id == "undefined" && typeof parent == "undefined") {
target = target.parent();
id = target.data('id');
parent = target.data('parent');
}
console.log('unlink ' + id + ' from ' + parent);
$.post('related/removeRelation/' + id + '/' + parent, {_token: token}).success(function (data) {
target.parent().parent().remove();
}).fail(function () {
alert('Could not!');
});
return false;
//$.post('related/removeRelation/' + id + '/' + relatedTo, {_token: token}).success(function (data) {
// target.parent().parent().remove();
//}).fail(function () {
// alert('Could not!');
//});
}
function relateTransaction(e) {
function relateTransactionDialog(e) {
var target = $(e.target);
var ID = target.data('id');
@ -41,21 +58,12 @@ function relateTransaction(e) {
function searchRelatedTransactions(e, ID) {
var searchValue = $('#relatedSearchValue').val();
if (searchValue != '') {
$.post('related/search/' + ID, {searchValue: searchValue,_token:token}).success(function (data) {
// post each result to some div.
$('#relatedSearchResults').empty();
$.each(data, function (i, row) {
var tr = $('<tr>');
var checkBox = $('<td>').append($('<input>').attr('type', 'checkbox').data('relateto', ID).data('id', row.id).click(doRelateNewTransaction));
var description = $('<td>').text(row.description);
var amount = $('<td>').html(row.amount);
tr.append(checkBox).append(description).append(amount);
$('#relatedSearchResults').append(tr);
//$('#relatedSearchResults').append($('<div>').text(row.id));
});
$.post('related/search/' + ID, {searchValue: searchValue, _token: token}).success(function (data) {
// post the results to some div.
$('#relatedSearchResultsTitle').show();
$('#relatedSearchResults').empty().html(data);
// remove any clicks.
$('.relate').unbind('click').on('click', doRelateNewTransaction);
}).fail(function () {
alert('Could not search. Sorry.');
@ -69,38 +77,35 @@ function doRelateNewTransaction(e) {
// remove the row from the table:
var target = $(e.target);
var id = target.data('id');
var relateToId = target.data('relateto');
if (!target.checked) {
var relateID = target.data('id');
$.post('related/relate/' + id + '/' + relateToId,{_token:token}).success(function (data) {
// success!
target.parent().parent().remove();
getAlreadyRelatedTransactions(null, relateToId);
}).fail(function () {
// could not relate.
alert('Error!');
});
var parent = target.data('parent');
} else {
alert('remove again!');
if (typeof id == "undefined" && typeof parent == "undefined") {
target = target.parent();
console.log(target);
id = target.data('id');
parent = target.data('parent');
}
console.log('Relate ' + id + ' to ' + parent);
$.post('related/relate/' + parent + '/' + id, {_token: token}).success(function (data) {
// success! remove entry:
target.parent().parent().remove();
// get related stuff (again).
getAlreadyRelatedTransactions(null, parent);
}).fail(function () {
// could not relate.
alert('Could not relate this transaction to the intended target.');
});
return false;
}
function getAlreadyRelatedTransactions(e, ID) {
//#alreadyRelated
$.get('related/alreadyRelated/' + ID).success(function (data) {
$('#alreadyRelated').empty();
$.each(data, function (i, row) {
var tr = $('<tr>');
$('#alreadyRelated').empty().html(data);
// some event triggers.
$('.unrelate').unbind('click').on('click', unrelateTransaction);
var checkBox = $('<td>').append($('<input>').attr('type', 'checkbox').data('relateto', ID).data('id', row.id).click(doRelateNewTransaction));
var description = $('<td>').text(row.description);
var amount = $('<td>').html(row.amount);
tr.append(checkBox).append(description).append(amount);
$('#alreadyRelated').append(tr);
//$('#relatedSearchResults').append($('<div>').text(row.id));
});
}).fail(function () {
alert('Cannot get related stuff.');
});

View File

@ -6,4 +6,55 @@ if (typeof(google) != 'undefined') {
googleStackedColumnChart('chart/budgets/spending/' + year, 'budgets');
}
}
$(function () {
$('.openModal').on('click', openModal);
includeSharedToggle();
$('#includeShared').click(includeSharedSet);
});
function openModal(e) {
"use strict";
var target = $(e.target).parent();
var URL = target.attr('href');
$.get(URL).success(function (data) {
$('#defaultModal').empty().html(data).modal('show');
}).fail(function () {
alert('Could not load data.');
});
return false;
}
function includeSharedToggle() {
// get setting from JSON.
$.getJSON('json/show-shared-reports').success(function (data) {
console.log('GO');
if (data.value == true) {
// show shared data, update button:
//<i class="state-icon glyphicon glyphicon-check"></i>
$('#includeShared').empty().addClass('btn-info').append($('<i>').addClass('state-icon glyphicon glyphicon-check')).append(' Include shared asset accounts').show();
console.log('true');
} else {
$('#includeShared').empty().removeClass('btn-info').append($('<i>').addClass('state-icon glyphicon glyphicon-unchecked')).append(' Include shared asset accounts').show();
console.log('false');
}
}).fail(function () {
console.log('fail');
});
}
function includeSharedSet() {
// get setting from JSON.
$.getJSON('json/show-shared-reports/set').success(function (data) {
console.log('Value is now: ' + data.value);
includeSharedToggle();
}).fail(function () {
console.log('fail');
});
return false;
}

View File

@ -20,7 +20,8 @@ return [
"alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.",
"alpha_num" => "The :attribute may only contain letters and numbers.",
"array" => "The :attribute must be an array.",
"unique_for_user" => "There already is an entry with this :attribute.",
"unique_for_user" => "There already is an entry with this :attribute.",
'piggy_bank_reminder' => 'The target date is too close to today to allow reminders.',
"before" => "The :attribute must be a date before :date.",
"between" => [
"numeric" => "The :attribute must be between :min and :max.",

View File

@ -22,7 +22,9 @@
</div>
<div class="panel-body">
@include('list.accounts')
</div>
</div>
</div>
</div>

View File

@ -2,7 +2,7 @@
@section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $account) !!}
<div class="row">
<div class="col-lg-8 col-md-6 col-sm-12">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-fw {{$subTitleIcon}} fa-fw"></i> {{{$account->name}}}
@ -27,24 +27,6 @@
</div>
</div>
</div>
<div class="col-lg-4 col-md-6 col-sm-12">
<!-- time based navigation -->
@include('partials.date_nav')
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-clock-o fa-fw"></i> View options for {{{$account->name}}}
</div>
<div class="panel-body">
<p>
@if($range == 'all')
<a href="{{route('accounts.show',$account->id)}}/session" class="btn btn-default">Stick to date-range</a>
@else
<a href="{{route('accounts.show',$account->id)}}/all" class="btn btn-default">Show all transactions</a>
@endif
</p>
</div>
</div>
</div>
</div>
@ -66,7 +48,6 @@
@section('scripts')
<script type="text/javascript">
var accountID = {{{$account->id}}};
var view = '{{{$range}}}';
var currencyCode = '{{Amount::getCurrencyCode()}}';
</script>
<!-- load the libraries and scripts necessary for Google Charts: -->

View File

@ -1,62 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<link href="/css/app.css" rel="stylesheet">
<!-- Fonts -->
<link href='//fonts.googleapis.com/css?family=Roboto:400,300' rel='stylesheet' type='text/css'>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Laravel</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
@if (Auth::guest())
<li><a href="/auth/login">Login</a></li>
<li><a href="/auth/register">Register</a></li>
@else
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ Auth::user()->name }} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="/auth/logout">Logout</a></li>
</ul>
</li>
@endif
</ul>
</div>
</div>
</nav>
@yield('content')
<!-- Scripts -->
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
</body>
</html>

View File

@ -20,10 +20,8 @@
</div>
</div>
</div>
<div class="panel-body">
@include('list.bills')
</div>
</div>
</div>
</div>
@stop

View File

@ -5,7 +5,7 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel">Update (expected) income for {{Session::get('start', \Carbon\Carbon::now()->startOfMonth())->format('F Y')}}</h4>
<h4 class="modal-title" id="myModalLabel">Update (expected) available amount for {{Session::get('start', \Carbon\Carbon::now()->startOfMonth())->format('F Y')}}</h4>
</div>
<div class="modal-body">
<div class="input-group">

View File

@ -5,15 +5,16 @@
<div class="col-lg-9 col-sm-8 col-md-8">
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-calendar fa-fw"></i>
{{Session::get('start', \Carbon\Carbon::now()->startOfMonth())->format('F Y')}}
</div>
<div class="panel-body">
<div class="row">
<div class="col-lg-6 col-md-4 col-sm-3">
<small>Budgeted: <span id="budgetedAmount" data-value="300">{{Amount::format(300)}}</span></small>
<small>Budgeted: <span id="budgetedAmount" data-value="300"></span></small>
</div>
<div class="col-lg-6 col-md-4 col-sm-3" style="text-align:right;">
<small>Income {{Session::get('start', \Carbon\Carbon::now()->startOfMonth())->format('F Y')}}:
<small>Available in {{Session::get('start', \Carbon\Carbon::now()->startOfMonth())->format('F Y')}}:
<a href="#" class="updateIncome"><span id="totalAmount" data-value="{{$amount}}">{!! Amount::format($amount) !!}</span></a></small>
</div>
</div>
@ -49,11 +50,10 @@
</div>
</div>
<div class="col-lg-3 col-sm-4 col-md-4">
<!-- time based navigation -->
@include('partials.date_nav')
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-fw fa-tags"></i>
Transactions without a budget
</div>
<div class="panel-body">
@ -71,6 +71,7 @@
<div class="col-lg-3 col-sm-4 col-md-6" style="height:180px;">
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-fw fa-tasks"></i>
@if(isset($budget->currentRep))
<a href="{{route('budgets.show',[$budget->id,$budget->currentRep->id])}}" id="budget-link-{{$budget->id}}">{{{$budget->name}}}</a>
@else
@ -135,10 +136,11 @@
<div class="col-lg-3 col-sm-4 col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-fw fa-plus-circle"></i>
Create budget
</div>
<div class="panel-body">
<a href="{{route('budgets.create')}}" class="btn btn-success">Create new budget</a>
<a href="{{route('budgets.create')}}" class="btn btn-success"><i class="fa fa-fw fa-plus"></i> Create new budget</a>
</div>
</div>
</div>

View File

@ -1,12 +1,6 @@
@extends('layouts.default')
@section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
<div class="row">
<div class="col-lg-4 col-md-4 col-sm-12 ">
<!-- time based navigation -->
@include('partials.date_nav')
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="panel panel-default">

View File

@ -20,6 +20,10 @@
</div>
</div>
<div class="col-lg-3 col-md-3 col-sm-5">
@if(count($limits) == 1)
<p class="small text-center"><a href="{{route('budgets.show',$budget->id)}}">Show everything</a></p>
@endif
@foreach($limits as $limit)
@foreach($limit->limitrepetitions as $rep)
<div class="panel panel-default">
@ -64,6 +68,9 @@
@endforeach
@endforeach
@if(count($limits) == 1)
<p class="small text-center"><a href="{{route('budgets.show',$budget->id)}}">Show everything</a></p>
@endif
</div>
</div>

View File

@ -1,12 +1,6 @@
@extends('layouts.default')
@section('content')
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) }}
<div class="row">
<div class="col-lg-4 col-md-4 col-sm-12 ">
<!-- time based navigation -->
@include('partials.date_nav')
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="panel panel-default">

View File

@ -2,18 +2,35 @@
@section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $category) !!}
<div class="row">
<div class="col-lg-9 col-md-9 col-sm-7">
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-calendar fa-fw"></i>
Overview
</div>
<div class="panel-body">
<div id="periodOverview"></div>
</div>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-calendar-o fa-fw"></i>
Overview
</div>
<div class="panel-body">
<div id="componentOverview"></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-repeat fa-fw"></i>
Transactions
</div>
<div class="panel-body">
@ -21,16 +38,12 @@
</div>
</div>
</div>
<div class="col-lg-3 col-md-3 col-sm-5">
(TODO)
</div>
</div>
@stop
@section('scripts')
<script type="text/javascript">
var componentID = {{$category->id}};
var year = {{Session::get('start',\Carbon\Carbon::now()->startOfMonth())->format('Y')}};
var categoryID = {{$category->id}};
var currencyCode = '{{Amount::getCurrencyCode()}}';
</script>
<!-- load the libraries and scripts necessary for Google Charts: -->

View File

@ -3,7 +3,7 @@
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
<div class="row">
<div class="col-lg-6 col-sm-12 col-md-12">
<div class="col-lg-12 col-sm-12 col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
Currencies
@ -14,23 +14,34 @@
</p>
<ul>
@if(count($currencies) > 0)
<table class="table table-striped table-bordered">
<tr>
<th>&nbsp;</th>
<th colspan="2">Currency</th>
</tr>
@foreach($currencies as $currency)
<li>
<a href="{{route('currency.edit',$currency->id)}}"><i class="fa fa-fw fa-pencil"></i></a>
<a href="{{route('currency.delete',$currency->id)}}"><i class="fa fa-fw fa-trash"></i></a>
{{{$currency->name}}} ({{{$currency->code}}}) ({{{$currency->symbol}}})
<tr>
<td>
<div class="btn-group btn-group-sm">
<a class="btn btn-default" href="{{route('currency.edit',$currency->id)}}"><i class="fa fa-fw fa-pencil"></i></a>
<a class="btn btn-default" href="{{route('currency.delete',$currency->id)}}"><i class="fa fa-fw fa-trash"></i></a>
</div>
</td>
<td>{{{$currency->name}}} ({{{$currency->code}}}) ({{{$currency->symbol}}})</td>
<td>
@if($currency->id == $defaultCurrency->id)
<span class="label label-success">default</span>
@else
<span class="label label-default"><a style="color:#fff" href="{{route('currency.default',$currency->id)}}">make default</a></span>
<a class="btn btn-info" href="{{route('currency.default',$currency->id)}}">make default</a>
@endif
</li>
</td>
</tr>
@endforeach
</table>
@endif
<li><a href="{{route('currency.create')}}"><i class="fa fa-fw fa-plus-circle"></i> Add another currency</a></li>
</ul>
<p><a class="btn btn-success" href="{{route('currency.create')}}"><i class="fa fa-fw fa-plus-circle"></i> Add another currency</a></p>
</div>
</div>
</div>

View File

@ -0,0 +1,5 @@
Hey there!
Welkome to Firefly III. Your registration has made it, and this email is here to confirm it.
Thanks for using Firefly!

View File

@ -17,6 +17,10 @@
</div>
@else
<!-- fancy new boxes -->
@include('partials.boxes')
<div class="row">
@ -61,8 +65,6 @@
</div>
<div class="col-lg-4 col-md-6 col-sm-12">
<!-- time based navigation -->
@include('partials.date_nav')
<!-- REMINDERS -->
<div class="panel panel-default">

View File

@ -16,15 +16,17 @@
</title>
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" type="text/css" media="all" />
<!-- <link rel="stylesheet" href="css/metisMenu.min.css" type="text/css" media="all" /> -->
<!-- new css for SB admin -->
<link rel="stylesheet" href="css/metisMenu.min.css" type="text/css" media="all" />
<link rel="stylesheet" href="css/sb-admin-2.css" type="text/css" media="all" />
<link rel="stylesheet" href="font-awesome/css/font-awesome.min.css" type="text/css" media="all" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto2" type="text/css" media="all" />
<!-- date range -->
<link rel="stylesheet" href="css/daterangepicker-bs3.css" type="text/css" media="all" />
<link rel="stylesheet" href="css/firefly.css" type="text/css" media="all" />
@yield('styles')
<!--[if lt IE 9]>
@ -107,24 +109,35 @@
<!-- modal to relate transactions to each other -->
<div class="modal fade" id="relationModal">
</div>
<!-- default modal -->
<div class="modal fade" id="defaultModal">
</div>
<script type="text/javascript" src="js/jquery-2.1.3.min.js"></script>
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
<!-- <script type="text/javascript" src="js/jquery.metisMenu.min.js"></script> -->
<!-- <script type="text/javascript" src="js/sb-admin-2.js"></script>-->
<!-- new js for sb admin -->
<script type="text/javascript" src="js/metisMenu.min.js"></script>
<script type="text/javascript" src="js/sb-admin-2.js"></script>
<script type="text/javascript" src="js/help.js"></script>
<!-- date range stuff -->
<script type="text/javascript" src="js/moment.min.js"></script>
<script type="text/javascript" src="js/daterangepicker.js"></script>
<script type="text/javascript">
var start = "{{Session::get('start')->format('d-m-Y')}}";
var end = "{{Session::get('end')->format('d-m-Y')}}";
var titleString = "{{Session::get('start')->format('j M Y')}} - {{Session::get('end')->format('j M Y')}}";
var dateRangeURL = "{{route('daterange')}}";
var token = "{{csrf_token()}}";
var firstDate = moment("{{Session::get('first')->format('Y-m-d')}}");
var currentMonthName = "{{$currentMonthName}}";
var previousMonthName = "{{$previousMonthName}}";
var nextMonthName = "{{$nextMonthName}}";
$('#daterange span').text(titleString);
</script>
<script type="text/javascript" src="js/firefly.js"></script>
@yield('scripts')
</body>

View File

@ -8,8 +8,10 @@
<title>Firefly III</title>
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" type="text/css" media="all" />
<!-- <link rel="stylesheet" href="css/metisMenu.min.css" type="text/css" media="all" /> -->
<!-- new css for SB admin -->
<link rel="stylesheet" href="css/metisMenu.min.css" type="text/css" media="all" />
<link rel="stylesheet" href="css/sb.css" type="text/css" media="all" />
<link rel="stylesheet" href="css/sb-admin-2.css" type="text/css" media="all" />
<link rel="stylesheet" href="font-awesome/css/font-awesome.min.css" type="text/css" media="all" />
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
@ -44,5 +46,9 @@
</div>
<script type="text/javascript" src="js/jquery-2.1.3.min.js"></script>
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
<!-- new js for sb admin -->
<script type="text/javascript" src="js/metisMenu.min.js"></script>
<script type="text/javascript" src="js/sb-admin-2.js"></script>
</body>
</html>

View File

@ -1,11 +1,17 @@
<table class="table table-striped">
@if(is_object($accounts) && method_exists($accounts, 'render'))
{!! $accounts->render() !!}
@endif
<table class="table table-striped table-bordered">
<tr>
<th>&nbsp;</th>
<th>Name</th>
@if(isset($what) && $what == 'asset')
<th>Role</th>
@endif
<th>Current balance</th>
<th>Active</th>
<th>Last activity</th>
<th>Balance difference between {{Session::get('start')->format('jS F Y')}} and {{Session::get('end')->format('jS F Y')}}</th>
</tr>
@foreach($accounts as $account)
<tr>
@ -16,7 +22,15 @@
</div>
</td>
<td><a href="{{route('accounts.show',$account->id)}}">{{{$account->name}}}</a></td>
<td>{{{$account->accountRole}}}</td>
@if(isset($what) && $what == 'asset')
<td>
@foreach($account->accountmeta as $entry)
@if($entry->name == 'accountRole')
{{Config::get('firefly.accountRoles.'.$entry->data)}}
@endif
@endforeach
</td>
@endif
<td>{!! Amount::format(Steam::balance($account)) !!}</td>
<td>
@if($account->active)
@ -32,7 +46,14 @@
<em>Never</em>
@endif
</td>
<td>
{!! Amount::format($account->endBalance - $account->startBalance) !!}
</td>
</tr>
@endforeach
</table>
@if(is_object($accounts) && method_exists($accounts, 'render'))
{!! $accounts->render() !!}
@endif

View File

@ -3,7 +3,7 @@
<th>&nbsp;</th>
<th>Name</th>
<th>Matches on</th>
<th>Matching amount</th>
<th colspan="2">Matching amount</th>
<th>Last seen match</th>
<th>Next expected match</th>
<th>Is active</th>
@ -28,7 +28,8 @@
</td>
<td>
{!! Amount::format($entry->amount_min) !!}
&mdash;
</td>
<td>
{!! Amount::format($entry->amount_max) !!}
</td>
<td>

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