Merge branch 'release/3.3.2'

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

View File

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

1
.gitignore vendored
View File

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

View File

@@ -15,12 +15,7 @@ install:
- mv -v .env.testing .env - mv -v .env.testing .env
script: script:
- ./tests/_data/db.sh - phpunit
- php vendor/bin/codecept build
- php vendor/bin/codecept run --coverage --coverage-xml --no-exit
after_script: after_script:
- cp -v tests/_output/coverage.xml build/logs/clover.xml
- php vendor/bin/coveralls - 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) [![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 FireflyIII\Models\Account;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Steam;
/** /**
* Class ReportHelper * 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. * This method gets some kind of list for a monthly overview.
* *
@@ -62,7 +50,7 @@ class ReportHelper implements ReportHelperInterface
$end = clone $date; $end = clone $date;
$end->endOfMonth(); $end->endOfMonth();
// all budgets // all budgets
$set = \Auth::user()->budgets() $set = Auth::user()->budgets()
->leftJoin( ->leftJoin(
'budget_limits', function (JoinClause $join) use ($date) { 'budget_limits', function (JoinClause $join) use ($date) {
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d')); $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(); $end = Carbon::now();
$months = []; $months = [];
while ($start <= $end) { while ($start <= $end) {
$months[] = [ $year = $start->format('Y');
$months[$year][] = [
'formatted' => $start->format('F Y'), 'formatted' => $start->format('F Y'),
'month' => intval($start->format('m')), 'month' => intval($start->format('m')),
'year' => intval($start->format('Y')), 'year' => intval($start->format('Y')),
@@ -130,43 +119,47 @@ class ReportHelper implements ReportHelperInterface
/** /**
* @param Carbon $date * @param Carbon $date
* @param bool $showSharedReports
* *
* @return array * @return array
*/ */
public function yearBalanceReport(Carbon $date) public function yearBalanceReport(Carbon $date, $showSharedReports = false)
{ {
$start = clone $date; $start = clone $date;
$end = clone $date; $end = clone $date;
$sharedAccounts = []; $sharedAccounts = [];
$sharedCollection = \Auth::user()->accounts() if ($showSharedReports === false) {
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id') $sharedCollection = \Auth::user()->accounts()
->where('account_meta.name', '=', 'accountRole') ->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
->where('account_meta.data', '=', json_encode('sharedExpense')) ->where('account_meta.name', '=', 'accountRole')
->get(['accounts.id']); ->where('account_meta.data', '=', json_encode('sharedAsset'))
->get(['accounts.id']);
foreach ($sharedCollection as $account) { foreach ($sharedCollection as $account) {
$sharedAccounts[] = $account->id; $sharedAccounts[] = $account->id;
}
} }
$accounts = \Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])->filter( $accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*'])
function (Account $account) use ($sharedAccounts) { ->filter(
if (!in_array($account->id, $sharedAccounts)) { function (Account $account) use ($sharedAccounts) {
return $account; if (!in_array($account->id, $sharedAccounts)) {
} return $account;
}
return null; return null;
} }
); );
$report = []; $report = [];
$start->startOfYear()->subDay(); $start->startOfYear()->subDay();
$end->endOfYear(); $end->endOfYear();
foreach ($accounts as $account) { foreach ($accounts as $account) {
$report[] = [ $report[] = [
'start' => \Steam::balance($account, $start), 'start' => Steam::balance($account, $start),
'end' => \Steam::balance($account, $end), 'end' => Steam::balance($account, $end),
'account' => $account, '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. * This methods fails to take in account transfers FROM shared accounts.
* *
@@ -59,4 +33,26 @@ interface ReportHelperInterface
* @return Collection * @return Collection
*/ */
public function getBudgetsForMonth(Carbon $date); 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 <?php
/**
* Created by PhpStorm.
* User: sander
* Date: 22/02/15
* Time: 18:30
*/
namespace FireflyIII\Helpers\Report; 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. * This query retrieves a list of accounts that are active and not shared.
* *
* @param bool $showSharedReports
*
* @return Collection * @return Collection
*/ */
public function accountList() public function accountList($showSharedReports = false)
{ {
return Auth::user()->accounts() $query = Auth::user()->accounts();
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') if ($showSharedReports === false) {
->leftJoin(
'account_meta', function (JoinClause $join) { $query->leftJoin(
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', "accountRole"); '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(
->where('active', 1) function (Builder $query) {
->where( $query->where('account_meta.data', '!=', '"sharedAsset"');
function (Builder $query) { $query->orWhereNull('account_meta.data');
$query->where('account_meta.data', '!=', '"sharedExpense"'); }
$query->orWhereNull('account_meta.data'); );
}
) }
->get(['accounts.*']); $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') ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'otherJournals.id')
->before($end)->after($start) ->before($end)->after($start)
->where('transaction_types.type', 'Withdrawal') ->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('budget_transaction_journal.budget_id')->whereNull('transaction_journals.deleted_at')
->whereNull('otherJournals.deleted_at') ->whereNull('otherJournals.deleted_at')
->where('transactions.account_id', $account->id) ->where('transactions.account_id', $account->id)
->whereNotNull('transaction_group_transaction_journal.transaction_group_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; $sum = 0;
if (!is_null($set)) { foreach ($set as $entry) {
$sum = floatval($set->amount); $sum += floatval($entry->amount);
} }
return $sum; return $sum;
@@ -105,25 +124,31 @@ class ReportQuery implements ReportQueryInterface
* *
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @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') $query = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')
->accountTypeIn(['Default account', 'Asset account', 'Cash account']) ->accountTypeIn(['Default account', 'Asset account', 'Cash account']);
->leftJoin( if ($showSharedReports === false) {
'account_meta', function (JoinClause $join) { $query->leftJoin(
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); 'account_meta', function (JoinClause $join) {
} $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
) }
->where( )
function (Builder $query) { ->orderBy('accounts.name', 'ASC')
$query->where('account_meta.data', '!=', '"sharedExpense"'); ->where(
$query->orWhereNull('account_meta.data'); function (Builder $query) use ($showSharedReports) {
}
) $query->where('account_meta.data', '!=', '"sharedAsset"');
->get(['accounts.*']); $query->orWhereNull('account_meta.data');
}
);
}
$set = $query->get(['accounts.*']);
$set->each( $set->each(
function (Account $account) use ($start, $end) { function (Account $account) use ($start, $end) {
/** @noinspection PhpParamsInspection */ /** @noinspection PhpParamsInspection */
@@ -167,7 +192,40 @@ class ReportQuery implements ReportQueryInterface
return $set; 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 $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @return Collection
*/ */
public function incomeByPeriod(Carbon $start, Carbon $end) public function incomeByPeriod(Carbon $start, Carbon $end, $showSharedReports = false)
{ {
return TransactionJournal:: $query = TransactionJournal::
leftJoin( leftJoin(
'transactions as t_from', function (JoinClause $join) { 'transactions as t_from', function (JoinClause $join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); $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('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin( ->leftJoin(
'account_meta as acm_from', function (JoinClause $join) { 'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole'); $join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
} }
) )
->leftJoin( ->leftJoin(
'transactions as t_to', function (JoinClause $join) { 'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0); $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('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin( ->leftJoin(
'account_meta as acm_to', function (JoinClause $join) { 'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole'); $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') ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
->where( if ($showSharedReports === false) {
function ($query) { // only get deposits not to a shared account
$query->where( // and transfers to a shared account.
function ($q) { $query->where(
$q->where('transaction_types.type', 'Deposit'); function ($query) {
$q->where('acm_to.data', '!=', '"sharedExpense"'); $query->where(
} function ($q) {
); $q->where('transaction_types.type', 'Deposit');
$query->orWhere( $q->where('acm_to.data', '!=', '"sharedAsset"');
function ($q) { }
$q->where('transaction_types.type', 'Transfer'); );
$q->where('acm_from.data', '=', '"sharedExpense"'); $query->orWhere(
} function ($q) {
); $q->where('transaction_types.type', 'Transfer');
} $q->where('acm_from.data', '=', '"sharedAsset"');
) }
->before($end)->after($start) );
->where('transaction_journals.user_id', Auth::user()->id) }
->groupBy('t_from.account_id')->orderBy('transaction_journals.date') );
->get( } else {
['transaction_journals.id', // any deposit is fine.
'transaction_journals.description', $query->where('transaction_types.type', 'Deposit');
'transaction_journals.encrypted', }
'transaction_types.type', $query->before($end)->after($start)
't_to.amount', 'transaction_journals.date', 't_from.account_id as account_id', ->where('transaction_journals.user_id', Auth::user()->id)
'ac_from.name as name'] ->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 $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @return Collection
*/ */
public function journalsByBudget(Carbon $start, Carbon $end) public function journalsByBudget(Carbon $start, Carbon $end, $showSharedReports = false)
{ {
return Auth::user()->transactionjournals() $query = Auth::user()->transactionjournals()
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id') ->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id')
->leftJoin( ->leftJoin(
'transactions', function (JoinClause $join) { 'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0); $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
} }
) )
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id');
->leftJoin( if ($showSharedReports === false) {
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); $query->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('account_meta.data', '!=', '"sharedAsset"');
->where('transaction_journals.date', '<=', $end->format('Y-m-d')) }
->where('account_meta.data', '!=', '"sharedExpense"') $query->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->where('transaction_types.type', 'Withdrawal') ->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->groupBy('budgets.id') ->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->orderBy('budgets.name', 'ASC') ->where('transaction_types.type', 'Withdrawal')
->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) AS `spent`')]); ->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 $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @return Collection
*/ */
public function journalsByCategory(Carbon $start, Carbon $end) public function journalsByCategory(Carbon $start, Carbon $end, $showSharedReports = false)
{ {
return Auth::user()->transactionjournals() $query = Auth::user()->transactionjournals()
->leftJoin( ->leftJoin(
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id' 'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
) )
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id') ->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
->leftJoin( ->leftJoin(
'transactions', function (JoinClause $join) { 'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0); $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
} }
) )
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id');
->leftJoin( if ($showSharedReports === false) {
'account_meta', function (JoinClause $join) { $query->leftJoin(
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); '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('account_meta.data', '!=', '"sharedAsset"');
->where('transaction_journals.date', '>=', $start->format('Y-m-d')) }
->where('transaction_journals.date', '<=', $end->format('Y-m-d')) $query->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->where('account_meta.data', '!=', '"sharedExpense"') ->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_types.type', 'Withdrawal') ->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->groupBy('categories.id') ->where('transaction_types.type', 'Withdrawal')
->orderBy('amount') ->groupBy('categories.id')
->get(['categories.id', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `amount`')]); ->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 $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @return Collection
*/ */
public function journalsByExpenseAccount(Carbon $start, Carbon $end) public function journalsByExpenseAccount(Carbon $start, Carbon $end, $showSharedReports = false)
{ {
return TransactionJournal:: $query = TransactionJournal::leftJoin(
leftJoin(
'transactions as t_from', function (JoinClause $join) { 'transactions as t_from', function (JoinClause $join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); $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('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id') ->leftJoin(
->leftJoin( 'account_meta as acm_from', function (JoinClause $join) {
'account_meta as acm_from', function (JoinClause $join) { $join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole'); }
} )
) ->leftJoin(
->leftJoin( 'transactions as t_to', function (JoinClause $join) {
'transactions as t_to', function (JoinClause $join) { $join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
$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('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id') ->leftJoin(
->leftJoin( 'account_meta as acm_to', function (JoinClause $join) {
'account_meta as acm_to', function (JoinClause $join) { $join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
$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');
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->where( if ($showSharedReports === false) {
function ($query) { // get all withdrawals not from a shared accounts
$query->where( // and all transfers to a shared account
function ($q) { $query->where(
$q->where('transaction_types.type', 'Withdrawal'); function ($query) {
$q->where('acm_from.data', '!=', '"sharedExpense"'); $query->where(
} function ($q) {
); $q->where('transaction_types.type', 'Withdrawal');
$query->orWhere( $q->where('acm_from.data', '!=', '"sharedAsset"');
function ($q) { }
$q->where('transaction_types.type', 'Transfer'); );
$q->where('acm_to.data', '=', '"sharedExpense"'); $query->orWhere(
} function ($q) {
); $q->where('transaction_types.type', 'Transfer');
} $q->where('acm_to.data', '=', '"sharedAsset"');
) }
->before($end) );
->after($start) }
->where('transaction_journals.user_id', Auth::user()->id) );
->groupBy('t_to.account_id') } else {
->orderBy('amount', 'DESC') // any withdrawal goes:
->get(['t_to.account_id as id', 'ac_to.name as name', DB::Raw('SUM(t_to.amount) as `amount`')]); $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 $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @return Collection
*/ */
public function journalsByRevenueAccount(Carbon $start, Carbon $end) public function journalsByRevenueAccount(Carbon $start, Carbon $end, $showSharedReports = false)
{ {
return TransactionJournal:: $query = TransactionJournal::
leftJoin( leftJoin(
'transactions as t_from', function (JoinClause $join) { 'transactions as t_from', function (JoinClause $join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); $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('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin( ->leftJoin(
'account_meta as acm_from', function (JoinClause $join) { 'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole'); $join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
} }
) )
->leftJoin( ->leftJoin(
'transactions as t_to', function (JoinClause $join) { 'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0); $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('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin( ->leftJoin(
'account_meta as acm_to', function (JoinClause $join) { 'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole'); $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') ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
->where( if ($showSharedReports === false) {
function ($query) {
$query->where( // show queries where transfer type is deposit, and its not to a shared account
function ($q) { // or where its a transfer and its from a shared account (both count as incomes)
$q->where('transaction_types.type', 'Deposit'); $query->where(
$q->where('acm_to.data', '!=', '"sharedExpense"'); function ($query) {
} $query->where(
); function ($q) {
$query->orWhere( $q->where('transaction_types.type', 'Deposit');
function ($q) { $q->where('acm_to.data', '!=', '"sharedAsset"');
$q->where('transaction_types.type', 'Transfer'); }
$q->where('acm_from.data', '=', '"sharedExpense"'); );
} $query->orWhere(
); function ($q) {
} $q->where('transaction_types.type', 'Transfer');
) $q->where('acm_from.data', '=', '"sharedAsset"');
->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`')]); );
} 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'); $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) ->after($start)
->before($end) ->before($end)
->where('transaction_types.type', 'Transfer') ->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' 'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
) )
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id') ->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
->where('account_meta.data', '"sharedExpense"') ->where('account_meta.data', '"sharedAsset"')
->after($start) ->after($start)
->before($end) ->before($end)
->where('transaction_types.type', 'Transfer') ->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. * This query retrieves a list of accounts that are active and not shared.
* *
* @param bool $showSharedReports
*
* @return Collection * @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. * Get a users accounts combined with various meta-data related to the start and end date.
* *
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @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 * 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 $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @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. * Gets a list of expenses grouped by the budget they were filed under.
* *
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @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. * 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 $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @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. * 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 $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @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, * This method returns all deposits into asset accounts, grouped by the revenue account,
* *
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports
* *
* @return Collection * @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 * With an equally misleading name, this query returns are transfers to shared accounts. These are considered
@@ -108,27 +163,4 @@ interface ReportQueryInterface
* @return Collection * @return Collection
*/ */
public function sharedExpensesByCategory(Carbon $start, Carbon $end); 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; <?php namespace FireflyIII\Http\Controllers;
use App;
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Config; use Config;
@@ -8,9 +7,11 @@ use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\AccountFormRequest; use FireflyIII\Http\Requests\AccountFormRequest;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator;
use Input; use Input;
use Redirect; use Redirect;
use Session; use Session;
use Steam;
use View; use View;
/** /**
@@ -74,6 +75,12 @@ class AccountController extends Controller
return Redirect::route('accounts.index', $typeName); return Redirect::route('accounts.index', $typeName);
} }
/**
* @param Account $account
* @param AccountRepositoryInterface $repository
*
* @return View
*/
public function edit(Account $account, AccountRepositoryInterface $repository) public function edit(Account $account, AccountRepositoryInterface $repository)
{ {
$what = Config::get('firefly.shortNamesByFullName')[$account->accountType->type]; $what = Config::get('firefly.shortNamesByFullName')[$account->accountType->type];
@@ -110,29 +117,59 @@ class AccountController extends Controller
$subTitle = Config::get('firefly.subTitlesByIdentifier.' . $what); $subTitle = Config::get('firefly.subTitlesByIdentifier.' . $what);
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what); $subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
$types = Config::get('firefly.accountTypesByIdentifier.' . $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')); return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
} }
/** /**
* @param Account $account * @param Account $account
* @param string $range
* @param AccountRepositoryInterface $repository * @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')); $page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $account->accountType->type); $subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $account->accountType->type);
$what = Config::get('firefly.shortNamesByFullName.' . $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) . '"'; $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!'); 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')); return Redirect::route('accounts.index', $request->input('what'));
} }
@@ -186,6 +227,10 @@ class AccountController extends Controller
Session::flash('success', 'Account "' . $account->name . '" updated.'); 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); 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\Guard;
use Illuminate\Contracts\Auth\Registrar; use Illuminate\Contracts\Auth\Registrar;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers; use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Http\Request;
use Mail;
use Session;
/** /**
* Class AuthController * Class AuthController
@@ -43,4 +46,40 @@ class AuthController extends Controller
$this->middleware('guest', ['except' => 'getLogout']); $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\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Input;
use Redirect; use Redirect;
use Session; use Session;
use URL; use URL;
@@ -80,7 +81,7 @@ class BillController extends Controller
*/ */
public function index(BillRepositoryInterface $repository) public function index(BillRepositoryInterface $repository)
{ {
$bills = Auth::user()->bills()->get(); $bills = Auth::user()->bills()->orderBy('name', 'ASC')->get();
$bills->each( $bills->each(
function (Bill $bill) use ($repository) { function (Bill $bill) use ($repository) {
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill); $bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
@@ -108,7 +109,9 @@ class BillController extends Controller
return Redirect::intended('/'); 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 = []; $ids = [];
/** @var Transaction $entry */ /** @var Transaction $entry */
@@ -116,7 +119,7 @@ class BillController extends Controller
$ids[] = intval($entry->transaction_journal_id); $ids[] = intval($entry->transaction_journal_id);
} }
if (count($ids) > 0) { if (count($ids) > 0) {
$journals = Auth::user()->transactionjournals()->whereIn('id',$ids)->get(); $journals = Auth::user()->transactionjournals()->whereIn('id', $ids)->get();
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
$repository->scan($bill, $journal); $repository->scan($bill, $journal);
@@ -168,6 +171,10 @@ class BillController extends Controller
$bill = $repository->store($billData); $bill = $repository->store($billData);
Session::flash('success', 'Bill "' . e($bill->name) . '" stored.'); 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'); return Redirect::route('bills.index');
} }
@@ -195,6 +202,10 @@ class BillController extends Controller
$bill = $repository->update($bill, $billData); $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.'); Session::flash('success', 'Bill "' . e($bill->name) . '" updated.');
return Redirect::route('bills.index'); return Redirect::route('bills.index');

View File

@@ -7,10 +7,10 @@ use FireflyIII\Http\Requests\CategoryFormRequest;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Input;
use Redirect; use Redirect;
use Session; use Session;
use View; use View;
use Input;
/** /**
@@ -38,44 +38,6 @@ class CategoryController extends Controller
return view('categories.create')->with('subTitle', 'Create a new category'); 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 * @param Category $category
* *
@@ -122,11 +84,61 @@ class CategoryController extends Controller
*/ */
public function index() 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 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 CategoryFormRequest $request
* @param CategoryRepositoryInterface $repository * @param CategoryRepositoryInterface $repository

View File

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

View File

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

View File

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

View File

@@ -3,11 +3,11 @@
use Auth; use Auth;
use Cache; use Cache;
use Carbon\Carbon; use Carbon\Carbon;
use Navigation; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Input;
use Preferences; use Preferences;
use Redirect; use Redirect;
use Session; use Session;
use URL;
/** /**
* Class HomeController * 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 * @return \Illuminate\Http\RedirectResponse
*/ */
@@ -37,9 +52,10 @@ class HomeController extends Controller
/** /**
* @return \Illuminate\View\View * @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'; $title = 'Firefly';
$subTitle = 'What\'s playing?'; $subTitle = 'What\'s playing?';
$mainTitleIcon = 'fa-fire'; $mainTitleIcon = 'fa-fire';
@@ -47,25 +63,10 @@ class HomeController extends Controller
$frontPage = Preferences::get('frontPageAccounts', []); $frontPage = Preferences::get('frontPageAccounts', []);
$start = Session::get('start', Carbon::now()->startOfMonth()); $start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth()); $end = Session::get('end', Carbon::now()->endOfMonth());
$accounts = $repository->getFrontpageAccounts($frontPage);
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.*']);
}
foreach ($accounts as $account) { foreach ($accounts as $account) {
$set = Auth::user() $set = $repository->getFrontpageTransactions($account, $start, $end);
->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.*']);
if (count($set) > 0) { if (count($set) > 0) {
$transactions[] = [$set, $account]; $transactions[] = [$set, $account];
} }
@@ -76,49 +77,5 @@ class HomeController extends Controller
return view('index', compact('count', 'title', 'subTitle', 'mainTitleIcon', 'transactions')); 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; <?php namespace FireflyIII\Http\Controllers;
use FireflyIII\Http\Requests; use Amount;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Response;
use Auth; 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 * Class JsonController
* *
* @package FireflyIII\Http\Controllers * @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. * Returns a list of categories.
* *
@@ -22,15 +115,13 @@ class JsonController extends Controller {
*/ */
public function categories() public function categories()
{ {
$list = Auth::user()->categories()->orderBy('name','ASC')->get(); $list = Auth::user()->categories()->orderBy('name', 'ASC')->get();
$return = []; $return = [];
foreach ($list as $entry) { foreach ($list as $entry) {
$return[] = $entry->name; $return[] = $entry->name;
} }
return Response::json($return); return Response::json($return);
} }
/** /**
@@ -40,8 +131,8 @@ class JsonController extends Controller {
*/ */
public function expenseAccounts() public function expenseAccounts()
{ {
$list = Auth::user()->accounts()->accountTypeIn(['Expense account', 'Beneficiary account'])->get(); $list = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Expense account', 'Beneficiary account'])->get();
$return = []; $return = [];
foreach ($list as $entry) { foreach ($list as $entry) {
$return[] = $entry->name; $return[] = $entry->name;
} }
@@ -55,8 +146,8 @@ class JsonController extends Controller {
*/ */
public function revenueAccounts() public function revenueAccounts()
{ {
$list = Auth::user()->accounts()->accountTypeIn(['Revenue account'])->get(); $list = Auth::user()->accounts()->accountTypeIn(['Revenue account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$return = []; $return = [];
foreach ($list as $entry) { foreach ($list as $entry) {
$return[] = $entry->name; $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\Http\Requests\PiggyBankFormRequest;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -62,7 +63,9 @@ class PiggyBankController extends Controller
{ {
$periods = Config::get('firefly.piggy_bank_periods'); $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'; $subTitle = 'Create new piggy bank';
$subTitleIcon = 'fa-plus'; $subTitleIcon = 'fa-plus';
@@ -78,7 +81,7 @@ class PiggyBankController extends Controller
{ {
$subTitle = 'Delete "' . e($piggyBank->name) . '"'; $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.'); 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'); $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) . '"'; $subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"';
$subTitleIcon = 'fa-pencil'; $subTitleIcon = 'fa-pencil';
@@ -124,7 +129,7 @@ class PiggyBankController extends Controller
'targetamount' => $piggyBank->targetamount, 'targetamount' => $piggyBank->targetamount,
'targetdate' => $targetDate, 'targetdate' => $targetDate,
'reminder' => $piggyBank->reminder, '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); Session::flash('preFilled', $preFilled);
@@ -191,6 +196,9 @@ class PiggyBankController extends Controller
$repetition->currentamount += $amount; $repetition->currentamount += $amount;
$repetition->save(); $repetition->save();
// create event.
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
/* /*
* Create event! * Create event!
*/ */
@@ -220,6 +228,8 @@ class PiggyBankController extends Controller
$repetition->currentamount -= $amount; $repetition->currentamount -= $amount;
$repetition->save(); $repetition->save();
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount * -1, 'piggy_bank_id' => $piggyBank->id]);
/* /*
* Create event! * Create event!
*/ */
@@ -278,12 +288,18 @@ class PiggyBankController extends Controller
'targetamount' => floatval($request->get('targetamount')), 'targetamount' => floatval($request->get('targetamount')),
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null, 'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
'reminder' => $request->get('reminder'), 'reminder' => $request->get('reminder'),
'remind_me' => $request->get('remind_me'),
]; ];
$piggyBank = $repository->store($piggyBankData); $piggyBank = $repository->store($piggyBankData);
Session::flash('success', 'Stored piggy bank "' . e($piggyBank->name) . '".'); 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'); return Redirect::route('piggy-banks.index');
} }
@@ -299,21 +315,28 @@ class PiggyBankController extends Controller
$piggyBankData = [ $piggyBankData = [
'repeats' => false, 'repeats' => false,
'name' => $request->get('name'), 'name' => $request->get('name'),
'startdate' => is_null($piggyBank->startdate) ? $piggyBank->created_at : $piggyBank->startdate,
'account_id' => intval($request->get('account_id')), 'account_id' => intval($request->get('account_id')),
'targetamount' => floatval($request->get('targetamount')), 'targetamount' => floatval($request->get('targetamount')),
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null, 'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
'reminder' => $request->get('reminder'), 'reminder' => $request->get('reminder'),
'remind_me' => $request->get('remind_me')
]; ];
$piggyBank = $repository->update($piggyBank, $piggyBankData); $piggyBank = $repository->update($piggyBank, $piggyBankData);
Session::flash('success', 'Updated piggy bank "' . e($piggyBank->name) . '".'); 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'); return Redirect::route('piggy-banks.index');
} }
} }

View File

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

View File

@@ -1,15 +1,16 @@
<?php namespace FireflyIII\Http\Controllers; <?php namespace FireflyIII\Http\Controllers;
use Amount;
use Auth; use Auth;
use FireflyIII\Http\Requests; use FireflyIII\Http\Requests;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Response;
use Input; use Input;
use Redirect;
use Response;
use URL;
/** /**
* Class RelatedController * 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) { if (count($unique) > 0) {
$set = Auth::user()->transactionjournals()->whereIn('id', $unique)->get(); $journals = Auth::user()->transactionjournals()->whereIn('id', $unique)->get();
$set->each( $journals->each(
function (TransactionJournal $journal) { function (TransactionJournal $journal) {
/** @var Transaction $t */ /** @var Transaction $t */
foreach ($journal->transactions()->get() as $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'))); $search = e(trim(Input::get('searchValue')));
$parent = $journal;
$result = $repository->searchRelated($search, $journal); $journals = $repository->searchRelated($search, $journal);
$result->each(
function (TransactionJournal $journal) { return view('related.searchResult', compact('journals', 'search', 'parent'));
/** @var Transaction $t */
foreach ($journal->transactions()->get() as $t) {
if ($t->amount > 0) {
$journal->amount = $t->amount;
}
}
}
);
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() public function create()
{ {
$periods = Config::get('firefly.piggy_bank_periods'); $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( return view('repeatedExpense.create', compact('accounts', 'periods'))->with('subTitle', 'Create new repeated expense')->with(
'subTitleIcon', 'fa-plus' 'subTitleIcon', 'fa-plus'
@@ -79,7 +81,9 @@ class RepeatedExpenseController extends Controller
{ {
$periods = Config::get('firefly.piggy_bank_periods'); $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) . '"'; $subTitle = 'Edit repeated expense "' . e($repeatedExpense->name) . '"';
$subTitleIcon = 'fa-pencil'; $subTitleIcon = 'fa-pencil';
@@ -183,7 +187,7 @@ class RepeatedExpenseController extends Controller
'rep_length' => $request->get('rep_length'), 'rep_length' => $request->get('rep_length'),
'rep_every' => intval($request->get('rep_every')), 'rep_every' => intval($request->get('rep_every')),
'rep_times' => intval($request->get('rep_times')), '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'), 'reminder' => $request->get('reminder'),
]; ];

View File

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

View File

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

View File

@@ -3,13 +3,14 @@
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use ExpandedForm; use ExpandedForm;
use FireflyIII\Events\JournalCreated;
use FireflyIII\Events\JournalSaved;
use FireflyIII\Http\Requests; use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\JournalFormRequest; use FireflyIII\Http\Requests\JournalFormRequest;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Input; use Input;
use Redirect; use Redirect;
use Session; use Session;
@@ -41,7 +42,9 @@ class TransactionController extends Controller
public function create($what = 'deposit') public function create($what = 'deposit')
{ {
$accounts = ExpandedForm::makeSelectList( $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 = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = '(no budget)'; $budgets[0] = '(no budget)';
@@ -118,7 +121,9 @@ class TransactionController extends Controller
{ {
$what = strtolower($journal->transactiontype->type); $what = strtolower($journal->transactiontype->type);
$accounts = ExpandedForm::makeSelectList( $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 = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = '(no budget)'; $budgets[0] = '(no budget)';
@@ -143,7 +148,7 @@ class TransactionController extends Controller
} }
if ($journal->piggyBankEvents()->count() > 0) { 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; $preFilled['amount'] = 0;
@@ -227,25 +232,15 @@ class TransactionController extends Controller
$t->after = $t->before + $t->amount; $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) . '"' 'subTitle', e($journal->transactiontype->type) . ' "' . e($journal->description) . '"'
); );
} }
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository) public function store(JournalFormRequest $request, JournalRepositoryInterface $repository)
{ {
$journalData = [ $journalData = [
'what' => $request->get('what'), 'what' => $request->get('what'),
'description' => $request->get('description'), 'description' => $request->get('description'),
@@ -264,8 +259,21 @@ class TransactionController extends Controller
$journal = $repository->store($journalData); $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!'); 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')); 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) public function update(TransactionJournal $journal, JournalFormRequest $request, JournalRepositoryInterface $repository)
{ {
$journalData = [ $journalData = [
'what' => $request->get('what'), 'what' => $request->get('what'),
'description' => $request->get('description'), 'description' => $request->get('description'),
@@ -298,8 +307,16 @@ class TransactionController extends Controller
]; ];
$repository->update($journal, $journalData); $repository->update($journal, $journalData);
event(new JournalSaved($journal));
// update, get events by date and sort DESC
Session::flash('success', 'Transaction "' . e($journalData['description']) . '" updated.'); 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']); return Redirect::route('transactions.index', $journalData['what']);
} }

View File

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

View File

@@ -9,6 +9,7 @@ use Illuminate\Contracts\Auth\Guard;
use Navigation; use Navigation;
use Preferences; use Preferences;
use Session; use Session;
use View;
/** /**
* Class SessionFilter * Class SessionFilter
@@ -46,25 +47,36 @@ class Range
public function handle($request, Closure $theNext) public function handle($request, Closure $theNext)
{ {
if ($this->auth->check()) { 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: /** @var \FireflyIII\Models\Preference $viewRange */
$start = Session::has('start') ? Session::get('start') : new Carbon; $viewRange = Preferences::get('viewRange', '1M');
$start = Navigation::updateStartDate($viewRange->data, $start); $start = Session::has('start') ? Session::get('start') : new Carbon;
$end = Navigation::updateEndDate($viewRange->data, $start); $start = Navigation::updateStartDate($viewRange->data, $start);
$period = Navigation::periodName($viewRange->data, $start); $end = Navigation::updateEndDate($viewRange->data, $start);
$prev = Navigation::jumpToPrevious($viewRange->data, clone $start);
$next = Navigation::jumpToNext($viewRange->data, clone $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 <?php
/**
* Created by PhpStorm.
* User: sander
* Date: 25/02/15
* Time: 12:29
*/
namespace FireflyIII\Http\Requests; namespace FireflyIII\Http\Requests;
@@ -33,8 +27,8 @@ class BillFormRequest extends Request
public function rules() public function rules()
{ {
$nameRule = 'required|between:1,255|uniqueForUser:bills,name'; $nameRule = 'required|between:1,255|uniqueForUser:bills,name';
if(intval(Input::get('id')) > 0) { if (intval(Input::get('id')) > 0) {
$nameRule .= ','.intval(Input::get('id')); $nameRule = 'required|between:1,255';
} }
$rules = [ $rules = [

View File

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

View File

@@ -35,6 +35,7 @@ class JournalFormRequest extends Request
'what' => 'required|in:withdrawal,deposit,transfer|exists:transaction_types,type', 'what' => 'required|in:withdrawal,deposit,transfer|exists:transaction_types,type',
'amount' => 'numeric|required|min:0.01', 'amount' => 'numeric|required|min:0.01',
'date' => 'required|date', 'date' => 'required|date',
'reminder_id' => 'numeric|exists:reminders,id',
'amount_currency_id' => 'required|exists:transaction_currencies,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', 'rep_times' => 'integer|min:0|max:99',
'reminder' => 'in:day,week,quarter,month,year', 'reminder' => 'in:day,week,quarter,month,year',
'reminder_skip' => 'integer|min:0|max:99', 'reminder_skip' => 'integer|min:0|max:99',
'remind_me' => 'boolean', 'remind_me' => 'boolean|piggyBankReminder',
'order' => 'integer|min:1', 'order' => 'integer|min:1',
]; ];

View File

@@ -7,6 +7,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
@@ -239,8 +240,17 @@ Breadcrumbs::register(
// reminders // reminders
Breadcrumbs::register( Breadcrumbs::register(
'reminders.show', function (Generator $breadcrumbs, Reminder $reminder) { 'reminders.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $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)); $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\Budget;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\PiggyBank;
// models // 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( Route::bind(
'limitrepetition', function ($value, $route) { 'limitrepetition', function ($value, $route) {
if (Auth::check()) { if (Auth::check()) {
@@ -135,7 +146,7 @@ Route::get('/register', ['uses' => 'Auth\AuthController@getRegister', 'as' => 'r
Route::controllers( Route::controllers(
[ [
'auth' => 'Auth\AuthController', 'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController', 'password' => 'Auth\PasswordController',
] ]
); );
@@ -145,12 +156,10 @@ Route::controllers(
* Home Controller * Home Controller
*/ */
Route::group( Route::group(
['middleware' => ['auth', 'range']], function () { ['middleware' => ['auth', 'range', 'reminders']], function () {
Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']); Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']);
Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']); Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']);
Route::get('/prev', ['uses' => 'HomeController@sessionPrev', 'as' => 'sessionPrev']); Route::post('/daterange', ['uses' => 'HomeController@dateRange', 'as' => 'daterange']);
Route::get('/next', ['uses' => 'HomeController@sessionNext', 'as' => 'sessionNext']);
Route::get('/jump/{range}', ['uses' => 'HomeController@rangeJump', 'as' => 'rangeJump']);
Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']); Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']);
/** /**
* Account Controller * Account Controller
@@ -232,11 +241,12 @@ Route::group(
Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']); Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']);
Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending']); Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending']);
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']); 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/{year}', ['uses' => 'GoogleChartController@yearInExp']);
Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']); Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']);
Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']); Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']);
Route::get('/chart/piggy-history/{piggyBank}', ['uses' => 'GoogleChartController@piggyBankHistory']); 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 * Help Controller
@@ -249,14 +259,17 @@ Route::group(
Route::get('/json/expense-accounts', ['uses' => 'JsonController@expenseAccounts', 'as' => 'json.expense-accounts']); 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/revenue-accounts', ['uses' => 'JsonController@revenueAccounts', 'as' => 'json.revenue-accounts']);
Route::get('/json/categories', ['uses' => 'JsonController@categories', 'as' => 'json.categories']); 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 * Piggy Bank Controller
*/ */
Route::get('/piggy-banks', ['uses' => 'PiggyBankController@index', 'as' => 'piggy-banks.index']); 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/add/{piggyBank}', ['uses' => 'PiggyBankController@add', 'as' => 'piggy-banks.addMoney']); # add money
Route::get('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove']); #remove 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/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/edit/{piggyBank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy-banks.edit']);
Route::get('/piggy-banks/delete/{piggyBank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy-banks.delete']); 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', ['uses' => 'ProfileController@index', 'as' => 'profile']);
Route::get('/profile/change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']); 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 * Related transactions controller
@@ -286,9 +299,19 @@ Route::group(
Route::get('/related/alreadyRelated/{tj}', ['uses' => 'RelatedController@alreadyRelated', 'as' => 'related.alreadyRelated']); 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/relate/{tj}/{tjSecond}', ['uses' => 'RelatedController@relate', 'as' => 'related.relate']);
Route::post('/related/removeRelation/{tj}/{tjSecond}', ['uses' => 'RelatedController@removeRelation', 'as' => 'related.removeRelation']); 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::get('/related/related/{tj}', ['uses' => 'RelatedController@related', 'as' => 'related.related']);
Route::post('/related/search/{tj}', ['uses' => 'RelatedController@search', 'as' => 'related.search']); 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 * Repeated Expenses Controller
*/ */
@@ -309,6 +332,16 @@ Route::group(
Route::get('/reports/{year}/{month}', ['uses' => 'ReportController@month', 'as' => 'reports.month']); Route::get('/reports/{year}/{month}', ['uses' => 'ReportController@month', 'as' => 'reports.month']);
Route::get('/reports/budget/{year}/{month}', ['uses' => 'ReportController@budget', 'as' => 'reports.budget']); 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 * Search Controller
*/ */

View File

@@ -4,7 +4,7 @@ use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
use Crypt;
/** /**
* Class Account * Class Account
* *
@@ -18,7 +18,7 @@ class Account extends Model
= [ = [
'user_id' => 'required|exists:users,id', 'user_id' => 'required|exists:users,id',
'account_type_id' => 'required|exists:account_types,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' '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 * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/ */

View File

@@ -14,7 +14,7 @@ class PiggyBank extends Model
{ {
use SoftDeletes; 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 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
@@ -24,6 +24,15 @@ class PiggyBank extends Model
return $this->belongsTo('FireflyIII\Models\Account'); 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 * Grabs the PiggyBankRepetition that's currently relevant / active
* *

View File

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

View File

@@ -1,7 +1,8 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Carbon\Carbon;
/** /**
* Class PiggyBankRepetition * Class PiggyBankRepetition
* *
@@ -26,4 +27,25 @@ class PiggyBankRepetition extends Model
return $this->belongsTo('FireflyIII\Models\PiggyBank'); 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; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
@@ -10,6 +12,19 @@ use Illuminate\Database\Eloquent\Model;
class Reminder extends 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 * @return array
*/ */
@@ -18,6 +33,26 @@ class Reminder extends Model
return ['created_at', 'updated_at', 'startdate', 'enddate']; 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 * @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/ */
@@ -26,6 +61,34 @@ class Reminder extends Model
return $this->morphTo(); 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 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/ */

View File

@@ -1,17 +1,19 @@
<?php namespace FireflyIII\Providers; <?php namespace FireflyIII\Providers;
use App;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition; use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\Facades\Navigation; use FireflyIII\Support\Facades\Navigation;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Log;
/** /**
* Class EventServiceProvider * Class EventServiceProvider
@@ -28,12 +30,14 @@ class EventServiceProvider extends ServiceProvider
*/ */
protected $listen protected $listen
= [ = [
'event.name' => [ 'FireflyIII\Events\JournalSaved' => [
'EventListener', 'FireflyIII\Handlers\Events\RescanJournal',
], 'FireflyIII\Handlers\Events\UpdateJournalConnection',
'App\Events\JournalDeleted' => [
'App\Handlers\Events\JournalDeletedHandler@handle',
], ],
'FireflyIII\Events\JournalCreated' => [
'FireflyIII\Handlers\Events\ConnectJournalToPiggyBank',
]
]; ];
/** /**
@@ -57,6 +61,8 @@ class EventServiceProvider extends ServiceProvider
} }
); );
Account::deleted( Account::deleted(
function (Account $account) { 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 = new PiggyBankRepetition;
$repetition->piggyBank()->associate($piggyBank); $repetition->piggyBank()->associate($piggyBank);
$repetition->startdate = $piggyBank->startdate; $repetition->startdate = is_null($piggyBank->startdate) ? null : $piggyBank->startdate;
$repetition->targetdate = $piggyBank->targetdate; $repetition->targetdate = is_null($piggyBank->targetdate) ? null : $piggyBank->targetdate;
$repetition->currentamount = 0; $repetition->currentamount = 0;
$repetition->save(); $repetition->save();
}); }
);
BudgetLimit::saved( BudgetLimit::saved(
function (BudgetLimit $budgetLimit) { 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\Repositories\PiggyBank\PiggyBankRepositoryInterface', 'FireflyIII\Repositories\PiggyBank\PiggyBankRepository');
$this->app->bind('FireflyIII\Support\Search\SearchInterface', 'FireflyIII\Support\Search\Search'); $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\ReportHelperInterface', 'FireflyIII\Helpers\Report\ReportHelper');
$this->app->bind('FireflyIII\Helpers\Report\ReportQueryInterface', 'FireflyIII\Helpers\Report\ReportQuery'); $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\AccountMeta;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Log; use Log;
use Session; use Session;
@@ -25,6 +27,14 @@ use Session;
class AccountRepository implements AccountRepositoryInterface class AccountRepository implements AccountRepositoryInterface
{ {
/**
* @return int
*/
public function countAssetAccounts()
{
return Auth::user()->accounts()->accountTypeIn(['Asset account', 'Default account'])->count();
}
/** /**
* @param Account $account * @param Account $account
* *
@@ -37,16 +47,53 @@ class AccountRepository implements AccountRepositoryInterface
return true; 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 Account $account
* @param int $page * @param Carbon $start
* @param string $range * @param Carbon $end
* *
* @return mixed * @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() $query = Auth::user()
->transactionJournals() ->transactionJournals()
->withRelevantData() ->withRelevantData()
@@ -54,10 +101,8 @@ class AccountRepository implements AccountRepositoryInterface
->where('transactions.account_id', $account->id) ->where('transactions.account_id', $account->id)
->orderBy('date', 'DESC'); ->orderBy('date', 'DESC');
if ($range == 'session') { $query->before(Session::get('end', Carbon::now()->endOfMonth()));
$query->before(Session::get('end', Carbon::now()->startOfMonth())); $query->after(Session::get('start', Carbon::now()->startOfMonth()));
$query->after(Session::get('start', Carbon::now()->startOfMonth()));
}
$count = $query->count(); $count = $query->count();
$set = $query->take(50)->offset($offset)->get(['transaction_journals.*']); $set = $query->take(50)->offset($offset)->get(['transaction_journals.*']);
$paginator = new LengthAwarePaginator($set, $count, 50, $page); $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 * @param Account $account
* *
@@ -123,13 +185,7 @@ class AccountRepository implements AccountRepositoryInterface
$account->save(); $account->save();
// update meta data: // update meta data:
/** @var AccountMeta $meta */ $this->_updateMetadata($account, $data);
foreach ($account->accountMeta()->get() as $meta) {
if ($meta->name == 'accountRole') {
$meta->data = $data['accountRole'];
$meta->save();
}
}
$openingBalance = $this->openingBalanceTransaction($account); $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 Account $account
* @param TransactionJournal $journal * @param TransactionJournal $journal
@@ -310,21 +400,4 @@ class AccountRepository implements AccountRepositoryInterface
return $journal; 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\Account;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Preference;
use Illuminate\Support\Collection;
use Carbon\Carbon;
/** /**
* Interface AccountRepositoryInterface * Interface AccountRepositoryInterface
* *
@@ -19,14 +21,34 @@ interface AccountRepositoryInterface
*/ */
public function destroy(Account $account); 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 Account $account
* @param int $page
* @param string $range * @param string $range
* *
* @return mixed * @return mixed
*/ */
public function getJournals(Account $account, $page, $range = 'session'); public function getJournals(Account $account, $page);
/** /**
* @param Account $account * @param Account $account

View File

@@ -1,18 +1,12 @@
<?php <?php
/**
* Created by PhpStorm.
* User: sander
* Date: 25/02/15
* Time: 07:40
*/
namespace FireflyIII\Repositories\Bill; namespace FireflyIII\Repositories\Bill;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Navigation;
use Log; use Log;
use Navigation;
/** /**
* Class BillRepository * Class BillRepository
@@ -21,6 +15,54 @@ use Log;
*/ */
class BillRepository implements BillRepositoryInterface 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 * @param Bill $bill
* *
@@ -28,6 +70,7 @@ class BillRepository implements BillRepositoryInterface
*/ */
public function nextExpectedMatch(Bill $bill) public function nextExpectedMatch(Bill $bill)
{ {
$finalDate = null; $finalDate = null;
if ($bill->active == 0) { if ($bill->active == 0) {
return $finalDate; return $finalDate;
@@ -113,7 +156,7 @@ class BillRepository implements BillRepositoryInterface
$wordMatch = true; $wordMatch = true;
Log::debug('word match is true'); Log::debug('word match is true');
} else { } else {
Log::debug('Count: ' . $count.', count(matches): ' . count($matches)); Log::debug('Count: ' . $count . ', count(matches): ' . count($matches));
} }

View File

@@ -1,13 +1,8 @@
<?php <?php
/**
* Created by PhpStorm.
* User: sander
* Date: 25/02/15
* Time: 07:40
*/
namespace FireflyIII\Repositories\Bill; namespace FireflyIII\Repositories\Bill;
use Carbon\Carbon;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -25,6 +20,19 @@ interface BillRepositoryInterface {
*/ */
public function nextExpectedMatch(Bill $bill); 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 * @param array $data
* *

View File

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

View File

@@ -2,8 +2,12 @@
namespace FireflyIII\Repositories\PiggyBank; namespace FireflyIII\Repositories\PiggyBank;
use Amount;
use Auth;
use Carbon\Carbon;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition; use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\Reminder;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Navigation; use Navigation;
@@ -15,49 +19,6 @@ use Navigation;
class PiggyBankRepository implements PiggyBankRepositoryInterface 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. * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
* *
@@ -126,4 +87,50 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return $part; 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\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition; use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\Reminder;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Carbon\Carbon;
/** /**
* Interface PiggyBankRepositoryInterface * Interface PiggyBankRepositoryInterface
* *
* @package FireflyIII\Repositories\PiggyBank * @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. * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
* *
@@ -48,4 +36,21 @@ interface PiggyBankRepositoryInterface {
* @return PiggyBankPart * @return PiggyBankPart
*/ */
public function createPiggyBankPart(array $data); 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 Input;
use Session; use Session;
use View; use View;
use Amount as Amt;
/** /**
* Class ExpandedForm * Class ExpandedForm
@@ -17,46 +18,6 @@ use View;
class ExpandedForm 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 $name
* @param null $value * @param null $value
@@ -72,7 +33,7 @@ class ExpandedForm
$value = $this->fillFieldValue($name, $value); $value = $this->fillFieldValue($name, $value);
$options['step'] = 'any'; $options['step'] = 'any';
$options['min'] = '0.01'; $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(); $currencies = TransactionCurrency::orderBy('code', 'ASC')->get();
$html = View::make('form.amount', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); $html = View::make('form.amount', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
@@ -91,9 +52,19 @@ class ExpandedForm
if (isset($options['label'])) { if (isset($options['label'])) {
return $options['label']; return $options['label'];
} }
$labels = ['amount_min' => 'Amount (min)', 'amount_max' => 'Amount (max)', 'match' => 'Matches on', 'repeat_freq' => 'Repetition', $labels = [
'account_from_id' => 'Account from', 'account_to_id' => 'Account to', 'account_id' => 'Asset account', 'budget_id' => 'Budget' 'amount_min' => 'Amount (min)',
, 'piggy_bank_id' => 'Piggy bank']; '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)); return isset($labels[$name]) ? $labels[$name] : str_replace('_', ' ', ucfirst($name));
@@ -157,7 +128,7 @@ class ExpandedForm
public function fillFieldValue($name, $value) public function fillFieldValue($name, $value)
{ {
if (Session::has('preFilled')) { if (Session::has('preFilled')) {
$preFilled = \Session::get('preFilled'); $preFilled = Session::get('preFilled');
$value = isset($preFilled[$name]) && is_null($value) ? $preFilled[$name] : $value; $value = isset($preFilled[$name]) && is_null($value) ? $preFilled[$name] : $value;
} }
if (!is_null(Input::old($name))) { if (!is_null(Input::old($name))) {
@@ -181,7 +152,7 @@ class ExpandedForm
$classes = $this->getHolderClasses($name); $classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value); $value = $this->fillFieldValue($name, $value);
$options['step'] = 'any'; $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(); $currencies = TransactionCurrency::orderBy('code', 'ASC')->get();
$html = View::make('form.balance', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); $html = View::make('form.balance', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
@@ -229,6 +200,26 @@ class ExpandedForm
return $html; 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. * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
* *
@@ -246,7 +237,7 @@ class ExpandedForm
$selectList[0] = '(none)'; $selectList[0] = '(none)';
} }
$fields = ['title', 'name', 'description']; $fields = ['title', 'name', 'description'];
/** @var \Eloquent $entry */ /** @var Eloquent $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
$id = intval($entry->id); $id = intval($entry->id);
$title = null; $title = null;
@@ -270,9 +261,9 @@ class ExpandedForm
*/ */
public function optionsList($type, $name) public function optionsList($type, $name)
{ {
$previousValue = \Input::old('post_submit_action'); $previousValue = Input::old('post_submit_action');
$previousValue = is_null($previousValue) ? 'store' : $previousValue; $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; return $html;
} }
@@ -291,7 +282,26 @@ class ExpandedForm
$options = $this->expandOptionArray($name, $label, $options); $options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name); $classes = $this->getHolderClasses($name);
$selected = $this->fillFieldValue($name, $selected); $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; return $html;
} }

View File

@@ -28,20 +28,27 @@ class Navigation
$add = ($skip + 1); $add = ($skip + 1);
$functionMap = [ $functionMap = [
'1D' => 'addDays',
'daily' => 'addDays', 'daily' => 'addDays',
'1W' => 'addWeeks',
'weekly' => 'addWeeks', 'weekly' => 'addWeeks',
'week' => 'addWeeks', 'week' => 'addWeeks',
'1M' => 'addMonths',
'month' => 'addMonths', 'month' => 'addMonths',
'monthly' => 'addMonths', 'monthly' => 'addMonths',
'3M' => 'addMonths',
'quarter' => 'addMonths', 'quarter' => 'addMonths',
'quarterly' => 'addMonths', 'quarterly' => 'addMonths',
'6M' => 'addMonths',
'half-year' => 'addMonths', 'half-year' => 'addMonths',
'year' => 'addYears', 'year' => 'addYears',
'yearly' => 'addYears', 'yearly' => 'addYears',
]; ];
$modifierMap = [ $modifierMap = [
'quarter' => 3, 'quarter' => 3,
'3M' => 3,
'quarterly' => 3, 'quarterly' => 3,
'6M' => 6,
'half-year' => 6, 'half-year' => 6,
]; ];
if (!isset($functionMap[$repeatFreq])) { if (!isset($functionMap[$repeatFreq])) {
@@ -68,24 +75,31 @@ class Navigation
$currentEnd = clone $theCurrentEnd; $currentEnd = clone $theCurrentEnd;
$functionMap = [ $functionMap = [
'1D' => 'addDay',
'daily' => 'addDay', 'daily' => 'addDay',
'1W' => 'addWeek',
'week' => 'addWeek', 'week' => 'addWeek',
'weekly' => 'addWeek', 'weekly' => 'addWeek',
'1M' => 'addMonth',
'month' => 'addMonth', 'month' => 'addMonth',
'monthly' => 'addMonth', 'monthly' => 'addMonth',
'3M' => 'addMonths',
'quarter' => 'addMonths', 'quarter' => 'addMonths',
'quarterly' => 'addMonths', 'quarterly' => 'addMonths',
'6M' => 'addMonths',
'half-year' => 'addMonths', 'half-year' => 'addMonths',
'year' => 'addYear', 'year' => 'addYear',
'yearly' => 'addYear', 'yearly' => 'addYear',
]; ];
$modifierMap = [ $modifierMap = [
'quarter' => 3, 'quarter' => 3,
'3M' => 3,
'quarterly' => 3, 'quarterly' => 3,
'half-year' => 6, '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])) { if (!isset($functionMap[$repeatFreq])) {
throw new FireflyException('Cannot do endOfPeriod for $repeat_freq ' . $repeatFreq); throw new FireflyException('Cannot do endOfPeriod for $repeat_freq ' . $repeatFreq);
@@ -298,15 +312,19 @@ class Navigation
$date = clone $theDate; $date = clone $theDate;
$functionMap = [ $functionMap = [
'daily' => 'startOfDay', '1D' => 'startOfDay',
'week' => 'startOfWeek', 'daily' => 'startOfDay',
'weekly' => 'startOfWeek', '1W' => 'startOfWeek',
'month' => 'startOfMonth', 'week' => 'startOfWeek',
'monthly' => 'startOfMonth', 'weekly' => 'startOfWeek',
'quarter' => 'firstOfQuarter', 'month' => 'startOfMonth',
'quartly' => 'firstOfQuarter', '1M' => 'startOfMonth',
'year' => 'startOfYear', 'monthly' => 'startOfMonth',
'yearly' => 'startOfYear', '3M' => 'firstOfQuarter',
'quarter' => 'firstOfQuarter',
'quarterly' => 'firstOfQuarter',
'year' => 'startOfYear',
'yearly' => 'startOfYear',
]; ];
if (isset($functionMap[$repeatFreq])) { if (isset($functionMap[$repeatFreq])) {
$function = $functionMap[$repeatFreq]; $function = $functionMap[$repeatFreq];
@@ -314,7 +332,7 @@ class Navigation
return $date; return $date;
} }
if ($repeatFreq == 'half-year') { if ($repeatFreq == 'half-year' || $repeatFreq == '6M') {
$month = intval($date->format('m')); $month = intval($date->format('m'));
$date->startOfYear(); $date->startOfYear();
if ($month >= 7) { if ($month >= 7) {
@@ -396,5 +414,47 @@ class Navigation
throw new FireflyException('updateStartDate cannot handle $range ' . $range); 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)) { if (is_null($pref)) {
$pref = new Preference; $pref = new Preference;
$pref->name = $name; $pref->name = $name;
$pref->user()->associate(Auth::user());
} }
$pref->data = $value; $pref->data = $value;
$pref->save(); if (!is_null(Auth::user()->id)) {
$pref->user()->associate(Auth::user());
$pref->save();
}
return $pref; return $pref;

View File

@@ -99,12 +99,4 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
return $this->hasMany('FireflyIII\Models\TransactionJournal'); 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; namespace FireflyIII\Validation;
use Auth; use Auth;
use Carbon\Carbon;
use DB; use DB;
use Illuminate\Validation\Validator; use Illuminate\Validation\Validator;
use Navigation;
/** /**
* Class FireflyValidator * 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 $attribute
* @param $value * @param $value
@@ -41,7 +68,11 @@ class FireflyValidator extends Validator
*/ */
public function validateUniqueForUser($attribute, $value, $parameters) 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) { if ($count == 0) {
return true; 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", "watson/validating": "dev-master",
"doctrine/dbal": "~2.5", "doctrine/dbal": "~2.5",
"illuminate/html": "~5.0", "illuminate/html": "~5.0",
"barryvdh/laravel-ide-helper": "~2.0",
"league/commonmark": "0.7.*" "league/commonmark": "0.7.*"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "@stable", "barryvdh/laravel-debugbar": "@stable",
"barryvdh/laravel-ide-helper": "~2.0",
"phpunit/phpunit": "~4.0", "phpunit/phpunit": "~4.0",
"phpspec/phpspec": "~2.1", "phpspec/phpspec": "~2.1",
"codeception/codeception": "@stable", "satooshi/php-coveralls": "0.6.1"
"codeception/c3": "@stable",
"league/factory-muffin": "~2.1",
"codeception/phpbuiltinserver": "*",
"codeception/specify": "*",
"codeception/verify": "*",
"fzaninotto/faker": "1.*",
"codeclimate/php-test-reporter": "dev-master"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [
@@ -60,14 +51,11 @@
"scripts": { "scripts": {
"post-install-cmd": [ "post-install-cmd": [
"php artisan clear-compiled", "php artisan clear-compiled",
"php artisan optimize", "php artisan optimize"
"Codeception\\c3\\Installer::copyC3ToRoot"
], ],
"post-update-cmd": [ "post-update-cmd": [
"php artisan clear-compiled", "php artisan clear-compiled",
"php artisan optimize", "php artisan optimize"
"Codeception\\c3\\Installer::copyC3ToRoot"
], ],
"post-create-project-cmd": [ "post-create-project-cmd": [
"php -r \"copy('.env.example', '.env');\"", "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' => [ 'accountRoles' => [
'defaultExpense' => 'Default expense account', 'defaultAsset' => 'Default asset account',
'sharedExpense' => 'Shared expense account' 'sharedAsset' => 'Shared asset account'
], ],
'range_to_text' => [ 'range_to_text' => [

View File

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

View File

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

View File

@@ -23,13 +23,17 @@ class ChangesForV322 extends Migration
// rename fields // rename fields
Schema::table( Schema::table(
'piggy_bank_events', function (Blueprint $table) { 'piggy_bank_events', function (Blueprint $table) {
$table->dropForeign('piggy_bank_events_piggy_bank_id_foreign');
$table->renameColumn('piggy_bank_id', 'piggybank_id'); $table->renameColumn('piggy_bank_id', 'piggybank_id');
$table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('cascade');
} }
); );
Schema::table( Schema::table(
'piggybank_repetitions', function (Blueprint $table) { 'piggybank_repetitions', function (Blueprint $table) {
$table->dropForeign('piggy_bank_repetitions_piggy_bank_id_foreign');
$table->renameColumn('piggy_bank_id', 'piggybank_id'); $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( Schema::table(
'budget_limits', function (Blueprint $table) { 'budget_limits', function (Blueprint $table) {
$table->dropForeign('bid_foreign'); $table->dropForeign('bid_foreign');
$table->dropUnique('unique_bl_combi'); $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]); $acc_c = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Delete me', 'active' => 1]);
// create account meta: // create account meta:
$meta_a = AccountMeta::create(['account_id' => $acc_a->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' => 'defaultExpense']); $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' => 'defaultExpense']); $meta_c = AccountMeta::create(['account_id' => $acc_c->id, 'name' => 'accountRole', 'data' => 'defaultAsset']);
// var_dump($meta_a->toArray()); // var_dump($meta_a->toArray());
// var_dump($meta_b->toArray()); // var_dump($meta_b->toArray());
// var_dump($meta_c->toArray()); // var_dump($meta_c->toArray());
@@ -279,7 +279,6 @@ class TestDataSeeder extends Seeder
); );
// and some events! // and some events!
PiggyBankEvent::create(['piggy_bank_id' => $newCamera->id, 'date' => $this->som, 'amount' => 100]); 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( $newClothes = PiggyBank::create(
@@ -301,27 +300,51 @@ class TestDataSeeder extends Seeder
); );
PiggyBankEvent::create(['piggy_bank_id' => $newClothes->id, 'date' => $this->som, 'amount' => 100]); 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( * New: create no less than eight piggy banks that
[ * create all sorts of reminders
'account_id' => $savings->id, */
'name' => 'Weekly reminder for clothes', $list = ['week','quarter','month','year'];
'targetamount' => 2000, $nextYear = clone $this->_startOfMonth;
'startdate' => $this->som, $nextYear->addYear();
'targetdate' => $next, foreach($list as $entry) {
'repeats' => 0,
'rep_length' => null, PiggyBank::create(
'rep_every' => 0, [
'rep_times' => null, 'account_id' => $savings->id,
'reminder' => 'week', 'name' => $entry.' piggy bank with target date.',
'reminder_skip' => 0, 'targetamount' => 1000,
'remind_me' => 1, 'startdate' => $this->som,
'order' => 0, 'targetdate' => $nextYear,
] 'repeats' => 0,
); 'rep_length' => null,
PiggyBankRepetition::create(['piggy_bank_id' => $weekly->id, 'startdate' => $this->som, 'targetdate' => $next, 'currentamount' => 0]); '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(); $user = User::whereEmail('thegrumpydictator@gmail.com')->first();
// for weekly piggy bank (clothes) // 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, '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"> syntaxCheck="false">
<testsuites> <testsuites>
<testsuite name="Application Test Suite"> <testsuite name="Application Test Suite">
<directory>./tests/</directory> <directory>./tests</directory>
</testsuite> </testsuite>
</testsuites> </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> <php>
<env name="APP_ENV" value="testing"/> <env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/> <env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/> <env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
</php> </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 { .huge {
font-size: 40px; font-size: 40px;
} }
.large {
font-size: 30px;
}
.panel-green { .panel-green {
border-color: #5cb85c; border-color: #5cb85c;

View File

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

View File

@@ -1,7 +1,8 @@
$(function () { $(function () {
if (typeof componentID !== 'undefined' && typeof repetitionID === 'undefined') { if (typeof categoryID !== 'undefined') {
googleColumnChart('chart/category/' + componentID + '/spending/' + year, 'componentOverview'); 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 () { $(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'));
}
);
}); });
@@ -22,3 +62,4 @@ function currencySelect(e) {
return false; return false;
} }

View File

@@ -3,7 +3,22 @@ google.setOnLoadCallback(drawChart);
function drawChart() { function drawChart() {
googleLineChart('chart/home/account', 'accounts-chart'); googleLineChart('chart/home/account', 'accounts-chart');
googleBarChart('chart/home/budgets','budgets-chart'); googleBarChart('chart/home/budgets', 'budgets-chart');
googleColumnChart('chart/home/categories','categories-chart'); googleColumnChart('chart/home/categories', 'categories-chart');
googlePieChart('chart/home/bills','bills-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) { function addMoney(e) {
var pigID = parseInt($(e.target).data('id')); 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; return false;
} }
function removeMoney(e) { function removeMoney(e) {
var pigID = parseInt($(e.target).data('id')); 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; return false;
} }

View File

@@ -1,23 +1,40 @@
$(document).ready(function () { $(document).ready(function () {
$('.relateTransaction').click(relateTransaction); $('.relateTransaction').click(relateTransactionDialog);
$('.unrelate-checkbox').click(unrelateTransaction); //$('.unrelate-checkbox').click(unrelateTransaction);
}); });
function unrelateTransaction(e) { function unrelateTransaction(e) {
var target = $(e.target); var target = $(e.target);
var id = target.data('id'); 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(); target.parent().parent().remove();
}).fail(function () { }).fail(function () {
alert('Could not!'); 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 target = $(e.target);
var ID = target.data('id'); var ID = target.data('id');
@@ -41,21 +58,12 @@ function relateTransaction(e) {
function searchRelatedTransactions(e, ID) { function searchRelatedTransactions(e, ID) {
var searchValue = $('#relatedSearchValue').val(); var searchValue = $('#relatedSearchValue').val();
if (searchValue != '') { if (searchValue != '') {
$.post('related/search/' + ID, {searchValue: searchValue,_token:token}).success(function (data) { $.post('related/search/' + ID, {searchValue: searchValue, _token: token}).success(function (data) {
// post each result to some div. // post the results to some div.
$('#relatedSearchResults').empty(); $('#relatedSearchResultsTitle').show();
$('#relatedSearchResults').empty().html(data);
$.each(data, function (i, row) { // remove any clicks.
var tr = $('<tr>'); $('.relate').unbind('click').on('click', doRelateNewTransaction);
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));
});
}).fail(function () { }).fail(function () {
alert('Could not search. Sorry.'); alert('Could not search. Sorry.');
@@ -69,38 +77,35 @@ function doRelateNewTransaction(e) {
// remove the row from the table: // remove the row from the table:
var target = $(e.target); var target = $(e.target);
var id = target.data('id'); var id = target.data('id');
var relateToId = target.data('relateto'); var parent = target.data('parent');
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!');
});
if (typeof id == "undefined" && typeof parent == "undefined") {
} else { target = target.parent();
alert('remove again!'); 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) { function getAlreadyRelatedTransactions(e, ID) {
//#alreadyRelated //#alreadyRelated
$.get('related/alreadyRelated/' + ID).success(function (data) { $.get('related/alreadyRelated/' + ID).success(function (data) {
$('#alreadyRelated').empty(); $('#alreadyRelated').empty().html(data);
$.each(data, function (i, row) { // some event triggers.
var tr = $('<tr>'); $('.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 () { }).fail(function () {
alert('Cannot get related stuff.'); alert('Cannot get related stuff.');
}); });

View File

@@ -7,3 +7,54 @@ if (typeof(google) != 'undefined') {
googleStackedColumnChart('chart/budgets/spending/' + year, 'budgets'); 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_dash" => "The :attribute may only contain letters, numbers, and dashes.",
"alpha_num" => "The :attribute may only contain letters and numbers.", "alpha_num" => "The :attribute may only contain letters and numbers.",
"array" => "The :attribute must be an array.", "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.", "before" => "The :attribute must be a date before :date.",
"between" => [ "between" => [
"numeric" => "The :attribute must be between :min and :max.", "numeric" => "The :attribute must be between :min and :max.",

View File

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

View File

@@ -2,7 +2,7 @@
@section('content') @section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $account) !!} {!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $account) !!}
<div class="row"> <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 panel-default">
<div class="panel-heading"> <div class="panel-heading">
<i class="fa fa-fw {{$subTitleIcon}} fa-fw"></i> {{{$account->name}}} <i class="fa fa-fw {{$subTitleIcon}} fa-fw"></i> {{{$account->name}}}
@@ -27,24 +27,6 @@
</div> </div>
</div> </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> </div>
@@ -66,7 +48,6 @@
@section('scripts') @section('scripts')
<script type="text/javascript"> <script type="text/javascript">
var accountID = {{{$account->id}}}; var accountID = {{{$account->id}}};
var view = '{{{$range}}}';
var currencyCode = '{{Amount::getCurrencyCode()}}'; var currencyCode = '{{Amount::getCurrencyCode()}}';
</script> </script>
<!-- load the libraries and scripts necessary for Google Charts: --> <!-- 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>
</div> </div>
<div class="panel-body">
@include('list.bills') @include('list.bills')
</div> </div>
</div>
</div> </div>
</div> </div>
@stop @stop

View File

@@ -5,7 +5,7 @@
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <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> <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>
<div class="modal-body"> <div class="modal-body">
<div class="input-group"> <div class="input-group">

View File

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

View File

@@ -1,12 +1,6 @@
@extends('layouts.default') @extends('layouts.default')
@section('content') @section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!} {!! 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="row">
<div class="col-lg-12 col-md-12 col-sm-12"> <div class="col-lg-12 col-md-12 col-sm-12">
<div class="panel panel-default"> <div class="panel panel-default">

View File

@@ -20,6 +20,10 @@
</div> </div>
</div> </div>
<div class="col-lg-3 col-md-3 col-sm-5"> <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($limits as $limit)
@foreach($limit->limitrepetitions as $rep) @foreach($limit->limitrepetitions as $rep)
<div class="panel panel-default"> <div class="panel panel-default">
@@ -64,6 +68,9 @@
@endforeach @endforeach
@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>
</div> </div>

View File

@@ -1,12 +1,6 @@
@extends('layouts.default') @extends('layouts.default')
@section('content') @section('content')
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) }} {{ 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="row">
<div class="col-lg-12 col-md-12 col-sm-12"> <div class="col-lg-12 col-md-12 col-sm-12">
<div class="panel panel-default"> <div class="panel panel-default">

View File

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

View File

@@ -3,7 +3,7 @@
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!} {!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
<div class="row"> <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 panel-default">
<div class="panel-heading"> <div class="panel-heading">
Currencies Currencies
@@ -14,23 +14,34 @@
</p> </p>
<ul> <ul>
@if(count($currencies) > 0) @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) @foreach($currencies as $currency)
<li> <tr>
<a href="{{route('currency.edit',$currency->id)}}"><i class="fa fa-fw fa-pencil"></i></a> <td>
<a href="{{route('currency.delete',$currency->id)}}"><i class="fa fa-fw fa-trash"></i></a> <div class="btn-group btn-group-sm">
{{{$currency->name}}} ({{{$currency->code}}}) ({{{$currency->symbol}}}) <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) @if($currency->id == $defaultCurrency->id)
<span class="label label-success">default</span> <span class="label label-success">default</span>
@else @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 @endif
</li> </td>
</tr>
@endforeach @endforeach
</table>
@endif @endif
<li><a href="{{route('currency.create')}}"><i class="fa fa-fw fa-plus-circle"></i> Add another currency</a></li> <p><a class="btn btn-success" href="{{route('currency.create')}}"><i class="fa fa-fw fa-plus-circle"></i> Add another currency</a></p>
</ul>
</div> </div>
</div> </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> </div>
@else @else
<!-- fancy new boxes -->
@include('partials.boxes')
<div class="row"> <div class="row">
@@ -61,8 +65,6 @@
</div> </div>
<div class="col-lg-4 col-md-6 col-sm-12"> <div class="col-lg-4 col-md-6 col-sm-12">
<!-- time based navigation -->
@include('partials.date_nav')
<!-- REMINDERS --> <!-- REMINDERS -->
<div class="panel panel-default"> <div class="panel panel-default">

View File

@@ -16,15 +16,17 @@
</title> </title>
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" type="text/css" media="all" /> <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/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="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="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" /> <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') @yield('styles')
<!--[if lt IE 9]> <!--[if lt IE 9]>
@@ -107,24 +109,35 @@
<!-- modal to relate transactions to each other --> <!-- modal to relate transactions to each other -->
<div class="modal fade" id="relationModal"> <div class="modal fade" id="relationModal">
</div>
<!-- default modal -->
<div class="modal fade" id="defaultModal">
</div> </div>
<script type="text/javascript" src="js/jquery-2.1.3.min.js"></script> <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="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/metisMenu.min.js"></script>
<script type="text/javascript" src="js/sb-admin-2.js"></script> <script type="text/javascript" src="js/sb-admin-2.js"></script>
<script type="text/javascript" src="js/help.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> <script type="text/javascript" src="js/firefly.js"></script>
@yield('scripts') @yield('scripts')
</body> </body>

View File

@@ -8,8 +8,10 @@
<title>Firefly III</title> <title>Firefly III</title>
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" type="text/css" media="all" /> <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/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" /> <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 --> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
@@ -44,5 +46,9 @@
</div> </div>
<script type="text/javascript" src="js/jquery-2.1.3.min.js"></script> <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="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> </body>
</html> </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> <tr>
<th>&nbsp;</th> <th>&nbsp;</th>
<th>Name</th> <th>Name</th>
@if(isset($what) && $what == 'asset')
<th>Role</th> <th>Role</th>
@endif
<th>Current balance</th> <th>Current balance</th>
<th>Active</th> <th>Active</th>
<th>Last activity</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> </tr>
@foreach($accounts as $account) @foreach($accounts as $account)
<tr> <tr>
@@ -16,7 +22,15 @@
</div> </div>
</td> </td>
<td><a href="{{route('accounts.show',$account->id)}}">{{{$account->name}}}</a></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>{!! Amount::format(Steam::balance($account)) !!}</td>
<td> <td>
@if($account->active) @if($account->active)
@@ -32,7 +46,14 @@
<em>Never</em> <em>Never</em>
@endif @endif
</td> </td>
<td>
{!! Amount::format($account->endBalance - $account->startBalance) !!}
</td>
</tr> </tr>
@endforeach @endforeach
</table> </table>
@if(is_object($accounts) && method_exists($accounts, 'render'))
{!! $accounts->render() !!}
@endif

View File

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

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