mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-11 05:41:24 +00:00
Compare commits
194 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae90815708 | ||
|
|
1c460343b7 | ||
|
|
26079622f9 | ||
|
|
06c6d6096f | ||
|
|
c8183aea51 | ||
|
|
7531134ad2 | ||
|
|
cd0c6439c2 | ||
|
|
c918c93f51 | ||
|
|
97d3bd68ed | ||
|
|
75f1e034ae | ||
|
|
8e72f218f1 | ||
|
|
d643e05c5a | ||
|
|
fea44834d0 | ||
|
|
195a2d7523 | ||
|
|
b2fd346ef8 | ||
|
|
1ff8b62cb7 | ||
|
|
c7ae15a41a | ||
|
|
efe6f59f79 | ||
|
|
8e31d0491d | ||
|
|
73d4a10351 | ||
|
|
81d9d4dbc7 | ||
|
|
184ec13f99 | ||
|
|
dee0422eff | ||
|
|
81a2975f1a | ||
|
|
5cd2ef4a5e | ||
|
|
466c2a68c2 | ||
|
|
0fb9fba531 | ||
|
|
356dd2c6cd | ||
|
|
32c4661233 | ||
|
|
a245b504ec | ||
|
|
a2f5fbdfd3 | ||
|
|
04be26adc5 | ||
|
|
be0adb7cf2 | ||
|
|
84fd92bf5a | ||
|
|
ee4e061739 | ||
|
|
4a2b01cd9a | ||
|
|
efdd6460fb | ||
|
|
803827e05c | ||
|
|
a41d5e9ab3 | ||
|
|
e94333f877 | ||
|
|
6dbb80d687 | ||
|
|
31a1031624 | ||
|
|
f8e9ce0d52 | ||
|
|
11baa968cd | ||
|
|
3e5e5b376f | ||
|
|
bda18f296d | ||
|
|
287d110c84 | ||
|
|
c98275e73a | ||
|
|
aa573cc951 | ||
|
|
883d3d86e3 | ||
|
|
fb047bd5f4 | ||
|
|
66a04d8365 | ||
|
|
a0e501f9fd | ||
|
|
8b40d3346d | ||
|
|
eddf5cd250 | ||
|
|
ee5c534ca3 | ||
|
|
fd4e77ae0f | ||
|
|
b747c50aa3 | ||
|
|
deebdd86a6 | ||
|
|
b2db79cc10 | ||
|
|
bbab370b1e | ||
|
|
db4adf399d | ||
|
|
0683c87e52 | ||
|
|
3f62b647fc | ||
|
|
2562a5b30d | ||
|
|
e232f2e223 | ||
|
|
21644ff4dd | ||
|
|
be96a4fce5 | ||
|
|
a1cabcbed3 | ||
|
|
ce933b1f06 | ||
|
|
51ae130922 | ||
|
|
da1bc18a47 | ||
|
|
e7165a526b | ||
|
|
6081cc399f | ||
|
|
7c5c24e15d | ||
|
|
e3e55b4347 | ||
|
|
40d8e7d1ad | ||
|
|
59e23b89f2 | ||
|
|
cc33af8193 | ||
|
|
0e1e7eb2a9 | ||
|
|
52a28a7758 | ||
|
|
3f752d6832 | ||
|
|
fe714e9989 | ||
|
|
0d3213a379 | ||
|
|
44056629e8 | ||
|
|
54125c05d3 | ||
|
|
7d32e50f25 | ||
|
|
4af9ff49a0 | ||
|
|
23faef845c | ||
|
|
41dad4091a | ||
|
|
daf859b977 | ||
|
|
f47ba6c977 | ||
|
|
4b9b207d92 | ||
|
|
875cbf66af | ||
|
|
412d6d4fd7 | ||
|
|
91c6deeb1f | ||
|
|
6d1978fd9a | ||
|
|
52d23b6ef5 | ||
|
|
0656ccbdd9 | ||
|
|
e774ebd0a3 | ||
|
|
edbda32a84 | ||
|
|
721fa04e3c | ||
|
|
9fd8d8915d | ||
|
|
7a9f5ebdd1 | ||
|
|
a3423f0321 | ||
|
|
c37e9a4467 | ||
|
|
6157d82a0b | ||
|
|
38b27fec92 | ||
|
|
c43439bb68 | ||
|
|
8d9561d7a5 | ||
|
|
2a72cce3b7 | ||
|
|
d3bbb6fb1f | ||
|
|
7b6723e9a2 | ||
|
|
1ee741460d | ||
|
|
967b0b493b | ||
|
|
b53aaf7dde | ||
|
|
714c13bdbf | ||
|
|
651a4fd3cc | ||
|
|
505aee22bb | ||
|
|
ca3d59dc33 | ||
|
|
13890e32a1 | ||
|
|
df8976eabe | ||
|
|
3e01daa172 | ||
|
|
f6999f355b | ||
|
|
5c06b45eb1 | ||
|
|
1802bb967a | ||
|
|
d8d92f147f | ||
|
|
4a95bdd8ba | ||
|
|
db5d94d956 | ||
|
|
06f2e34bb5 | ||
|
|
2ef7a01945 | ||
|
|
d3f642551d | ||
|
|
490997157e | ||
|
|
2432af7883 | ||
|
|
7abeece3f0 | ||
|
|
3851652821 | ||
|
|
1d67d2250a | ||
|
|
37f40d8637 | ||
|
|
0224d1d59b | ||
|
|
587b94153d | ||
|
|
5124ce0302 | ||
|
|
950c4045b0 | ||
|
|
9c8ba66873 | ||
|
|
25d1d1be1b | ||
|
|
339c352505 | ||
|
|
c587081fe4 | ||
|
|
8f9b1b866b | ||
|
|
ff5ecf6182 | ||
|
|
05670cf393 | ||
|
|
f10f5d30bf | ||
|
|
0d336727e8 | ||
|
|
bf354275b3 | ||
|
|
1932bf277a | ||
|
|
192db4bb6e | ||
|
|
701efb943d | ||
|
|
b2674971f1 | ||
|
|
c907cb4cf1 | ||
|
|
bb1462b4d9 | ||
|
|
1035f0e139 | ||
|
|
8475757716 | ||
|
|
20ffd8d61b | ||
|
|
8601428c4c | ||
|
|
59998573ee | ||
|
|
293cd72001 | ||
|
|
22ab9ebb2f | ||
|
|
9136e592d3 | ||
|
|
ed8e392616 | ||
|
|
e57ce6e644 | ||
|
|
8204e46086 | ||
|
|
9e365d9f80 | ||
|
|
6b40a933e9 | ||
|
|
8520a5002f | ||
|
|
b38ed06f6e | ||
|
|
48427b1143 | ||
|
|
5d505f4ed0 | ||
|
|
0c02a08954 | ||
|
|
0221bd0f80 | ||
|
|
28216cbcb5 | ||
|
|
3e08a8cd6b | ||
|
|
67fafdeef7 | ||
|
|
cc82505b66 | ||
|
|
fd5f075f63 | ||
|
|
a115960411 | ||
|
|
e9fa4ca816 | ||
|
|
d5c39d54d8 | ||
|
|
dca395a018 | ||
|
|
fcc22c692a | ||
|
|
26eafb0bd2 | ||
|
|
6dd1b4537a | ||
|
|
2722f0b749 | ||
|
|
ccf0e1875e | ||
|
|
7ed2e03654 | ||
|
|
549e0f3477 | ||
|
|
b243ed93aa |
18
.env.backup
Executable file
18
.env.backup
Executable file
@@ -0,0 +1,18 @@
|
||||
APP_ENV=local
|
||||
APP_DEBUG=true
|
||||
APP_KEY=SomeRandomString
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=localhost
|
||||
DB_DATABASE=homestead
|
||||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
EMAIL_SMTP=
|
||||
EMAIL_DRIVER=smtp
|
||||
EMAIL_USERNAME=
|
||||
EMAIL_PASSWORD=
|
||||
ANALYTICS_ID=
|
||||
@@ -1,5 +1,5 @@
|
||||
APP_ENV=local
|
||||
APP_DEBUG=true
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_KEY=SomeRandomString
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
|
||||
18
.env.local
Executable file
18
.env.local
Executable file
@@ -0,0 +1,18 @@
|
||||
APP_ENV=local
|
||||
APP_DEBUG=true
|
||||
APP_KEY=SomeRandomString
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=localhost
|
||||
DB_DATABASE=homestead
|
||||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
EMAIL_SMTP=
|
||||
EMAIL_DRIVER=smtp
|
||||
EMAIL_USERNAME=
|
||||
EMAIL_PASSWORD=
|
||||
ANALYTICS_ID=
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,3 +28,4 @@ tests/_output/*
|
||||
clover.xml
|
||||
node_modules/
|
||||
addNewLines.php
|
||||
.phpstorm.meta.php
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Firefly III (v3.3.5)
|
||||
Firefly III (v3.4)
|
||||
===========
|
||||
|
||||
[](https://travis-ci.org/JC5/firefly-iii)
|
||||
@@ -22,7 +22,9 @@ laptop and [Firefly II](https://github.com/JC5/Firefly) is live.
|
||||
If you're not sure if this tool is for you, please read the [full description](https://github.com/JC5/firefly-iii/wiki/full-description).
|
||||
|
||||
To install and use Firefly III, please read [the installation guide](https://github.com/JC5/firefly-iii/wiki/Installation),
|
||||
[the upgrade guide](https://github.com/JC5/firefly-iii/wiki/Upgrade-instructions) (if applicable) and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**
|
||||
[the upgrade guide](https://github.com/JC5/firefly-iii/wiki/Upgrade-instructions) (if applicable) and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**.
|
||||
|
||||
If you want to try out Firefly III, you can do so on [this dedicated website](https://geld.nder.be/). This site always runs the latest version of Firefly III. If you want to use it, please read the [privacy considerations](https://github.com/JC5/firefly-iii/wiki/Privacy-on-demo-site) for this demo-site.
|
||||
|
||||
## Current features
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php namespace FireflyIII\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Foundation\Inspiring;
|
||||
|
||||
/**
|
||||
* Class Inspire
|
||||
*
|
||||
* @package FireflyIII\Console\Commands
|
||||
*/
|
||||
class Inspire extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Display an inspiring quote';
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'inspire';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->comment(PHP_EOL . Inspiring::quote() . PHP_EOL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,7 +18,6 @@ class Kernel extends ConsoleKernel
|
||||
*/
|
||||
protected $commands
|
||||
= [
|
||||
'FireflyIII\Console\Commands\Inspire',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -30,8 +29,6 @@ class Kernel extends ConsoleKernel
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
$schedule->command('inspire')
|
||||
->hourly();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,14 +51,7 @@ class ConnectJournalToPiggyBank
|
||||
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);
|
||||
}
|
||||
}
|
||||
$amount = $journal->amount;
|
||||
Log::debug('Amount: ' . $amount);
|
||||
if ($amount == 0) {
|
||||
return;
|
||||
@@ -72,6 +65,22 @@ class ConnectJournalToPiggyBank
|
||||
}
|
||||
|
||||
Log::debug('Found rep! ' . $repetition->id);
|
||||
|
||||
/*
|
||||
* Add amount when
|
||||
*/
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions()->get() as $transaction) {
|
||||
if ($transaction->account_id == $piggyBank->account_id) {
|
||||
if ($transaction->amount < 0) {
|
||||
$amount = $amount * -1;
|
||||
Log::debug('Transaction is away from piggy, so amount becomes ' . $amount);
|
||||
} else {
|
||||
Log::debug('Transaction is to from piggy, so amount stays ' . $amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$repetition->currentamount += $amount;
|
||||
$repetition->save();
|
||||
|
||||
|
||||
@@ -45,17 +45,8 @@ class UpdateJournalConnection
|
||||
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;
|
||||
$amount = $journal->amount;
|
||||
$diff = $amount - $event->amount;// update current repetition
|
||||
|
||||
$repetition->currentamount += $diff;
|
||||
$repetition->save();
|
||||
|
||||
85
app/Helpers/Help/Help.php
Normal file
85
app/Helpers/Help/Help.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Help;
|
||||
|
||||
use Cache;
|
||||
use ErrorException;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use Log;
|
||||
use Route;
|
||||
|
||||
/**
|
||||
* Class Help
|
||||
*
|
||||
* @package FireflyIII\Helpers\Help
|
||||
*/
|
||||
class Help implements HelpInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromCache($key)
|
||||
{
|
||||
return Cache::get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFromGithub($route)
|
||||
{
|
||||
$uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md';
|
||||
$content = [
|
||||
'text' => '<p>There is no help for this route!</p>',
|
||||
'title' => $route,
|
||||
];
|
||||
try {
|
||||
$content['text'] = file_get_contents($uri);
|
||||
} catch (ErrorException $e) {
|
||||
Log::error(trim($e->getMessage()));
|
||||
}
|
||||
if (strlen(trim($content['text'])) == 0) {
|
||||
$content['text'] = '<p>There is no help for this route.</p>';
|
||||
}
|
||||
$converter = new CommonMarkConverter();
|
||||
$content['text'] = $converter->convertToHtml($content['text']);
|
||||
|
||||
return $content;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasRoute($route)
|
||||
{
|
||||
return Route::has($route);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $title
|
||||
* @param array $content
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function putInCache($route, array $content)
|
||||
{
|
||||
Cache::put('help.' . $route . '.text', $content['text'], 10080); // a week.
|
||||
Cache::put('help.' . $route . '.title', $content['title'], 10080);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function inCache($route)
|
||||
{
|
||||
return Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text');
|
||||
}
|
||||
}
|
||||
46
app/Helpers/Help/HelpInterface.php
Normal file
46
app/Helpers/Help/HelpInterface.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Help;
|
||||
|
||||
/**
|
||||
* Interface HelpInterface
|
||||
*
|
||||
* @package FireflyIII\Helpers\Help
|
||||
*/
|
||||
interface HelpInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromCache($key);
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasRoute($route);
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFromGithub($route);
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param array $content
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function putInCache($route, array $content);
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function inCache($route);
|
||||
}
|
||||
@@ -60,23 +60,21 @@ class ReportHelper implements ReportHelperInterface
|
||||
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
|
||||
}
|
||||
)
|
||||
->get(['budgets.*', 'budget_limits.amount as amount']);
|
||||
->get(['budgets.*', 'budget_limits.amount as queryAmount']);
|
||||
|
||||
$budgets = Steam::makeArray($set);
|
||||
$amountSet = $query->journalsByBudget($start, $end, $showSharedReports);
|
||||
$amounts = Steam::makeArray($amountSet);
|
||||
$budgets = Steam::mergeArrays($budgets, $amounts);
|
||||
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
|
||||
$budgets[0]['amount'] = isset($budgets[0]['amount']) ? $budgets[0]['amount'] : 0.0;
|
||||
$budgets[0]['name'] = 'No budget';
|
||||
$budgets = Steam::makeArray($set);
|
||||
$amountSet = $query->journalsByBudget($start, $end, $showSharedReports);
|
||||
$amounts = Steam::makeArray($amountSet);
|
||||
$budgets = Steam::mergeArrays($budgets, $amounts);
|
||||
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
|
||||
$budgets[0]['queryAmount'] = isset($budgets[0]['queryAmount']) ? $budgets[0]['queryAmount'] : 0.0;
|
||||
$budgets[0]['name'] = 'No budget';
|
||||
|
||||
// find transactions to shared asset accounts, which are without a budget by default:
|
||||
// which is only relevant when shared asset accounts are hidden.
|
||||
if ($showSharedReports === false) {
|
||||
$transfers = $query->sharedExpenses($start, $end);
|
||||
foreach ($transfers as $transfer) {
|
||||
$budgets[0]['spent'] += floatval($transfer->amount) * -1;
|
||||
}
|
||||
$transfers = $query->sharedExpenses($start, $end)->sum('queryAmount');
|
||||
$budgets[0]['spent'] += floatval($transfers) * -1;
|
||||
}
|
||||
|
||||
return $budgets;
|
||||
|
||||
@@ -96,7 +96,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
->get(
|
||||
[
|
||||
'transaction_journals.*',
|
||||
'transactions.amount'
|
||||
'transactions.amount as queryAmount'
|
||||
]
|
||||
);
|
||||
|
||||
@@ -111,17 +111,11 @@ class ReportQuery implements ReportQueryInterface
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
* @return float
|
||||
*/
|
||||
public function balancedTransactionsSum(Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
$set = $this->balancedTransactionsList($account, $start, $end);
|
||||
$sum = 0;
|
||||
foreach ($set as $entry) {
|
||||
$sum += floatval($entry->amount);
|
||||
}
|
||||
|
||||
return $sum;
|
||||
return floatval($this->balancedTransactionsList($account, $start, $end)->sum('queryAmount'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +172,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
{
|
||||
$query = $this->queryJournalsNoBudget($account, $start, $end);
|
||||
|
||||
return $query->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) as `amount`')]);
|
||||
return $query->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) as `queryAmount`')]);
|
||||
|
||||
}
|
||||
|
||||
@@ -196,7 +190,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
{
|
||||
$query = $this->queryJournalsNoBudget($account, $start, $end);
|
||||
|
||||
return $query->get(['budgets.name', 'transactions.amount', 'transaction_journals.*']);
|
||||
return $query->get(['budgets.name', 'transactions.amount as queryAmount', 'transaction_journals.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,7 +230,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
// any deposit is fine.
|
||||
$query->where('transaction_types.type', 'Deposit');
|
||||
}
|
||||
$query->groupBy('t_from.account_id')->orderBy('transaction_journals.date');
|
||||
$query->groupBy('transaction_journals.id')->orderBy('transaction_journals.date');
|
||||
|
||||
// get everything, decrypt and return
|
||||
$data = $query->get(
|
||||
@@ -244,7 +238,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
'transaction_journals.description',
|
||||
'transaction_journals.encrypted',
|
||||
'transaction_types.type',
|
||||
DB::Raw('SUM(`t_to`.`amount`) as `amount`'),
|
||||
DB::Raw('SUM(`t_to`.`amount`) as `queryAmount`'),
|
||||
'transaction_journals.date',
|
||||
't_from.account_id as account_id',
|
||||
'ac_from.name as name',
|
||||
@@ -254,7 +248,6 @@ class ReportQuery implements ReportQueryInterface
|
||||
|
||||
$data->each(
|
||||
function (Model $object) {
|
||||
// $object->description = intval($object->encrypted);
|
||||
$object->name = intval($object->account_encrypted) == 1 ? Crypt::decrypt($object->name) : $object->name;
|
||||
}
|
||||
);
|
||||
@@ -335,9 +328,9 @@ class ReportQuery implements ReportQueryInterface
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->groupBy('categories.id')
|
||||
->orderBy('amount');
|
||||
->orderBy('queryAmount');
|
||||
|
||||
$data = $query->get(['categories.id', 'categories.encrypted', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `amount`')]);
|
||||
$data = $query->get(['categories.id', 'categories.encrypted', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `queryAmount`')]);
|
||||
// decrypt data:
|
||||
$data->each(
|
||||
function (Model $object) {
|
||||
@@ -390,9 +383,9 @@ class ReportQuery implements ReportQueryInterface
|
||||
$query->before($end)->after($start)
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->groupBy('t_to.account_id')
|
||||
->orderBy('amount', 'DESC');
|
||||
->orderBy('queryAmount', 'DESC');
|
||||
|
||||
$data = $query->get(['t_to.account_id as id', 'ac_to.name as name', 'ac_to.encrypted', DB::Raw('SUM(t_to.amount) as `amount`')]);
|
||||
$data = $query->get(['t_to.account_id as id', 'ac_to.name as name', 'ac_to.encrypted', DB::Raw('SUM(t_to.amount) as `queryAmount`')]);
|
||||
|
||||
// decrypt
|
||||
$data->each(
|
||||
@@ -441,10 +434,10 @@ class ReportQuery implements ReportQueryInterface
|
||||
$query->where('transaction_types.type', 'Deposit');
|
||||
}
|
||||
|
||||
$query->groupBy('t_from.account_id')->orderBy('amount');
|
||||
$query->groupBy('t_from.account_id')->orderBy('queryAmount');
|
||||
|
||||
$data = $query->get(
|
||||
['t_from.account_id as account_id', 'ac_from.name as name', 'ac_from.encrypted as encrypted', DB::Raw('SUM(t_from.amount) as `amount`')]
|
||||
['t_from.account_id as account_id', 'ac_from.name as name', 'ac_from.encrypted as encrypted', DB::Raw('SUM(t_from.amount) as `queryAmount`')]
|
||||
);
|
||||
// decrypt
|
||||
$data->each(
|
||||
@@ -489,7 +482,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->get(
|
||||
['transaction_journals.id', 'transaction_journals.description', 'transactions.account_id', 'accounts.name',
|
||||
'transactions.amount']
|
||||
'transactions.amount as queryAmount']
|
||||
);
|
||||
|
||||
}
|
||||
@@ -534,7 +527,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
[
|
||||
'categories.id',
|
||||
'categories.name as name',
|
||||
DB::Raw('SUM(`transactions`.`amount`) * -1 AS `amount`')
|
||||
DB::Raw('SUM(`transactions`.`amount`) * -1 AS `queryAmount`')
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ interface ReportQueryInterface
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
* @return float
|
||||
*/
|
||||
public function balancedTransactionsSum(Account $account, Carbon $start, Carbon $end);
|
||||
|
||||
|
||||
@@ -7,12 +7,11 @@ use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\AccountFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Input;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use Steam;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
@@ -27,6 +26,7 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('mainTitleIcon', 'fa-credit-card');
|
||||
View::share('title', 'Accounts');
|
||||
}
|
||||
@@ -41,6 +41,12 @@ class AccountController extends Controller
|
||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||
$subTitle = 'Create a new ' . e($what) . ' account';
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('accounts.create.fromStore') !== true) {
|
||||
Session::put('accounts.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('accounts.create.fromStore');
|
||||
|
||||
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
|
||||
|
||||
}
|
||||
@@ -54,6 +60,9 @@ class AccountController extends Controller
|
||||
{
|
||||
$subTitle = 'Delete ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
|
||||
|
||||
// put previous url in session
|
||||
Session::put('accounts.delete.url', URL::previous());
|
||||
|
||||
return view('accounts.delete', compact('account', 'subTitle'));
|
||||
}
|
||||
|
||||
@@ -73,7 +82,7 @@ class AccountController extends Controller
|
||||
|
||||
Session::flash('success', 'The ' . e($typeName) . ' account "' . e($name) . '" was deleted.');
|
||||
|
||||
return Redirect::route('accounts.index', $typeName);
|
||||
return Redirect::to(Session::get('accounts.delete.url'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +99,12 @@ class AccountController extends Controller
|
||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||
$openingBalance = $repository->openingBalanceTransaction($account);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('accounts.edit.fromUpdate') !== true) {
|
||||
Session::put('accounts.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('accounts.edit.fromUpdate');
|
||||
|
||||
// pre fill some useful values.
|
||||
|
||||
// the opening balance is tricky:
|
||||
@@ -114,50 +129,31 @@ class AccountController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $what
|
||||
* @param $what
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function index($what = 'default')
|
||||
public function index($what, AccountRepositoryInterface $repository)
|
||||
{
|
||||
$subTitle = Config::get('firefly.subTitlesByIdentifier.' . $what);
|
||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||
$types = Config::get('firefly.accountTypesByIdentifier.' . $what);
|
||||
$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 (HasMany $query) {
|
||||
$query->where('name', 'accountRole');
|
||||
}]
|
||||
)->accountTypeIn($types)->take($size)->offset($offset)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
|
||||
$total = Auth::user()->accounts()->accountTypeIn($types)->count();
|
||||
|
||||
$accounts = $repository->getAccounts($types);
|
||||
// last activity:
|
||||
/**
|
||||
* HERE WE ARE
|
||||
*/
|
||||
$start = clone Session::get('start', Carbon::now()->startOfMonth());
|
||||
$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, clone Session::get('end'));
|
||||
$accounts->each(
|
||||
function (Account $account) use ($start, $repository) {
|
||||
$account->lastActivityDate = $repository->getLastActivity($account);
|
||||
$account->startBalance = Steam::balance($account, $start);
|
||||
$account->endBalance = Steam::balance($account, clone Session::get('end', Carbon::now()->endOfMonth()));
|
||||
}
|
||||
);
|
||||
|
||||
$accounts = new LengthAwarePaginator($set, $total, $size, $page);
|
||||
$accounts->setPath(route('accounts.index', $what));
|
||||
|
||||
|
||||
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
|
||||
}
|
||||
|
||||
@@ -176,6 +172,7 @@ class AccountController extends Controller
|
||||
$subTitle = 'Details for ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
|
||||
$journals->setPath('accounts/show/' . $account->id);
|
||||
|
||||
|
||||
return view('accounts.show', compact('account', 'what', 'subTitleIcon', 'journals', 'subTitle'));
|
||||
}
|
||||
|
||||
@@ -204,10 +201,15 @@ class AccountController extends Controller
|
||||
Session::flash('success', 'New account "' . $account->name . '" stored!');
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
return Redirect::route('accounts.create', $request->input('what'))->withInput();
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('accounts.create.fromStore', true);
|
||||
|
||||
return Redirect::route('accounts.create')->withInput();
|
||||
}
|
||||
|
||||
return Redirect::route('accounts.index', $request->input('what'));
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('accounts.create.url'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -220,7 +222,7 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function update(Account $account, AccountFormRequest $request, AccountRepositoryInterface $repository)
|
||||
{
|
||||
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
|
||||
$accountData = [
|
||||
'name' => $request->input('name'),
|
||||
'active' => $request->input('active'),
|
||||
@@ -239,10 +241,14 @@ class AccountController extends Controller
|
||||
Session::flash('success', 'Account "' . $account->name . '" updated.');
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
return Redirect::route('accounts.edit', $account->id);
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('accounts.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('accounts.edit', $account->id)->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
return Redirect::route('accounts.index', $what);
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('accounts.edit.url'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Mail\Message;
|
||||
use Mail;
|
||||
use Session;
|
||||
use Twig;
|
||||
|
||||
/**
|
||||
* Class AuthController
|
||||
@@ -47,6 +48,16 @@ class AuthController extends Controller
|
||||
$this->middleware('guest', ['except' => 'getLogout']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application login form.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function getLogin()
|
||||
{
|
||||
return Twig::render('auth.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a registration request for the application.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Config;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\BillFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
@@ -8,6 +8,7 @@ use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use Input;
|
||||
use Redirect;
|
||||
@@ -28,6 +29,7 @@ class BillController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Bills');
|
||||
View::share('mainTitleIcon', 'fa-calendar-o');
|
||||
}
|
||||
@@ -37,15 +39,14 @@ class BillController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function add(Bill $bill)
|
||||
public function add(Bill $bill, AccountRepositoryInterface $repository)
|
||||
{
|
||||
$matches = explode(',', $bill->match);
|
||||
$description = [];
|
||||
$expense = null;
|
||||
|
||||
// get users expense accounts:
|
||||
$type = AccountType::where('type', 'Expense account')->first();
|
||||
$accounts = Auth::user()->accounts()->where('account_type_id', $type->id)->get();
|
||||
$accounts = $repository->getAccounts(Config::get('firefly.accountTypesByIdentifier.expense'));
|
||||
|
||||
foreach ($matches as $match) {
|
||||
$match = strtolower($match);
|
||||
@@ -81,7 +82,13 @@ class BillController extends Controller
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$periods = \Config::get('firefly.periods_to_text');
|
||||
$periods = Config::get('firefly.periods_to_text');
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('bills.create.fromStore') !== true) {
|
||||
Session::put('bills.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('bills.create.fromStore');
|
||||
|
||||
return view('bills.create')->with('periods', $periods)->with('subTitle', 'Create new');
|
||||
}
|
||||
@@ -93,6 +100,9 @@ class BillController extends Controller
|
||||
*/
|
||||
public function delete(Bill $bill)
|
||||
{
|
||||
// put previous url in session
|
||||
Session::put('bills.delete.url', URL::previous());
|
||||
|
||||
return view('bills.delete')->with('bill', $bill)->with('subTitle', 'Delete "' . e($bill->name) . '"');
|
||||
}
|
||||
|
||||
@@ -101,12 +111,13 @@ class BillController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Bill $bill)
|
||||
public function destroy(Bill $bill, BillRepositoryInterface $repository)
|
||||
{
|
||||
$bill->delete();
|
||||
$repository->destroy($bill);
|
||||
|
||||
Session::flash('success', 'The bill was deleted.');
|
||||
|
||||
return Redirect::route('bills.index');
|
||||
return Redirect::to(Session::get('bills.delete.url'));
|
||||
|
||||
}
|
||||
|
||||
@@ -117,7 +128,13 @@ class BillController extends Controller
|
||||
*/
|
||||
public function edit(Bill $bill)
|
||||
{
|
||||
$periods = \Config::get('firefly.periods_to_text');
|
||||
$periods = Config::get('firefly.periods_to_text');
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('bills.edit.fromUpdate') !== true) {
|
||||
Session::put('bills.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('bills.edit.fromUpdate');
|
||||
|
||||
return view('bills.edit')->with('periods', $periods)->with('bill', $bill)->with('subTitle', 'Edit "' . e($bill->name) . '"');
|
||||
}
|
||||
@@ -129,15 +146,11 @@ class BillController extends Controller
|
||||
*/
|
||||
public function index(BillRepositoryInterface $repository)
|
||||
{
|
||||
$bills = Auth::user()->bills()->orderBy('name', 'ASC')->get();
|
||||
$bills = $repository->getBills();
|
||||
$bills->each(
|
||||
function (Bill $bill) use ($repository) {
|
||||
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
|
||||
$last = $bill->transactionjournals()->orderBy('date', 'DESC')->first();
|
||||
$bill->lastFoundMatch = null;
|
||||
if ($last) {
|
||||
$bill->lastFoundMatch = $last->date;
|
||||
}
|
||||
$bill->lastFoundMatch = $repository->lastFoundMatch($bill);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -154,25 +167,15 @@ class BillController extends Controller
|
||||
if (intval($bill->active) == 0) {
|
||||
Session::flash('warning', 'Inactive bills cannot be scanned.');
|
||||
|
||||
return Redirect::intended('/');
|
||||
return Redirect::to(URL::previous());
|
||||
}
|
||||
|
||||
$set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)->get(
|
||||
['transaction_journal_id']
|
||||
);
|
||||
$ids = [];
|
||||
$journals = $repository->getPossiblyRelatedJournals($bill);
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$repository->scan($bill, $journal);
|
||||
}
|
||||
|
||||
/** @var Transaction $entry */
|
||||
foreach ($set as $entry) {
|
||||
$ids[] = intval($entry->transaction_journal_id);
|
||||
}
|
||||
if (count($ids) > 0) {
|
||||
$journals = Auth::user()->transactionjournals()->whereIn('id', $ids)->get();
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$repository->scan($bill, $journal);
|
||||
}
|
||||
}
|
||||
|
||||
Session::flash('success', 'Rescanned everything.');
|
||||
|
||||
@@ -186,15 +189,10 @@ class BillController extends Controller
|
||||
*/
|
||||
public function show(Bill $bill, BillRepositoryInterface $repository)
|
||||
{
|
||||
$journals = $bill->transactionjournals()->withRelevantData()
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->get();
|
||||
$journals = $repository->getJournals($bill);
|
||||
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
|
||||
$hideBill = true;
|
||||
|
||||
|
||||
return view('bills.show', compact('journals', 'hideBill', 'bill'))->with('subTitle', e($bill->name));
|
||||
}
|
||||
|
||||
@@ -208,10 +206,14 @@ class BillController extends Controller
|
||||
Session::flash('success', 'Bill "' . e($bill->name) . '" stored.');
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('bills.create.fromStore', true);
|
||||
|
||||
return Redirect::route('bills.create')->withInput();
|
||||
}
|
||||
|
||||
return Redirect::route('bills.index');
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('bills.create.url'));
|
||||
|
||||
}
|
||||
|
||||
@@ -225,13 +227,17 @@ class BillController extends Controller
|
||||
$billData = $request->getBillData();
|
||||
$bill = $repository->update($bill, $billData);
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
return Redirect::route('bills.edit', $bill->id);
|
||||
}
|
||||
|
||||
Session::flash('success', 'Bill "' . e($bill->name) . '" updated.');
|
||||
|
||||
return Redirect::route('bills.index');
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('bills.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('bills.edit', $bill->id)->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('bills.edit.url'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,9 @@ use Preferences;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use Session;
|
||||
use View;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class BudgetController
|
||||
*
|
||||
@@ -28,8 +29,10 @@ class BudgetController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Budgets');
|
||||
View::share('mainTitleIcon', 'fa-tasks');
|
||||
View::share('hideBudgets', true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,7 +91,6 @@ class BudgetController extends Controller
|
||||
$repository->destroy($budget);
|
||||
|
||||
|
||||
|
||||
Session::flash('success', 'The budget "' . e($name) . '" was deleted.');
|
||||
|
||||
return Redirect::to(Session::get('budgets.delete.url'));
|
||||
@@ -118,8 +120,8 @@ class BudgetController extends Controller
|
||||
*/
|
||||
public function index(BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$budgets = Auth::user()->budgets()->where('active', 1)->get();
|
||||
$inactive = Auth::user()->budgets()->where('active', 0)->get();
|
||||
$budgets = $repository->getActiveBudgets();
|
||||
$inactive = $repository->getInactiveBudgets();
|
||||
|
||||
/**
|
||||
* Do some cleanup:
|
||||
@@ -127,19 +129,18 @@ class BudgetController extends Controller
|
||||
$repository->cleanupBudgets();
|
||||
|
||||
|
||||
|
||||
// loop the budgets:
|
||||
$budgets->each(
|
||||
function (Budget $budget) use ($repository) {
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$budget->spent = $repository->spentInMonth($budget, $date);
|
||||
$budget->currentRep = $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']);
|
||||
$budget->currentRep = $repository->getCurrentRepetition($budget, $date);
|
||||
}
|
||||
);
|
||||
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
|
||||
$dateAsString = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
|
||||
$spent = $budgets->sum('spent');
|
||||
$amount = Preferences::get('budgetIncomeTotal' . $date, 1000)->data;
|
||||
$amount = Preferences::get('budgetIncomeTotal' . $dateAsString, 1000)->data;
|
||||
$overspent = $spent > $amount;
|
||||
$spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100);
|
||||
$budgetMax = Preferences::get('budgetMaximum', 1000);
|
||||
@@ -151,21 +152,12 @@ class BudgetController extends Controller
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function noBudget()
|
||||
public function noBudget(BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$start = \Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = \Session::get('end', Carbon::now()->startOfMonth());
|
||||
$list = Auth::user()
|
||||
->transactionjournals()
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->whereNull('budget_transaction_journal.id')
|
||||
->before($end)
|
||||
->after($start)
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->get(['transaction_journals.*']);
|
||||
$subTitle = 'Transactions without a budget in ' . $start->format('F Y');
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->startOfMonth());
|
||||
$list = $repository->getWithoutBudget($start, $end);
|
||||
$subTitle = 'Transactions without a budget between ' . $start->format('jS F Y') . ' and ' . $end->format('jS F Y');
|
||||
|
||||
return view('budgets.noBudget', compact('list', 'subTitle'));
|
||||
}
|
||||
@@ -182,6 +174,27 @@ class BudgetController extends Controller
|
||||
return Redirect::route('budgets.index');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param LimitRepetition $repetition
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(Budget $budget, LimitRepetition $repetition = null, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
if (!is_null($repetition->id) && $repetition->budgetLimit->budget->id != $budget->id) {
|
||||
return view('error')->with('message', 'Invalid selection.');
|
||||
}
|
||||
|
||||
$journals = $repository->getJournals($budget, $repetition);
|
||||
$limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $repository->getBudgetLimits($budget);
|
||||
$subTitle = !is_null($repetition->id) ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name);
|
||||
$journals->setPath('/budgets/show/' . $budget->id);
|
||||
|
||||
return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetFormRequest $request
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
@@ -201,6 +214,7 @@ class BudgetController extends Controller
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('budgets.create.fromStore', true);
|
||||
|
||||
return Redirect::route('budgets.create')->withInput();
|
||||
}
|
||||
|
||||
@@ -209,27 +223,6 @@ class BudgetController extends Controller
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param LimitRepetition $repetition
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(Budget $budget, LimitRepetition $repetition = null, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
if (!is_null($repetition->id) && $repetition->budgetLimit->budget->id != $budget->id) {
|
||||
return view('error')->with('message', 'Invalid selection.');
|
||||
}
|
||||
|
||||
$hideBudget = true; // used in transaction list.
|
||||
$journals = $repository->getJournals($budget, $repetition);
|
||||
$limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $budget->budgetLimits()->orderBy('startdate', 'DESC')->get();
|
||||
$subTitle = !is_null($repetition->id) ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name);
|
||||
|
||||
return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle', 'hideBudget'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param BudgetFormRequest $request
|
||||
@@ -251,6 +244,7 @@ class BudgetController extends Controller
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('budgets.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('budgets.edit', $budget->id)->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Input;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use View;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class CategoryController
|
||||
@@ -26,6 +26,7 @@ class CategoryController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Categories');
|
||||
View::share('mainTitleIcon', 'fa-bar-chart');
|
||||
}
|
||||
@@ -51,7 +52,7 @@ class CategoryController extends Controller
|
||||
*/
|
||||
public function delete(Category $category)
|
||||
{
|
||||
$subTitle = 'Delete category' . e($category->name) . '"';
|
||||
$subTitle = 'Delete category "' . e($category->name) . '"';
|
||||
|
||||
// put previous url in session
|
||||
Session::put('categories.delete.url', URL::previous());
|
||||
@@ -96,21 +97,15 @@ class CategoryController extends Controller
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*
|
||||
*/
|
||||
public function index()
|
||||
public function index(CategoryRepositoryInterface $repository)
|
||||
{
|
||||
$categories = Auth::user()->categories()->orderBy('name', 'ASC')->get();
|
||||
$categories = $repository->getCategories();
|
||||
|
||||
$categories->each(
|
||||
function (Category $category) {
|
||||
$latest = $category->transactionjournals()
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->first();
|
||||
if ($latest) {
|
||||
$category->lastActivity = $latest->date;
|
||||
}
|
||||
function (Category $category) use ($repository) {
|
||||
$category->lastActivity = $repository->getLatestActivity($category);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -120,21 +115,11 @@ class CategoryController extends Controller
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function noCategory()
|
||||
public function noCategory(CategoryRepositoryInterface $repository)
|
||||
{
|
||||
$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', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->get(['transaction_journals.*']);
|
||||
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->startOfMonth());
|
||||
$list = $repository->getWithoutCategory($start, $end);
|
||||
$subTitle = 'Transactions without a category between ' . $start->format('jS F Y') . ' and ' . $end->format('jS F Y');
|
||||
|
||||
return view('categories.noCategory', compact('list', 'subTitle'));
|
||||
@@ -149,17 +134,10 @@ class CategoryController extends Controller
|
||||
{
|
||||
$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('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->get(
|
||||
['transaction_journals.*']
|
||||
);
|
||||
$count = $category->transactionJournals()->count();
|
||||
|
||||
$journals = new LengthAwarePaginator($set, $count, 50, $page);
|
||||
$set = $repository->getJournals($category, $page);
|
||||
$count = $repository->countJournals($category);
|
||||
$journals = new LengthAwarePaginator($set, $count, 50, $page);
|
||||
$journals->setPath('categories/show/' . $category->id);
|
||||
|
||||
return view('categories.show', compact('category', 'journals', 'hideCategory'));
|
||||
}
|
||||
@@ -182,12 +160,11 @@ class CategoryController extends Controller
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
Session::put('categories.create.fromStore', true);
|
||||
|
||||
return Redirect::route('categories.create')->withInput();
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('categories.create.url'));
|
||||
|
||||
return Redirect::route('categories.index');
|
||||
}
|
||||
|
||||
|
||||
@@ -210,6 +187,7 @@ class CategoryController extends Controller
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
Session::put('categories.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('categories.edit', $category->id);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use Illuminate\Foundation\Bus\DispatchesCommands;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class Controller
|
||||
@@ -14,4 +15,14 @@ abstract class Controller extends BaseController
|
||||
|
||||
use DispatchesCommands, ValidatesRequests;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
View::share('hideBudgets', false);
|
||||
View::share('hideCategories', false);
|
||||
View::share('hideBills', false);
|
||||
View::share('hideTags', false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\CurrencyFormRequest;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use View;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class CurrencyController
|
||||
@@ -26,7 +27,7 @@ class CurrencyController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
parent::__construct();
|
||||
View::share('title', 'Currencies');
|
||||
View::share('mainTitleIcon', 'fa-usd');
|
||||
}
|
||||
@@ -56,9 +57,7 @@ class CurrencyController extends Controller
|
||||
public function defaultCurrency(TransactionCurrency $currency)
|
||||
{
|
||||
|
||||
$currencyPreference = Preferences::get('currencyPreference', 'EUR');
|
||||
$currencyPreference->data = $currency->code;
|
||||
$currencyPreference->save();
|
||||
Preferences::set('currencyPreference', $currency->code);
|
||||
|
||||
Session::flash('success', $currency->name . ' is now the default currency.');
|
||||
Cache::forget('FFCURRENCYSYMBOL');
|
||||
@@ -73,17 +72,18 @@ class CurrencyController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
||||
*/
|
||||
public function delete(TransactionCurrency $currency)
|
||||
public function delete(TransactionCurrency $currency, CurrencyRepositoryInterface $repository)
|
||||
{
|
||||
if ($currency->transactionJournals()->count() > 0) {
|
||||
Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.');
|
||||
|
||||
// put previous url in session
|
||||
Session::put('currency.delete.url', URL::previous());
|
||||
if ($repository->countJournals($currency) > 0) {
|
||||
Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.');
|
||||
|
||||
return Redirect::route('currency.index');
|
||||
}
|
||||
|
||||
// put previous url in session
|
||||
Session::put('currency.delete.url', URL::previous());
|
||||
|
||||
|
||||
return view('currency.delete', compact('currency'));
|
||||
}
|
||||
@@ -93,10 +93,10 @@ class CurrencyController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(TransactionCurrency $currency)
|
||||
public function destroy(TransactionCurrency $currency, CurrencyRepositoryInterface $repository)
|
||||
{
|
||||
if ($currency->transactionJournals()->count() > 0) {
|
||||
Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.');
|
||||
if ($repository->countJournals($currency) > 0) {
|
||||
Session::flash('error', 'Cannot destroy ' . e($currency->name) . ' because there are still transactions attached to it.');
|
||||
|
||||
return Redirect::route('currency.index');
|
||||
}
|
||||
@@ -132,12 +132,10 @@ class CurrencyController extends Controller
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
public function index(CurrencyRepositoryInterface $repository)
|
||||
{
|
||||
$currencies = TransactionCurrency::get();
|
||||
$currencyPreference = Preferences::get('currencyPreference', 'EUR');
|
||||
$defaultCurrency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||
|
||||
$currencies = $repository->get();
|
||||
$defaultCurrency = $repository->getCurrencyByPreference(Preferences::get('currencyPreference', 'EUR'));
|
||||
|
||||
return view('currency.index', compact('currencies', 'defaultCurrency'));
|
||||
}
|
||||
@@ -147,28 +145,22 @@ class CurrencyController extends Controller
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(CurrencyFormRequest $request)
|
||||
public function store(CurrencyFormRequest $request, CurrencyRepositoryInterface $repository)
|
||||
{
|
||||
$data = $request->getCurrencyData();
|
||||
$currency = $repository->store($data);
|
||||
|
||||
|
||||
// no repository, because the currency controller is relatively simple.
|
||||
$currency = TransactionCurrency::create(
|
||||
[
|
||||
'name' => $request->get('name'),
|
||||
'code' => $request->get('code'),
|
||||
'symbol' => $request->get('symbol'),
|
||||
]
|
||||
);
|
||||
|
||||
Session::flash('success', 'Currency "' . $currency->name . '" created');
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
Session::put('currency.create.fromStore', true);
|
||||
|
||||
return Redirect::route('currency.create')->withInput();
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('categories.create.url'));
|
||||
return Redirect::to(Session::get('currency.create.url'));
|
||||
|
||||
|
||||
}
|
||||
@@ -178,19 +170,17 @@ class CurrencyController extends Controller
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(TransactionCurrency $currency, CurrencyFormRequest $request)
|
||||
public function update(TransactionCurrency $currency, CurrencyFormRequest $request, CurrencyRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$currency->code = $request->get('code');
|
||||
$currency->symbol = $request->get('symbol');
|
||||
$currency->name = $request->get('name');
|
||||
$currency->save();
|
||||
$data = $request->getCurrencyData();
|
||||
$currency = $repository->update($currency, $data);
|
||||
|
||||
Session::flash('success', 'Currency "' . e($currency->name) . '" updated.');
|
||||
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
Session::put('currency.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('currency.edit', $currency->id);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Amount;
|
||||
use App;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Crypt;
|
||||
use DB;
|
||||
use Exception;
|
||||
use FireflyIII\Helpers\Report\ReportQueryInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
@@ -17,11 +12,12 @@ use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use Grumpydictator\Gchart\GChart;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
@@ -72,19 +68,15 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function allAccountsBalanceChart(GChart $chart)
|
||||
public function allAccountsBalanceChart(GChart $chart, AccountRepositoryInterface $repository)
|
||||
{
|
||||
$chart->addColumn('Day of the month', 'date');
|
||||
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$accounts = $repository->getFrontpageAccounts($frontPage);
|
||||
|
||||
if ($frontPage->data == []) {
|
||||
$accounts = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']);
|
||||
} else {
|
||||
$accounts = Auth::user()->accounts()->whereIn('id', $frontPage->data)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
|
||||
}
|
||||
$index = 1;
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
@@ -118,22 +110,16 @@ class GoogleChartController extends Controller
|
||||
*/
|
||||
public function allBudgetsAndSpending($year, GChart $chart, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
try {
|
||||
new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid year.');
|
||||
}
|
||||
$budgets = Auth::user()->budgets()->get();
|
||||
$budgets->sortBy('name');
|
||||
$budgets = $repository->getBudgets();
|
||||
$chart->addColumn('Month', 'date');
|
||||
foreach ($budgets as $budget) {
|
||||
$chart->addColumn($budget->name, 'number');
|
||||
}
|
||||
|
||||
$start = Carbon::createFromDate(intval($year), 1, 1);
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
|
||||
|
||||
while ($start <= $end) {
|
||||
$row = [clone $start];
|
||||
foreach ($budgets as $budget) {
|
||||
@@ -144,7 +130,6 @@ class GoogleChartController extends Controller
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
@@ -156,73 +141,45 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function allBudgetsHomeChart(GChart $chart)
|
||||
public function allBudgetsHomeChart(GChart $chart, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$chart->addColumn('Budget', 'string');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
$chart->addColumn('Left', 'number');
|
||||
//$chart->addColumn('Spent', 'number');
|
||||
|
||||
$budgets = Auth::user()->budgets()->orderBy('name', 'DESC')->get();
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$budgets = $repository->getBudgets();
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$allEntries = new Collection;
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
|
||||
/** @var Collection $repetitions */
|
||||
$repetitions = LimitRepetition::
|
||||
leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00'))
|
||||
->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.budget_id', $budget->id)
|
||||
->get(['limit_repetitions.*']);
|
||||
|
||||
// no results? search entire range for expenses and list those.
|
||||
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
|
||||
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 {
|
||||
// add with foreach:
|
||||
/** @var LimitRepetition $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
|
||||
$expenses
|
||||
=
|
||||
floatval($budget->transactionjournals()->before($repetition->enddate)->after($repetition->startdate)->lessThan(0)->sum('amount')) * -1;
|
||||
if ($expenses > 0) {
|
||||
$chart->addRow($budget->name . ' (' . $repetition->startdate->format('j M Y') . ')', floatval($repetition->amount), $expenses);
|
||||
}
|
||||
}
|
||||
$expenses = $repository->sumBudgetExpensesInPeriod($budget, $start, $end);
|
||||
$allEntries->push([$budget->name, 0, $expenses]);
|
||||
continue;
|
||||
}
|
||||
/** @var LimitRepetition $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
$expenses = $repository->sumBudgetExpensesInPeriod($budget, $repetition->startdate, $repetition->enddate);
|
||||
$allEntries->push([$budget->name . ' (' . $repetition->startdate->format('j M Y') . ')', floatval($repetition->amount), $expenses]);
|
||||
}
|
||||
}
|
||||
|
||||
$noBudgetExpenses = $repository->getWithoutBudgetSum($start, $end);
|
||||
$allEntries->push(['(no budget)', 0, $noBudgetExpenses]);
|
||||
|
||||
foreach ($allEntries as $entry) {
|
||||
if ($entry[2] > 0) {
|
||||
$left = $entry[1] - $entry[2];
|
||||
$chart->addRow($entry[0], $left);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
$noBudgetSet = Auth::user()
|
||||
->transactionjournals()
|
||||
->whereNotIn(
|
||||
'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) {
|
||||
$query
|
||||
->select('transaction_journals.id')
|
||||
->from('transaction_journals')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'))
|
||||
->whereNotNull('budget_transaction_journal.budget_id');
|
||||
}
|
||||
)
|
||||
->before($end)
|
||||
->after($start)
|
||||
->lessThan(0)
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->get();
|
||||
$sum = $noBudgetSet->sum('amount') * -1;
|
||||
$chart->addRow('No budget', 0, $sum);
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,34 +187,14 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function allCategoriesHomeChart(GChart $chart)
|
||||
public function allCategoriesHomeChart(GChart $chart, CategoryRepositoryInterface $repository)
|
||||
{
|
||||
$chart->addColumn('Category', 'string');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
// query!
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$set = TransactionJournal::
|
||||
where('transaction_journals.user_id', Auth::user()->id)
|
||||
->leftJoin(
|
||||
'transactions',
|
||||
function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
|
||||
)
|
||||
->leftJoin('categories', 'categories.id', '=', 'category_transaction_journal.category_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->before($end)
|
||||
->where('categories.user_id', Auth::user()->id)
|
||||
->after($start)
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->groupBy('categories.id')
|
||||
->orderBy('sum', 'DESC')
|
||||
->get(['categories.id', 'categories.encrypted', 'categories.name', \DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
|
||||
$set = $repository->getCategoriesAndExpenses($start, $end);
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$isEncrypted = intval($entry->encrypted) == 1 ? true : false;
|
||||
@@ -273,11 +210,12 @@ class GoogleChartController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param Bill $bill
|
||||
* @param GChart $chart
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function billOverview(Bill $bill, GChart $chart)
|
||||
public function billOverview(Bill $bill, GChart $chart, BillRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$chart->addColumn('Date', 'date');
|
||||
@@ -286,24 +224,10 @@ class GoogleChartController extends Controller
|
||||
$chart->addColumn('Recorded bill entry', 'number');
|
||||
|
||||
// get first transaction or today for start:
|
||||
$first = $bill->transactionjournals()->orderBy('date', 'ASC')->first();
|
||||
if ($first) {
|
||||
$start = $first->date;
|
||||
} else {
|
||||
$start = new Carbon;
|
||||
}
|
||||
|
||||
$results = $bill->transactionjournals()->after($start)->get();
|
||||
$results = $repository->getJournals($bill);
|
||||
/** @var TransactionJournal $result */
|
||||
foreach ($results as $result) {
|
||||
$amount = 0;
|
||||
/** @var Transaction $tr */
|
||||
foreach ($result->transactions()->get() as $tr) {
|
||||
if (floatval($tr->amount) > 0) {
|
||||
$amount = floatval($tr->amount);
|
||||
}
|
||||
}
|
||||
$chart->addRow(clone $result->date, $bill->amount_max, $bill->amount_min, $amount);
|
||||
$chart->addRow(clone $result->date, floatval($bill->amount_max), floatval($bill->amount_min), floatval($result->amount));
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
@@ -317,18 +241,21 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function billsOverview(GChart $chart, BillRepositoryInterface $repository)
|
||||
public function billsOverview(GChart $chart, BillRepositoryInterface $repository, AccountRepositoryInterface $accounts)
|
||||
{
|
||||
$chart->addColumn('Name', 'string');
|
||||
$chart->addColumn('Amount', 'number');
|
||||
|
||||
|
||||
$paid = ['items' => [], 'amount' => 0];
|
||||
$unpaid = ['items' => [], 'amount' => 0];
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
$bills = Auth::user()->bills()->where('active', 1)->get();
|
||||
$bills = $repository->getActiveBills();
|
||||
$paid = new Collection; // journals.
|
||||
$unpaid = new Collection; // bills
|
||||
// loop paid and create single entry:
|
||||
$paidDescriptions = [];
|
||||
$paidAmount = 0;
|
||||
$unpaidDescriptions = [];
|
||||
$unpaidAmount = 0;
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
@@ -336,71 +263,56 @@ class GoogleChartController extends Controller
|
||||
|
||||
foreach ($ranges as $range) {
|
||||
// paid a bill in this range?
|
||||
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
|
||||
if ($count == 0) {
|
||||
$unpaid['items'][] = $bill->name . ' (' . $range['start']->format('jS M Y') . ')';
|
||||
$unpaid['amount'] += ($bill->amount_max + $bill->amount_min / 2);
|
||||
|
||||
$journals = $repository->getJournalsInRange($bill, $range['start'], $range['end']);
|
||||
if ($journals->count() == 0) {
|
||||
$unpaid->push([$bill, $range['start']]);
|
||||
} else {
|
||||
$journal = $bill->transactionjournals()->with('transactions')->before($range['end'])->after($range['start'])->first();
|
||||
$paid['items'][] = $journal->description;
|
||||
$amount = 0;
|
||||
foreach ($journal->transactions as $t) {
|
||||
if (floatval($t->amount) > 0) {
|
||||
$amount = floatval($t->amount);
|
||||
}
|
||||
}
|
||||
$paid['amount'] += $amount;
|
||||
$paid = $paid->merge($journals);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find credit card accounts and possibly unpaid credit card bills.
|
||||
*/
|
||||
$creditCards = Auth::user()->accounts()
|
||||
->hasMetaValue('accountRole', 'ccAsset')
|
||||
->hasMetaValue('ccType', 'monthlyFull')
|
||||
->get(
|
||||
[
|
||||
'accounts.*',
|
||||
'ccType.data as ccType',
|
||||
'accountRole.data as accountRole'
|
||||
]
|
||||
);
|
||||
// if the balance is not zero, the monthly payment is still underway.
|
||||
/** @var Account $creditCard */
|
||||
$creditCards = $accounts->getCreditCards();
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, null, true);
|
||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||
if ($balance < 0) {
|
||||
// unpaid!
|
||||
$unpaid['amount'] += $balance * -1;
|
||||
$unpaid['items'][] = $creditCard->name . ' (expected ' . Amount::format(($balance * -1), false) . ') on the ' . $date->format('jS') . ')';
|
||||
// unpaid! create a fake bill that matches the amount.
|
||||
$description = $creditCard->name;
|
||||
$amount = $balance * -1;
|
||||
$fakeBill = $repository->createFakeBill($description, $date, $amount);
|
||||
unset($description, $amount);
|
||||
$unpaid->push([$fakeBill, $date]);
|
||||
}
|
||||
if ($balance == 0) {
|
||||
// find a transfer TO the credit card which should account for
|
||||
// find transfer(s) TO the credit card which should account for
|
||||
// anything paid. If not, the CC is not yet used.
|
||||
$transactions = $creditCard->transactions()
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->before($end)->after($start)->get();
|
||||
if ($transactions->count() > 0) {
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$journal = $transaction->transactionJournal;
|
||||
if ($journal->transactionType->type == 'Transfer') {
|
||||
$paid['amount'] += floatval($transaction->amount);
|
||||
$paid['items'][] = $creditCard->name .
|
||||
' (paid ' . Amount::format((floatval($transaction->amount)), false) .
|
||||
' on the ' . $journal->date->format('jS') . ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
$journals = $accounts->getTransfersInRange($creditCard, $start, $end);
|
||||
$paid = $paid->merge($journals);
|
||||
}
|
||||
}
|
||||
$chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
|
||||
$chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
|
||||
|
||||
|
||||
/** @var TransactionJournal $entry */
|
||||
foreach ($paid as $entry) {
|
||||
|
||||
$paidDescriptions[] = $entry->description;
|
||||
$paidAmount += floatval($entry->amount);
|
||||
}
|
||||
|
||||
// loop unpaid:
|
||||
/** @var Bill $entry */
|
||||
foreach ($unpaid as $entry) {
|
||||
$description = $entry[0]->name . ' (' . $entry[1]->format('jS M Y') . ')';
|
||||
$amount = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
|
||||
$unpaidDescriptions[] = $description;
|
||||
$unpaidAmount += $amount;
|
||||
unset($amount, $description);
|
||||
}
|
||||
|
||||
$chart->addRow('Unpaid: ' . join(', ', $unpaidDescriptions), $unpaidAmount);
|
||||
$chart->addRow('Paid: ' . join(', ', $paidDescriptions), $paidAmount);
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
@@ -413,7 +325,7 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function budgetLimitSpending(Budget $budget, LimitRepetition $repetition, GChart $chart)
|
||||
public function budgetLimitSpending(Budget $budget, LimitRepetition $repetition, GChart $chart, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$start = clone $repetition->startdate;
|
||||
$end = $repetition->enddate;
|
||||
@@ -428,7 +340,7 @@ class GoogleChartController extends Controller
|
||||
/*
|
||||
* Sum of expenses on this day:
|
||||
*/
|
||||
$sum = floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($start)->sum('amount'));
|
||||
$sum = $repository->expensesOnDay($budget, $start);
|
||||
$amount += $sum;
|
||||
$chart->addRow(clone $start, $amount);
|
||||
$start->addDay();
|
||||
@@ -440,37 +352,22 @@ class GoogleChartController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param int $year
|
||||
* @param GChart $chart
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
*
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @param int $year
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function budgetsAndSpending(Budget $budget, $year = 0)
|
||||
public function budgetsAndSpending(GChart $chart, BudgetRepositoryInterface $repository, Budget $budget, $year = 0)
|
||||
{
|
||||
|
||||
$chart = App::make('Grumpydictator\Gchart\GChart');
|
||||
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepository');
|
||||
$chart->addColumn('Month', 'date');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
if ($year == 0) {
|
||||
// grab the first budgetlimit ever:
|
||||
$firstLimit = $budget->budgetlimits()->orderBy('startdate', 'ASC')->first();
|
||||
if ($firstLimit) {
|
||||
$start = new Carbon($firstLimit->startdate);
|
||||
} else {
|
||||
$start = Carbon::now()->startOfYear();
|
||||
}
|
||||
|
||||
// grab the last budget limit ever:
|
||||
$lastLimit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first();
|
||||
if ($lastLimit) {
|
||||
$end = new Carbon($lastLimit->startdate);
|
||||
} else {
|
||||
$end = Carbon::now()->endOfYear();
|
||||
}
|
||||
if ($year == 0) {
|
||||
$start = $repository->getFirstBudgetLimitDate($budget);
|
||||
$end = $repository->getLastBudgetLimitDate($budget);
|
||||
} else {
|
||||
$start = Carbon::createFromDate(intval($year), 1, 1);
|
||||
$end = clone $start;
|
||||
@@ -478,19 +375,8 @@ class GoogleChartController extends Controller
|
||||
}
|
||||
|
||||
while ($start <= $end) {
|
||||
$spent = $repository->spentInMonth($budget, $start);
|
||||
$repetition = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.budget_id', $budget->id)
|
||||
->first(['limit_repetitions.*']);
|
||||
|
||||
if ($repetition) {
|
||||
$budgeted = floatval($repetition->amount);
|
||||
\Log::debug('Found a repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name . '!');
|
||||
} else {
|
||||
\Log::debug('No repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name);
|
||||
$budgeted = null;
|
||||
}
|
||||
$spent = $repository->spentInMonth($budget, $start);
|
||||
$budgeted = $repository->getLimitAmountOnDate($budget, $start);
|
||||
$chart->addRow(clone $start, $budgeted, $spent);
|
||||
$start->addMonth();
|
||||
}
|
||||
@@ -508,12 +394,11 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function categoryOverviewChart(Category $category, GChart $chart)
|
||||
public function categoryOverviewChart(Category $category, GChart $chart, CategoryRepositoryInterface $repository)
|
||||
{
|
||||
// oldest transaction in category:
|
||||
/** @var TransactionJournal $first */
|
||||
$first = $category->transactionjournals()->orderBy('date', 'ASC')->first();
|
||||
$start = $first->date;
|
||||
$start = $repository->getFirstActivityDate($category);
|
||||
|
||||
/** @var Preference $range */
|
||||
$range = Preferences::get('viewRange', '1M');
|
||||
// jump to start of week / month / year / etc (TODO).
|
||||
@@ -526,13 +411,12 @@ class GoogleChartController extends Controller
|
||||
while ($start <= $end) {
|
||||
|
||||
$currentEnd = Navigation::endOfPeriod($start, $range->data);
|
||||
$spent = floatval($category->transactionjournals()->before($currentEnd)->after($start)->lessThan(0)->sum('amount')) * -1;
|
||||
$spent = $repository->spentInPeriodSum($category, $start, $currentEnd);
|
||||
$chart->addRow(clone $start, $spent);
|
||||
|
||||
$start = Navigation::addPeriod($start, $range->data, 0);
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
@@ -546,17 +430,15 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function categoryPeriodChart(Category $category, GChart $chart)
|
||||
public function categoryPeriodChart(Category $category, GChart $chart, CategoryRepositoryInterface $repository)
|
||||
{
|
||||
// oldest transaction in category:
|
||||
/** @var TransactionJournal $first */
|
||||
$start = clone Session::get('start');
|
||||
$start = clone Session::get('start', Carbon::now()->startOfMonth());
|
||||
$chart->addColumn('Period', 'date');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
$end = Session::get('end');
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
while ($start <= $end) {
|
||||
$spent = floatval($category->transactionjournals()->onDate($start)->lessThan(0)->sum('amount')) * -1;
|
||||
$spent = $repository->spentOnDaySum($category, $start);
|
||||
$chart->addRow(clone $start, $spent);
|
||||
$start->addDay();
|
||||
}
|
||||
@@ -574,13 +456,13 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function piggyBankHistory(PiggyBank $piggyBank, GChart $chart)
|
||||
public function piggyBankHistory(PiggyBank $piggyBank, GChart $chart, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
$chart->addColumn('Date', 'date');
|
||||
$chart->addColumn('Balance', 'number');
|
||||
|
||||
/** @var Collection $set */
|
||||
$set = DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
|
||||
$set = $repository->getEventSummarySet($piggyBank);
|
||||
$sum = 0;
|
||||
|
||||
foreach ($set as $entry) {
|
||||
@@ -602,11 +484,7 @@ class GoogleChartController extends Controller
|
||||
*/
|
||||
public function yearInExp($year, GChart $chart, ReportQueryInterface $query)
|
||||
{
|
||||
try {
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid year.');
|
||||
}
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
$chart->addColumn('Month', 'date');
|
||||
$chart->addColumn('Income', 'number');
|
||||
$chart->addColumn('Expenses', 'number');
|
||||
@@ -621,19 +499,9 @@ class GoogleChartController extends Controller
|
||||
while ($start < $end) {
|
||||
$currentEnd = clone $start;
|
||||
$currentEnd->endOfMonth();
|
||||
// total income:
|
||||
$income = $query->incomeByPeriod($start, $currentEnd, $showSharedReports);
|
||||
$incomeSum = 0;
|
||||
foreach ($income as $entry) {
|
||||
$incomeSum += floatval($entry->amount);
|
||||
}
|
||||
|
||||
// total expenses:
|
||||
$expense = $query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports);
|
||||
$expenseSum = 0;
|
||||
foreach ($expense as $entry) {
|
||||
$expenseSum += floatval($entry->amount);
|
||||
}
|
||||
// total income && total expenses:
|
||||
$incomeSum = floatval($query->incomeByPeriod($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
|
||||
$expenseSum = floatval($query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
|
||||
|
||||
$chart->addRow(clone $start, $incomeSum, $expenseSum);
|
||||
$start->addMonth();
|
||||
@@ -654,11 +522,7 @@ class GoogleChartController extends Controller
|
||||
*/
|
||||
public function yearInExpSum($year, GChart $chart, ReportQueryInterface $query)
|
||||
{
|
||||
try {
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid year.');
|
||||
}
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
$chart->addColumn('Summary', 'string');
|
||||
$chart->addColumn('Income', 'number');
|
||||
$chart->addColumn('Expenses', 'number');
|
||||
@@ -676,18 +540,9 @@ class GoogleChartController extends Controller
|
||||
$currentEnd = clone $start;
|
||||
$currentEnd->endOfMonth();
|
||||
// total income:
|
||||
$incomeResult = $query->incomeByPeriod($start, $currentEnd, $showSharedReports);
|
||||
$incomeSum = 0;
|
||||
foreach ($incomeResult as $entry) {
|
||||
$incomeSum += floatval($entry->amount);
|
||||
}
|
||||
|
||||
$incomeSum = floatval($query->incomeByPeriod($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
|
||||
// total expenses:
|
||||
$expenseResult = $query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports);
|
||||
$expenseSum = 0;
|
||||
foreach ($expenseResult as $entry) {
|
||||
$expenseSum += floatval($entry->amount);
|
||||
}
|
||||
$expenseSum = floatval($query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
|
||||
|
||||
$income += $incomeSum;
|
||||
$expense += $expenseSum;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Cache;
|
||||
use ErrorException;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use FireflyIII\Helpers\Help\HelpInterface;
|
||||
use Log;
|
||||
use Response;
|
||||
use Route;
|
||||
|
||||
/**
|
||||
* Class HelpController
|
||||
@@ -19,73 +17,34 @@ class HelpController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show($route)
|
||||
public function show($route, HelpInterface $help)
|
||||
{
|
||||
$content = [
|
||||
'text' => '<p>There is no help for this route!</p>',
|
||||
'title' => 'Help',
|
||||
];
|
||||
|
||||
if (!Route::has($route)) {
|
||||
\Log::error('No such route: ' . $route);
|
||||
if (!$help->hasRoute($route)) {
|
||||
Log::error('No such route: ' . $route);
|
||||
|
||||
return Response::json($content);
|
||||
}
|
||||
|
||||
if ($this->inCache($route)) {
|
||||
if ($help->inCache($route)) {
|
||||
$content = [
|
||||
'text' => Cache::get('help.' . $route . '.text'),
|
||||
'title' => Cache::get('help.' . $route . '.title'),
|
||||
'text' => $help->getFromCache('help.' . $route . '.text'),
|
||||
'title' => $help->getFromCache('help.' . $route . '.title'),
|
||||
];
|
||||
|
||||
return Response::json($content);
|
||||
}
|
||||
$content = $this->getFromGithub($route);
|
||||
$content = $help->getFromGithub($route);
|
||||
|
||||
|
||||
Cache::put('help.' . $route . '.text', $content['text'], 10080); // a week.
|
||||
Cache::put('help.' . $route . '.title', $content['title'], 10080);
|
||||
$help->putInCache($route, $content);
|
||||
|
||||
return Response::json($content);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function inCache($route)
|
||||
{
|
||||
return Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFromGithub($route)
|
||||
{
|
||||
$uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md';
|
||||
$content = [
|
||||
'text' => '<p>There is no help for this route!</p>',
|
||||
'title' => $route,
|
||||
];
|
||||
try {
|
||||
$content['text'] = file_get_contents($uri);
|
||||
} catch (ErrorException $e) {
|
||||
\Log::error(trim($e->getMessage()));
|
||||
}
|
||||
if (strlen(trim($content['text'])) == 0) {
|
||||
$content['text'] = '<p>There is no help for this route.</p>';
|
||||
}
|
||||
$converter = new CommonMarkConverter();
|
||||
$content['text'] = $converter->convertToHtml($content['text']);
|
||||
|
||||
return $content;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Session;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class HomeController
|
||||
*
|
||||
@@ -30,30 +32,45 @@ class HomeController extends Controller
|
||||
Session::put('end', $end);
|
||||
}
|
||||
|
||||
public function flush() {
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
Session::clear();
|
||||
|
||||
return Redirect::route('index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$count = $repository->countAssetAccounts();
|
||||
$title = 'Firefly';
|
||||
$subTitle = 'What\'s playing?';
|
||||
$mainTitleIcon = 'fa-fire';
|
||||
$transactions = [];
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$accounts = $repository->getFrontpageAccounts($frontPage);
|
||||
$savings = $repository->getSavingsAccounts();
|
||||
$types = Config::get('firefly.accountTypesByIdentifier.asset');
|
||||
$count = $repository->countAccounts($types);
|
||||
$title = 'Firefly';
|
||||
$subTitle = 'What\'s playing?';
|
||||
$mainTitleIcon = 'fa-fire';
|
||||
$transactions = [];
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$accounts = $repository->getFrontpageAccounts($frontPage);
|
||||
$savings = $repository->getSavingsAccounts();
|
||||
$piggyBankAccounts = $repository->getPiggyBankAccounts();
|
||||
|
||||
|
||||
$savingsTotal = 0;
|
||||
foreach ($savings as $savingAccount) {
|
||||
$savingsTotal += Steam::balance($savingAccount, $end);
|
||||
}
|
||||
|
||||
// check if all books are correct.
|
||||
$sum = floatval(Auth::user()->transactions()->sum('amount'));
|
||||
$sum = $repository->sumOfEverything();
|
||||
if ($sum != 0) {
|
||||
Session::flash(
|
||||
'error', 'Your transactions are unbalanced. This means a'
|
||||
@@ -69,7 +86,7 @@ class HomeController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
return view('index', compact('count', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions'));
|
||||
return view('index', compact('count', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions', 'savingsTotal', 'piggyBankAccounts'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Amount;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Helpers\Report\ReportQueryInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use Input;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use Session;
|
||||
@@ -23,149 +26,124 @@ use Steam;
|
||||
class JsonController extends Controller
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param BillRepositoryInterface $repository
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function box(BillRepositoryInterface $repository)
|
||||
public function boxBillsPaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$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);
|
||||
}
|
||||
// these two functions are the same as the chart TODO
|
||||
$bills = $repository->getActiveBills();
|
||||
|
||||
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);
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
$ranges = $repository->getRanges($bill, $start, $end);
|
||||
foreach ($ranges as $range) {
|
||||
// paid a bill in this range?
|
||||
$amount += $repository->getJournalsInRange($bill, $range['start'], $range['end'])->sum('amount');
|
||||
}
|
||||
}
|
||||
unset($ranges, $bill, $range, $bills);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find credit card accounts and possibly unpaid credit card bills.
|
||||
*/
|
||||
$creditCards = Auth::user()->accounts()
|
||||
->hasMetaValue('accountRole', 'ccAsset')
|
||||
->hasMetaValue('ccType', 'monthlyFull')
|
||||
->get(
|
||||
[
|
||||
'accounts.*',
|
||||
'ccType.data as ccType',
|
||||
'accountRole.data as accountRole'
|
||||
]
|
||||
);
|
||||
// if the balance is not zero, the monthly payment is still underway.
|
||||
/** @var Account $creditCard */
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, null, true);
|
||||
if ($balance < 0) {
|
||||
// unpaid!
|
||||
$amount += $balance * -1;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
$currentAmount = 0;
|
||||
foreach ($journal->transactions as $t) {
|
||||
if (floatval($t->amount) > 0) {
|
||||
$currentAmount = floatval($t->amount);
|
||||
}
|
||||
}
|
||||
$amount += $currentAmount;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find credit card accounts and possibly unpaid credit card bills.
|
||||
*/
|
||||
$creditCards = Auth::user()->accounts()
|
||||
->hasMetaValue('accountRole', 'ccAsset')
|
||||
->hasMetaValue('ccType', 'monthlyFull')
|
||||
->get(
|
||||
[
|
||||
'accounts.*',
|
||||
'ccType.data as ccType',
|
||||
'accountRole.data as accountRole'
|
||||
]
|
||||
);
|
||||
// if the balance is not zero, the monthly payment is still underway.
|
||||
/** @var Account $creditCard */
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, null, true);
|
||||
if ($balance == 0) {
|
||||
// find a transfer TO the credit card which should account for
|
||||
// anything paid. If not, the CC is not yet used.
|
||||
$transactions = $creditCard->transactions()
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->before($end)->after($start)->get();
|
||||
if ($transactions->count() > 0) {
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$journal = $transaction->transactionJournal;
|
||||
if ($journal->transactionType->type == 'Transfer') {
|
||||
$amount += floatval($transaction->amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Find credit card accounts and possibly unpaid credit card bills.
|
||||
*/
|
||||
$creditCards = $accountRepository->getCreditCards();
|
||||
// if the balance is not zero, the monthly payment is still underway.
|
||||
/** @var Account $creditCard */
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, null, true);
|
||||
if ($balance == 0) {
|
||||
// find a transfer TO the credit card which should account for
|
||||
// anything paid. If not, the CC is not yet used.
|
||||
$amount += $accountRepository->getTransfersInRange($creditCard, $start, $end)->sum('amount');
|
||||
}
|
||||
}
|
||||
|
||||
return Response::json(['box' => $box, 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
|
||||
return Response::json(['box' => 'bills-paid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BillRepositoryInterface $repository
|
||||
* @param AccountRepositoryInterface $accountRepository
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxBillsUnpaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$amount = 0;
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$bills = $repository->getActiveBills();
|
||||
$unpaid = new Collection; // bills
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
$ranges = $repository->getRanges($bill, $start, $end);
|
||||
|
||||
foreach ($ranges as $range) {
|
||||
$journals = $repository->getJournalsInRange($bill, $range['start'], $range['end']);
|
||||
if ($journals->count() == 0) {
|
||||
$unpaid->push([$bill, $range['start']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($bill, $bills, $range, $ranges);
|
||||
|
||||
$creditCards = $accountRepository->getCreditCards();
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, null, true);
|
||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||
if ($balance < 0) {
|
||||
// unpaid! create a fake bill that matches the amount.
|
||||
$description = $creditCard->name;
|
||||
$fakeAmount = $balance * -1;
|
||||
$fakeBill = $repository->createFakeBill($description, $date, $fakeAmount);
|
||||
$unpaid->push([$fakeBill, $date]);
|
||||
}
|
||||
}
|
||||
/** @var Bill $entry */
|
||||
foreach ($unpaid as $entry) {
|
||||
$current = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
|
||||
$amount += $current;
|
||||
}
|
||||
|
||||
return Response::json(['box' => 'bills-unpaid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReportQueryInterface $reportQuery
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxIn(ReportQueryInterface $reportQuery)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$amount = $reportQuery->incomeByPeriod($start, $end, true)->sum('queryAmount');
|
||||
|
||||
return Response::json(['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReportQueryInterface $reportQuery
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxOut(ReportQueryInterface $reportQuery)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$amount = $reportQuery->journalsByExpenseAccount($start, $end, true)->sum('queryAmount');
|
||||
|
||||
return Response::json(['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,13 +151,14 @@ class JsonController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function categories()
|
||||
public function categories(CategoryRepositoryInterface $repository)
|
||||
{
|
||||
$list = Auth::user()->categories()->orderBy('name', 'ASC')->get();
|
||||
$list = $repository->getCategories();
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
}
|
||||
sort($return);
|
||||
|
||||
return Response::json($return);
|
||||
}
|
||||
@@ -189,9 +168,9 @@ class JsonController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function expenseAccounts()
|
||||
public function expenseAccounts(AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$list = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Expense account', 'Beneficiary account'])->get();
|
||||
$list = $accountRepository->getAccounts(['Expense account', 'Beneficiary account']);
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
@@ -202,11 +181,28 @@ class JsonController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON list of all beneficiaries.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function revenueAccounts()
|
||||
public function tags(TagRepositoryInterface $tagRepository)
|
||||
{
|
||||
$list = Auth::user()->accounts()->accountTypeIn(['Revenue account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
|
||||
$list = $tagRepository->get();
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->tag;
|
||||
}
|
||||
|
||||
return Response::json($return);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function revenueAccounts(AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$list = $accountRepository->getAccounts(['Revenue account']);
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
@@ -239,13 +235,17 @@ class JsonController extends Controller
|
||||
return Response::json(['value' => $pref->data]);
|
||||
}
|
||||
|
||||
public function transactionJournals($what)
|
||||
/**
|
||||
* @param $what
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function transactionJournals($what, JournalRepositoryInterface $repository)
|
||||
{
|
||||
$descriptions = [];
|
||||
$dbType = TransactionType::whereType($what)->first();
|
||||
$journals = Auth::user()->transactionjournals()->where('transaction_type_id', $dbType->id)
|
||||
->orderBy('id', 'DESC')->take(50)
|
||||
->get();
|
||||
$dbType = $repository->getTransactionType($what);
|
||||
|
||||
$journals = $repository->getJournalsOfType($dbType);
|
||||
foreach ($journals as $j) {
|
||||
$descriptions[] = $j->description;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Amount;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use ExpandedForm;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\PiggyBankFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
@@ -16,8 +16,8 @@ use Input;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use Steam;
|
||||
use View;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class PiggyBankController
|
||||
@@ -32,6 +32,7 @@ class PiggyBankController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Piggy banks');
|
||||
View::share('mainTitleIcon', 'fa-sort-amount-asc');
|
||||
}
|
||||
@@ -56,13 +57,13 @@ class PiggyBankController extends Controller
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function create()
|
||||
public function create(AccountRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$periods = Config::get('firefly.piggy_bank_periods');
|
||||
$accounts = ExpandedForm::makeSelectList(
|
||||
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
|
||||
);
|
||||
$periods = Config::get('firefly.piggy_bank_periods');
|
||||
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
||||
//Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
|
||||
// );
|
||||
$subTitle = 'Create new piggy bank';
|
||||
$subTitleIcon = 'fa-plus';
|
||||
|
||||
@@ -95,11 +96,12 @@ class PiggyBankController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(PiggyBank $piggyBank)
|
||||
public function destroy(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
|
||||
Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.');
|
||||
$piggyBank->delete();
|
||||
$repository->destroy($piggyBank);
|
||||
|
||||
return Redirect::to(Session::get('piggy-banks.delete.url'));
|
||||
}
|
||||
@@ -111,13 +113,11 @@ class PiggyBankController extends Controller
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function edit(PiggyBank $piggyBank)
|
||||
public function edit(PiggyBank $piggyBank, AccountRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$periods = Config::get('firefly.piggy_bank_periods');
|
||||
$accounts = ExpandedForm::makeSelectList(
|
||||
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
|
||||
);
|
||||
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
||||
$subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"';
|
||||
$subTitleIcon = 'fa-pencil';
|
||||
|
||||
@@ -151,16 +151,16 @@ class PiggyBankController extends Controller
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
public function index(AccountRepositoryInterface $repository, PiggyBankRepositoryInterface $piggyRepository)
|
||||
{
|
||||
/** @var Collection $piggyBanks */
|
||||
$piggyBanks = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get();
|
||||
$piggyBanks = $piggyRepository->getPiggyBanks();
|
||||
|
||||
$accounts = [];
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($piggyBanks as $piggyBank) {
|
||||
$piggyBank->savedSoFar = floatval($piggyBank->currentRelevantRep()->currentamount);
|
||||
$piggyBank->percentage = intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100);
|
||||
$piggyBank->percentage = $piggyBank->savedSoFar != 0 ? intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100) : 0;
|
||||
$piggyBank->leftToSave = $piggyBank->targetamount - $piggyBank->savedSoFar;
|
||||
|
||||
/*
|
||||
@@ -170,7 +170,7 @@ class PiggyBankController extends Controller
|
||||
if (!isset($accounts[$account->id])) {
|
||||
$accounts[$account->id] = [
|
||||
'name' => $account->name,
|
||||
'balance' => Steam::balance($account,null,true),
|
||||
'balance' => Steam::balance($account, null, true),
|
||||
'leftForPiggyBanks' => $repository->leftOnAccount($account),
|
||||
'sumOfSaved' => $piggyBank->savedSoFar,
|
||||
'sumOfTargets' => floatval($piggyBank->targetamount),
|
||||
@@ -223,8 +223,8 @@ class PiggyBankController extends Controller
|
||||
$repetition->currentamount += $amount;
|
||||
$repetition->save();
|
||||
|
||||
// create event.
|
||||
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
|
||||
// create event
|
||||
$repository->createEvent($piggyBank, $amount);
|
||||
|
||||
/*
|
||||
* Create event!
|
||||
@@ -244,7 +244,7 @@ class PiggyBankController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function postRemove(PiggyBank $piggyBank)
|
||||
public function postRemove(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
$amount = floatval(Input::get('amount'));
|
||||
|
||||
@@ -255,12 +255,8 @@ class PiggyBankController extends Controller
|
||||
$repetition->currentamount -= $amount;
|
||||
$repetition->save();
|
||||
|
||||
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount * -1, 'piggy_bank_id' => $piggyBank->id]);
|
||||
|
||||
/*
|
||||
* Create event!
|
||||
*/
|
||||
//Event::fire('piggy_bank.removeMoney', [$piggyBank, $amount]); // new and used.
|
||||
// create event
|
||||
$repository->createEvent($piggyBank, $amount * -1);
|
||||
|
||||
Session::flash('success', 'Removed ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".');
|
||||
} else {
|
||||
@@ -287,10 +283,9 @@ class PiggyBankController extends Controller
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function show(PiggyBank $piggyBank)
|
||||
public function show(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$events = $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get();
|
||||
$events = $repository->getEvents($piggyBank);
|
||||
|
||||
/*
|
||||
* Number of reminders:
|
||||
@@ -310,6 +305,7 @@ class PiggyBankController extends Controller
|
||||
*/
|
||||
public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$piggyBankData = [
|
||||
'name' => $request->get('name'),
|
||||
'startdate' => new Carbon,
|
||||
@@ -326,6 +322,7 @@ class PiggyBankController extends Controller
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
Session::put('piggy-banks.create.fromStore', true);
|
||||
|
||||
return Redirect::route('piggy-banks.create')->withInput();
|
||||
}
|
||||
|
||||
@@ -353,13 +350,13 @@ class PiggyBankController extends Controller
|
||||
'remind_me' => $request->get('remind_me')
|
||||
];
|
||||
|
||||
|
||||
$piggyBank = $repository->update($piggyBank, $piggyBankData);
|
||||
|
||||
Session::flash('success', 'Updated piggy bank "' . e($piggyBank->name) . '".');
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
Session::put('piggy-banks.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('piggy-banks.edit', $piggyBank->id);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
@@ -20,7 +20,7 @@ class PreferencesController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
parent::__construct();
|
||||
View::share('title', 'Preferences');
|
||||
View::share('mainTitleIcon', 'fa-gear');
|
||||
}
|
||||
@@ -28,9 +28,9 @@ class PreferencesController extends Controller
|
||||
/**
|
||||
* @return $this|\Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
{
|
||||
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
|
||||
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
|
||||
$viewRange = Preferences::get('viewRange', '1M');
|
||||
$viewRangeValue = $viewRange->data;
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\DeleteAccountFormRequest;
|
||||
use FireflyIII\Http\Requests\ProfileFormRequest;
|
||||
use Hash;
|
||||
use Redirect;
|
||||
@@ -34,6 +35,37 @@ class ProfileController extends Controller
|
||||
return view('profile.index')->with('title', 'Profile')->with('subTitle', Auth::user()->email)->with('mainTitleIcon', 'fa-user');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function deleteAccount()
|
||||
{
|
||||
return view('profile.delete-account')->with('title', Auth::user()->email)->with('subTitle', 'Delete account')->with(
|
||||
'mainTitleIcon', 'fa-user'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function postDeleteAccount(DeleteAccountFormRequest $request)
|
||||
{
|
||||
// old, new1, new2
|
||||
if (!Hash::check($request->get('password'), Auth::user()->password)) {
|
||||
Session::flash('error', 'Invalid password!');
|
||||
|
||||
return Redirect::route('delete-account');
|
||||
}
|
||||
|
||||
// DELETE!
|
||||
Auth::user()->delete();
|
||||
Session::flush();
|
||||
|
||||
return Redirect::route('index');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
||||
*/
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Input;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use URL;
|
||||
|
||||
/**
|
||||
* Class RelatedController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class RelatedController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function alreadyRelated(TransactionJournal $journal)
|
||||
{
|
||||
$ids = [];
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($journal->transactiongroups()->get() as $group) {
|
||||
/** @var TransactionJournal $loopJournal */
|
||||
foreach ($group->transactionjournals()->get() as $loopJournal) {
|
||||
if ($loopJournal->id != $journal->id) {
|
||||
$ids[] = $loopJournal->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
$unique = array_unique($ids);
|
||||
$journals = new Collection;
|
||||
if (count($unique) > 0) {
|
||||
|
||||
$journals = Auth::user()->transactionjournals()->whereIn('id', $unique)->get();
|
||||
$journals->each(
|
||||
function (TransactionJournal $journal) {
|
||||
/** @var Transaction $t */
|
||||
foreach ($journal->transactions()->get() as $t) {
|
||||
if ($t->amount > 0) {
|
||||
$journal->amount = $t->amount;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
$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());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $parentJournal
|
||||
* @param TransactionJournal $childJournal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function relate(TransactionJournal $parentJournal, TransactionJournal $childJournal)
|
||||
{
|
||||
$group = new TransactionGroup;
|
||||
$group->relation = 'balance';
|
||||
$group->user_id = Auth::user()->id;
|
||||
$group->save();
|
||||
$group->transactionjournals()->save($parentJournal);
|
||||
$group->transactionjournals()->save($childJournal);
|
||||
|
||||
return Response::json(true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function related(TransactionJournal $journal)
|
||||
{
|
||||
$groups = $journal->transactiongroups()->get();
|
||||
$members = new Collection;
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($groups as $group) {
|
||||
/** @var TransactionJournal $loopJournal */
|
||||
foreach ($group->transactionjournals()->get() as $loopJournal) {
|
||||
if ($loopJournal->id != $journal->id) {
|
||||
$members->push($loopJournal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return view('related.relate', compact('journal', 'members'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 removeRelation(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 Response::json(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function search(TransactionJournal $journal, JournalRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$search = e(trim(Input::get('searchValue')));
|
||||
$parent = $journal;
|
||||
|
||||
$journals = $repository->searchRelated($search, $journal);
|
||||
|
||||
return view('related.searchResult', compact('journals', 'search', 'parent'));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,6 @@ use Preferences;
|
||||
use Session;
|
||||
use Steam;
|
||||
use View;
|
||||
use Crypt;
|
||||
|
||||
/**
|
||||
* Class ReportController
|
||||
@@ -48,50 +47,51 @@ class ReportController extends Controller
|
||||
*/
|
||||
public function budget($year = '2014', $month = '1')
|
||||
{
|
||||
try {
|
||||
new Carbon($year . '-' . $month . '-01');
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid date');
|
||||
}
|
||||
$date = new Carbon($year . '-' . $month . '-01');
|
||||
$start = clone $date;
|
||||
$date = new Carbon($year . '-' . $month . '-01');
|
||||
$subTitle = 'Budget report for ' . $date->format('F Y');
|
||||
$subTitleIcon = 'fa-calendar';
|
||||
$start = clone $date;
|
||||
|
||||
|
||||
$start->startOfMonth();
|
||||
$end = clone $date;
|
||||
$end->endOfMonth();
|
||||
$start->subDay();
|
||||
|
||||
// should show shared reports?
|
||||
/** @var Preference $pref */
|
||||
$pref = Preferences::get('showSharedReports', false);
|
||||
$showSharedReports = $pref->data;
|
||||
$accountAmounts = []; // array with sums of spent amounts on each account.
|
||||
$accounts = $this->query->getAllAccounts($start, $end, $showSharedReports); // all accounts and some data.
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
|
||||
$dayEarly = clone $date;
|
||||
$subTitle = 'Budget report for ' . $date->format('F Y');
|
||||
$subTitleIcon = 'fa-calendar';
|
||||
$dayEarly = $dayEarly->subDay();
|
||||
$accounts = $this->query->getAllAccounts($start, $end, $showSharedReports);
|
||||
$start->addDay();
|
||||
$budgets = $this->query->getBudgetSummary($account, $start, $end);// get budget summary for this account:
|
||||
$balancedAmount = $this->query->balancedTransactionsSum($account, $start, $end);
|
||||
$accountAmounts[$account->id] = $balancedAmount;
|
||||
// balance out the transactions (see transaction groups & tags) ^^
|
||||
|
||||
$accounts->each(
|
||||
function (Account $account) use ($start, $end) {
|
||||
$budgets = $this->query->getBudgetSummary($account, $start, $end);
|
||||
$balancedAmount = $this->query->balancedTransactionsSum($account, $start, $end);
|
||||
$array = [];
|
||||
$hide = true;
|
||||
foreach ($budgets as $budget) {
|
||||
$id = intval($budget->id);
|
||||
$data = $budget->toArray();
|
||||
$array[$id] = $data;
|
||||
if (floatval($data['amount']) != 0) {
|
||||
$hide = false;
|
||||
}
|
||||
// array with budget information for each account:
|
||||
$array = [];
|
||||
// should always hide account
|
||||
$hide = true;
|
||||
// loop all budgets
|
||||
foreach ($budgets as $budget) {
|
||||
$id = intval($budget->id);
|
||||
$data = $budget->toArray();
|
||||
$array[$id] = $data;
|
||||
|
||||
// no longer hide account if any budget has money in it.
|
||||
if (floatval($data['queryAmount']) != 0) {
|
||||
$hide = false;
|
||||
}
|
||||
$account->hide = $hide;
|
||||
$account->budgetInformation = $array;
|
||||
$account->balancedAmount = $balancedAmount;
|
||||
|
||||
$accountAmounts[$account->id] += $data['queryAmount'];
|
||||
}
|
||||
);
|
||||
$account->hide = $hide;
|
||||
$account->budgetInformation = $array;
|
||||
$account->balancedAmount = $balancedAmount;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Start getBudgetsForMonth DONE
|
||||
@@ -102,7 +102,7 @@ class ReportController extends Controller
|
||||
* End getBudgetsForMonth DONE
|
||||
*/
|
||||
|
||||
return view('reports.budget', compact('subTitle', 'year', 'month', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly'));
|
||||
return view('reports.budget', compact('subTitle', 'accountAmounts', 'year', 'month', 'subTitleIcon', 'date', 'accounts', 'budgets'));
|
||||
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ class ReportController extends Controller
|
||||
/**
|
||||
* Start getExpenseGroupedForMonth DONE
|
||||
*/
|
||||
$set = $this->query->journalsByExpenseAccount($start, $end, $showSharedReports);
|
||||
$set = $this->query->journalsByExpenseAccount($start, $end, $showSharedReports);
|
||||
|
||||
$expenses = Steam::makeArray($set);
|
||||
$expenses = Steam::sortArray($expenses);
|
||||
|
||||
314
app/Http/Controllers/TagController.php
Normal file
314
app/Http/Controllers/TagController.php
Normal file
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Requests\TagFormRequest;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use Session;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class TagController
|
||||
*
|
||||
* Remember: a balancingAct takes at most one expense and one transfer.
|
||||
* an advancePayment takes at most one expense, infinite deposits and NO transfers.
|
||||
*
|
||||
* TODO transaction can only have one advancePayment OR balancingAct.
|
||||
* TODO Other attempts to put in such a tag are blocked.
|
||||
* TODO also show an error when editing a tag and it becomes either
|
||||
* TODO of these two types. Or rather, block editing of the tag.
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class TagController extends Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Tags');
|
||||
View::share('mainTitleIcon', 'fa-tags');
|
||||
View::share('hideTags', true);
|
||||
$tagOptions = [
|
||||
'nothing' => 'Just a regular tag.',
|
||||
'balancingAct' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.',
|
||||
'advancePayment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
|
||||
];
|
||||
View::share('tagOptions', $tagOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$subTitle = 'New tag';
|
||||
$subTitleIcon = 'fa-tag';
|
||||
|
||||
$preFilled = [
|
||||
'tagMode' => 'nothing'
|
||||
];
|
||||
if (!Input::old('tagMode')) {
|
||||
Session::flash('preFilled', $preFilled);
|
||||
}
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('tags.create.fromStore') !== true) {
|
||||
Session::put('tags.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('tags.create.fromStore');
|
||||
|
||||
return view('tags.create', compact('subTitle', 'subTitleIcon'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function delete(Tag $tag)
|
||||
{
|
||||
$subTitle = 'Delete "' . e($tag->tag) . '"';
|
||||
|
||||
// put previous url in session
|
||||
Session::put('tags.delete.url', URL::previous());
|
||||
|
||||
return view('tags.delete', compact('tag', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Tag $tag, TagRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$tagName = $tag->tag;
|
||||
$repository->destroy($tag);
|
||||
|
||||
Session::flash('success', 'Tag "' . e($tagName) . '" was deleted.');
|
||||
|
||||
return Redirect::to(route('tags.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function edit(Tag $tag)
|
||||
{
|
||||
$subTitle = 'Edit tag "' . e($tag->tag) . '"';
|
||||
$subTitleIcon = 'fa-tag';
|
||||
|
||||
/*
|
||||
* Default tag options (again)
|
||||
*/
|
||||
$tagOptions = [
|
||||
'nothing' => 'Just a regular tag.',
|
||||
'balancingAct' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.',
|
||||
'advancePayment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
|
||||
];
|
||||
|
||||
/*
|
||||
* Can this tag become another type?
|
||||
*/
|
||||
$allowToAdvancePayment = true;
|
||||
$allowToBalancingAct = true;
|
||||
|
||||
/*
|
||||
* If this tag is a balancing act, and it contains transfers, it cannot be
|
||||
* changes to an advancePayment.
|
||||
*/
|
||||
|
||||
if ($tag->tagMode == 'balancingAct') {
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->transactionType->type == 'Transfer') {
|
||||
$allowToAdvancePayment = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this tag contains more than one expenses, it cannot become an advance payment.
|
||||
*/
|
||||
$count = 0;
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->transactionType->type == 'Withdrawal') {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
if($count > 1) {
|
||||
$allowToAdvancePayment = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If has more than two transactions already, cannot become a balancing act:
|
||||
*/
|
||||
if ($tag->transactionjournals->count() > 2) {
|
||||
$allowToBalancingAct = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If any transaction is a deposit, cannot become a balancing act.
|
||||
*/
|
||||
$count = 0;
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->transactionType->type == 'Deposit') {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
if($count > 0) {
|
||||
$allowToBalancingAct = false;
|
||||
}
|
||||
|
||||
|
||||
// edit tagoptions:
|
||||
if ($allowToAdvancePayment === false) {
|
||||
unset($tagOptions['advancePayment']);
|
||||
}
|
||||
if ($allowToBalancingAct === false) {
|
||||
unset($tagOptions['balancingAct']);
|
||||
}
|
||||
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('tags.edit.fromUpdate') !== true) {
|
||||
Session::put('tags.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('tags.edit.fromUpdate');
|
||||
|
||||
return view('tags.edit', compact('tag', 'subTitle', 'subTitleIcon', 'tagOptions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $state
|
||||
*/
|
||||
public function hideTagHelp($state)
|
||||
{
|
||||
|
||||
$state = $state == 'true' ? true : false;
|
||||
Preferences::set('hideTagHelp', $state);
|
||||
|
||||
return Response::json(true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
/** @var Preference $helpHiddenPref */
|
||||
$helpHiddenPref = Preferences::get('hideTagHelp', false);
|
||||
$title = 'Tags';
|
||||
$mainTitleIcon = 'fa-tags';
|
||||
$helpHidden = $helpHiddenPref->data;
|
||||
$tags = Auth::user()->tags()->get();
|
||||
|
||||
return view('tags.index', compact('title', 'mainTitleIcon', 'helpHidden', 'tags'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(Tag $tag)
|
||||
{
|
||||
$subTitle = $tag->tag;
|
||||
$subTitleIcon = 'fa-tag';
|
||||
|
||||
return view('tags.show', compact('tag', 'subTitle', 'subTitleIcon'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TagFormRequest $request
|
||||
*/
|
||||
public function store(TagFormRequest $request, TagRepositoryInterface $repository)
|
||||
{
|
||||
if (Input::get('setTag') == 'true') {
|
||||
$latitude = strlen($request->get('latitude')) > 0 ? $request->get('latitude') : null;
|
||||
$longitude = strlen($request->get('longitude')) > 0 ? $request->get('longitude') : null;
|
||||
$zoomLevel = strlen($request->get('zoomLevel')) > 0 ? $request->get('zoomLevel') : null;
|
||||
} else {
|
||||
$latitude = null;
|
||||
$longitude = null;
|
||||
$zoomLevel = null;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'tag' => $request->get('tag'),
|
||||
'date' => strlen($request->get('date')) > 0 ? new Carbon($request->get('date')) : null,
|
||||
'description' => strlen($request->get('description')) > 0 ? $request->get('description') : '',
|
||||
'latitude' => $latitude,
|
||||
'longitude' => $longitude,
|
||||
'zoomLevel' => $zoomLevel,
|
||||
'tagMode' => $request->get('tagMode'),
|
||||
];
|
||||
$repository->store($data);
|
||||
|
||||
Session::flash('success', 'The tag has been created!');
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('tags.create.fromStore', true);
|
||||
|
||||
return Redirect::route('tags.create')->withInput();
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('tags.create.url'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*/
|
||||
public function update(Tag $tag, TagFormRequest $request, TagRepositoryInterface $repository)
|
||||
{
|
||||
if (Input::get('setTag') == 'true') {
|
||||
$latitude = strlen($request->get('latitude')) > 0 ? $request->get('latitude') : null;
|
||||
$longitude = strlen($request->get('longitude')) > 0 ? $request->get('longitude') : null;
|
||||
$zoomLevel = strlen($request->get('zoomLevel')) > 0 ? $request->get('zoomLevel') : null;
|
||||
} else {
|
||||
$latitude = null;
|
||||
$longitude = null;
|
||||
$zoomLevel = null;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'tag' => $request->get('tag'),
|
||||
'date' => strlen($request->get('date')) > 0 ? new Carbon($request->get('date')) : null,
|
||||
'description' => strlen($request->get('description')) > 0 ? $request->get('description') : '',
|
||||
'latitude' => $latitude,
|
||||
'longitude' => $longitude,
|
||||
'zoomLevel' => $zoomLevel,
|
||||
'tagMode' => $request->get('tagMode'),
|
||||
];
|
||||
|
||||
$repository->update($tag, $data);
|
||||
|
||||
Session::flash('success', 'Tag "' . e($data['tag']) . '" updated.');
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('tags.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('tags.edit', $tag->id)->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('tags.edit.url'));
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ class TransactionController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Transactions');
|
||||
View::share('mainTitleIcon', 'fa-repeat');
|
||||
}
|
||||
@@ -88,7 +89,7 @@ class TransactionController extends Controller
|
||||
// put previous url in session
|
||||
Session::put('transactions.delete.url', URL::previous());
|
||||
|
||||
return View::make('transactions.delete', compact('journal', 'subTitle'));
|
||||
return view('transactions.delete', compact('journal', 'subTitle'));
|
||||
|
||||
|
||||
}
|
||||
@@ -134,6 +135,12 @@ class TransactionController extends Controller
|
||||
'budget_id' => 0,
|
||||
'piggy_bank_id' => 0
|
||||
];
|
||||
// get tags:
|
||||
$tags = [];
|
||||
foreach ($journal->tags as $tag) {
|
||||
$tags[] = $tag->tag;
|
||||
}
|
||||
$preFilled['tags'] = join(',', $tags);
|
||||
|
||||
$category = $journal->categories()->first();
|
||||
if (!is_null($category)) {
|
||||
@@ -149,19 +156,15 @@ class TransactionController extends Controller
|
||||
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->orderBy('date', 'DESC')->first()->piggy_bank_id;
|
||||
}
|
||||
|
||||
$preFilled['amount'] = 0;
|
||||
/** @var Transaction $t */
|
||||
foreach ($transactions as $t) {
|
||||
if (floatval($t->amount) > 0) {
|
||||
$preFilled['amount'] = floatval($t->amount);
|
||||
}
|
||||
}
|
||||
$preFilled['account_id'] = $repository->getAssetAccount($journal);
|
||||
$preFilled['amount'] = $journal->amount;
|
||||
$preFilled['account_id'] = $journal->assetAccount->id;
|
||||
$preFilled['expense_account'] = $transactions[0]->account->name;
|
||||
$preFilled['revenue_account'] = $transactions[1]->account->name;
|
||||
$preFilled['account_from_id'] = $transactions[1]->account->id;
|
||||
$preFilled['account_to_id'] = $transactions[0]->account->id;
|
||||
|
||||
Session::flash('preFilled', $preFilled);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('transactions.edit.fromUpdate') !== true) {
|
||||
Session::put('transactions.edit.url', URL::previous());
|
||||
@@ -277,6 +280,7 @@ class TransactionController extends Controller
|
||||
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
|
||||
$journalData = $request->getJournalData();
|
||||
$journal = $repository->store($journalData);
|
||||
|
||||
|
||||
@@ -3,17 +3,13 @@
|
||||
namespace FireflyIII\Http\Middleware;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use App;
|
||||
use Closure;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankRepetition;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Navigation;
|
||||
use Session;
|
||||
use App;
|
||||
|
||||
/**
|
||||
* Class PiggyBanks
|
||||
|
||||
@@ -32,11 +32,11 @@ class AccountFormRequest extends Request
|
||||
$types = join(',', array_keys(Config::get('firefly.subTitlesByIdentifier')));
|
||||
$ccPaymentTypes = join(',', array_keys(Config::get('firefly.ccTypes')));
|
||||
|
||||
$nameRule = 'required|between:1,100|uniqueAccountForUser';
|
||||
$nameRule = 'required|min:1|uniqueAccountForUser';
|
||||
$idRule = '';
|
||||
if (Account::find(Input::get('id'))) {
|
||||
$idRule = 'belongsToUser:accounts';
|
||||
$nameRule = 'required|between:1,100|uniqueAccountForUser:' . Input::get('id');
|
||||
$nameRule = 'required|min:1|uniqueAccountForUser:' . Input::get('id');
|
||||
}
|
||||
|
||||
return [
|
||||
|
||||
@@ -30,7 +30,7 @@ class BudgetFormRequest extends Request
|
||||
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:budgets,name,encrypted';
|
||||
if (Budget::find(Input::get('id'))) {
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:budgets,name,encrypted,'.intval(Input::get('id'));
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:budgets,name,encrypted,' . intval(Input::get('id'));
|
||||
}
|
||||
|
||||
return [
|
||||
|
||||
@@ -30,7 +30,7 @@ class CategoryFormRequest extends Request
|
||||
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:categories,name,encrypted';
|
||||
if (Category::find(Input::get('id'))) {
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:categories,name,encrypted,'.intval(Input::get('id'));
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:categories,name,encrypted,' . intval(Input::get('id'));
|
||||
}
|
||||
|
||||
return [
|
||||
|
||||
@@ -21,6 +21,18 @@ class CurrencyFormRequest extends Request
|
||||
return Auth::check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getCurrencyData()
|
||||
{
|
||||
return [
|
||||
'name' => $this->get('name'),
|
||||
'code' => $this->get('code'),
|
||||
'symbol' => $this->get('symbol'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
||||
32
app/Http/Requests/DeleteAccountFormRequest.php
Normal file
32
app/Http/Requests/DeleteAccountFormRequest.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
|
||||
/**
|
||||
* Class DeleteAccountFormRequest
|
||||
*
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class DeleteAccountFormRequest extends Request
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
// Only allow logged in users
|
||||
return Auth::check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'password' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ class JournalFormRequest extends Request
|
||||
'date' => new Carbon($this->get('date')),
|
||||
'budget_id' => intval($this->get('budget_id')),
|
||||
'category' => $this->get('category'),
|
||||
'tags' => explode(',', $this->get('tags')),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Input;
|
||||
use Navigation;
|
||||
|
||||
/**
|
||||
* Class PiggyBankFormRequest
|
||||
@@ -32,7 +30,7 @@ class PiggyBankFormRequest extends Request
|
||||
$nameRule = 'required|between:1,255|uniquePiggyBankForUser';
|
||||
$targetDateRule = 'date';
|
||||
if (intval(Input::get('id'))) {
|
||||
$nameRule = 'required|between:1,255|uniquePiggyBankForUser:'.intval(Input::get('id'));
|
||||
$nameRule = 'required|between:1,255|uniquePiggyBankForUser:' . intval(Input::get('id'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
53
app/Http/Requests/TagFormRequest.php
Normal file
53
app/Http/Requests/TagFormRequest.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: sander
|
||||
* Date: 27/04/15
|
||||
* Time: 12:50
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Models\Tag;
|
||||
use Input;
|
||||
|
||||
/**
|
||||
* Class TagFormRequest
|
||||
*
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class TagFormRequest extends Request
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
// Only allow logged in users
|
||||
return Auth::check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$idRule = '';
|
||||
$tagRule = 'required|min:1|uniqueObjectForUser:tags,tag,TRUE';
|
||||
if (Tag::find(Input::get('id'))) {
|
||||
$idRule = 'belongsToUser:tags';
|
||||
$tagRule = 'required|min:1|uniqueObjectForUser:tags,tag,TRUE,' . Input::get('id');
|
||||
}
|
||||
|
||||
return [
|
||||
'tag' => $tagRule,
|
||||
'id' => $idRule,
|
||||
'description' => 'min:1',
|
||||
'date' => 'date',
|
||||
'latitude' => 'numeric|min:-90|max:90',
|
||||
'longitude' => 'numeric|min:-90|max:90',
|
||||
'tagMode' => 'required|in:nothing,balancingAct,advancePayment'
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,9 @@ use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Reminder;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
|
||||
use FireflyIII\Models\Tag;
|
||||
/*
|
||||
* Back home.
|
||||
*/
|
||||
@@ -22,6 +23,14 @@ Breadcrumbs::register(
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'index',
|
||||
function (Generator $breadcrumbs) {
|
||||
|
||||
$breadcrumbs->push('Home', route('index'));
|
||||
}
|
||||
);
|
||||
|
||||
// accounts
|
||||
Breadcrumbs::register(
|
||||
'accounts.index', function (Generator $breadcrumbs, $what) {
|
||||
@@ -95,6 +104,13 @@ Breadcrumbs::register(
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'budgets.noBudget', function (Generator $breadcrumbs, $subTitle) {
|
||||
$breadcrumbs->parent('budgets.index');
|
||||
$breadcrumbs->push($subTitle, route('budgets.noBudget'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'budgets.show', function (Generator $breadcrumbs, Budget $budget, LimitRepetition $repetition = null) {
|
||||
$breadcrumbs->parent('budgets.index');
|
||||
@@ -142,6 +158,34 @@ Breadcrumbs::register(
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'categories.noCategory', function (Generator $breadcrumbs, $subTitle) {
|
||||
$breadcrumbs->parent('categories.index');
|
||||
$breadcrumbs->push($subTitle, route('categories.noCategory'));
|
||||
}
|
||||
);
|
||||
|
||||
// currencies.
|
||||
Breadcrumbs::register(
|
||||
'currency.index', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Currencies', route('currency.index'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'currency.edit', function (Generator $breadcrumbs, TransactionCurrency $currency) {
|
||||
$breadcrumbs->parent('currency.index');
|
||||
$breadcrumbs->push('Edit '.$currency->name, route('currency.edit', $currency->id));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'currency.delete', function (Generator $breadcrumbs, TransactionCurrency $currency) {
|
||||
$breadcrumbs->parent('currency.index');
|
||||
$breadcrumbs->push('Delete '.$currency->name, route('currency.delete', $currency->id));
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// piggy banks
|
||||
Breadcrumbs::register(
|
||||
@@ -350,3 +394,24 @@ Breadcrumbs::register(
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// tags
|
||||
Breadcrumbs::register(
|
||||
'tags.index', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Tags', route('tags.index'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'tags.create', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('tags.index');
|
||||
$breadcrumbs->push('Create tag', route('tags.create'));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'tags.show', function (Generator $breadcrumbs, Tag $tag) {
|
||||
$breadcrumbs->parent('tags.index');
|
||||
$breadcrumbs->push(e($tag->tag), route('tags.show', $tag));
|
||||
}
|
||||
);
|
||||
@@ -6,8 +6,10 @@ use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Reminder;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
|
||||
// models
|
||||
@@ -15,102 +17,113 @@ Route::bind(
|
||||
'account',
|
||||
function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
$account = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
||||
->where('account_types.editable', 1)
|
||||
->where('accounts.id', $value)
|
||||
->where('user_id', Auth::user()->id)
|
||||
->first(['accounts.*']);
|
||||
if ($account) {
|
||||
return $account;
|
||||
$object = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
||||
->where('account_types.editable', 1)
|
||||
->where('accounts.id', $value)
|
||||
->where('user_id', Auth::user()->id)
|
||||
->first(['accounts.*']);
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
App::abort(404);
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'tjSecond', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return TransactionJournal::
|
||||
where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'tj', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return TransactionJournal::
|
||||
where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
$object = TransactionJournal::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'currency', function ($value, $route) {
|
||||
return TransactionCurrency::find($value);
|
||||
if (Auth::check()) {
|
||||
$object = TransactionCurrency::find($value);
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'bill', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Bill::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
$object = Bill::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'budget', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Budget::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
$object = Budget::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'reminder', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Reminder::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
$object = Reminder::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'limitrepetition', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return LimitRepetition::where('limit_repetitions.id', $value)
|
||||
->leftjoin('budget_limits', 'budget_limits.id', '=', 'limit_repetitions.budget_limit_id')
|
||||
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
|
||||
->where('budgets.user_id', Auth::user()->id)
|
||||
->first(['limit_repetitions.*']);
|
||||
$object = LimitRepetition::where('limit_repetitions.id', $value)
|
||||
->leftjoin('budget_limits', 'budget_limits.id', '=', 'limit_repetitions.budget_limit_id')
|
||||
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
|
||||
->where('budgets.user_id', Auth::user()->id)
|
||||
->first(['limit_repetitions.*']);
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'piggyBank', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return PiggyBank::
|
||||
where('piggy_banks.id', $value)
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')
|
||||
->where('accounts.user_id', Auth::user()->id)
|
||||
->first(['piggy_banks.*']);
|
||||
$object = PiggyBank::where('piggy_banks.id', $value)
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')
|
||||
->where('accounts.user_id', Auth::user()->id)
|
||||
->first(['piggy_banks.*']);
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -118,9 +131,25 @@ Route::bind(
|
||||
'category', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Category::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
$object = $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'tag', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Tag::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
$object = $object;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -170,7 +199,6 @@ Route::group(
|
||||
Route::get('/bills/add/{bill}', ['uses' => 'BillController@add', 'as' => 'bills.add']);
|
||||
Route::get('/bills/delete/{bill}', ['uses' => 'BillController@delete', 'as' => 'bills.delete']);
|
||||
Route::get('/bills/show/{bill}', ['uses' => 'BillController@show', 'as' => 'bills.show']);
|
||||
|
||||
Route::post('/bills/store', ['uses' => 'BillController@store', 'as' => 'bills.store']);
|
||||
Route::post('/bills/update/{bill}', ['uses' => 'BillController@update', 'as' => 'bills.update']);
|
||||
Route::post('/bills/destroy/{bill}', ['uses' => 'BillController@destroy', 'as' => 'bills.destroy']);
|
||||
@@ -226,7 +254,7 @@ Route::group(
|
||||
Route::get('/chart/home/bills', ['uses' => 'GoogleChartController@billsOverview']);
|
||||
Route::get('/chart/account/{account}/{view?}', ['uses' => 'GoogleChartController@accountBalanceChart']);
|
||||
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'])->where(['year' => '[0-9]+']);
|
||||
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']);
|
||||
Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']);
|
||||
Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']);
|
||||
@@ -246,7 +274,11 @@ Route::group(
|
||||
Route::get('/json/expense-accounts', ['uses' => 'JsonController@expenseAccounts', 'as' => 'json.expense-accounts']);
|
||||
Route::get('/json/revenue-accounts', ['uses' => 'JsonController@revenueAccounts', 'as' => 'json.revenue-accounts']);
|
||||
Route::get('/json/categories', ['uses' => 'JsonController@categories', 'as' => 'json.categories']);
|
||||
Route::get('/json/box', ['uses' => 'JsonController@box', 'as' => 'json.box']);
|
||||
Route::get('/json/tags', ['uses' => 'JsonController@tags', 'as' => 'json.tags']);
|
||||
Route::get('/json/box/in', ['uses' => 'JsonController@boxIn', 'as' => 'json.box.in']);
|
||||
Route::get('/json/box/out', ['uses' => 'JsonController@boxOut', 'as' => 'json.box.out']);
|
||||
Route::get('/json/box/bills-unpaid', ['uses' => 'JsonController@boxBillsUnpaid', 'as' => 'json.box.paid']);
|
||||
Route::get('/json/box/bills-paid', ['uses' => 'JsonController@boxBillsPaid', 'as' => 'json.box.unpaid']);
|
||||
Route::get('/json/show-shared-reports', 'JsonController@showSharedReports');
|
||||
Route::get('/json/transaction-journals/{what}', 'JsonController@transactionJournals');
|
||||
Route::get('/json/show-shared-reports/set', 'JsonController@setSharedReports');
|
||||
@@ -280,18 +312,10 @@ Route::group(
|
||||
*/
|
||||
Route::get('/profile', ['uses' => 'ProfileController@index', 'as' => 'profile']);
|
||||
Route::get('/profile/change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']);
|
||||
Route::get('/profile/delete-account', ['uses' => 'ProfileController@deleteAccount', 'as' => 'delete-account']);
|
||||
Route::post('/profile/delete-account', ['uses' => 'ProfileController@postDeleteAccount', 'as' => 'delete-account-post']);
|
||||
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword', 'as' => 'change-password-post']);
|
||||
|
||||
/**
|
||||
* Related transactions controller
|
||||
*/
|
||||
Route::get('/related/alreadyRelated/{tj}', ['uses' => 'RelatedController@alreadyRelated', 'as' => 'related.alreadyRelated']);
|
||||
Route::post('/related/relate/{tj}/{tjSecond}', ['uses' => 'RelatedController@relate', 'as' => 'related.relate']);
|
||||
Route::post('/related/removeRelation/{tj}/{tjSecond}', ['uses' => 'RelatedController@removeRelation', 'as' => 'related.removeRelation']);
|
||||
Route::get('/related/remove/{tj}/{tjSecond}', ['uses' => 'RelatedController@getRemoveRelation', 'as' => 'related.getRemoveRelation']);
|
||||
Route::get('/related/related/{tj}', ['uses' => 'RelatedController@related', 'as' => 'related.related']);
|
||||
Route::post('/related/search/{tj}', ['uses' => 'RelatedController@search', 'as' => 'related.search']);
|
||||
|
||||
/**
|
||||
* Reminder Controller
|
||||
*/
|
||||
@@ -323,6 +347,22 @@ Route::group(
|
||||
*/
|
||||
Route::get('/search', ['uses' => 'SearchController@index', 'as' => 'search']);
|
||||
|
||||
/**
|
||||
* Tag Controller
|
||||
*/
|
||||
Route::get('/tags', ['uses' => 'TagController@index', 'as' => 'tags.index']);
|
||||
Route::get('/tags/create', ['uses' => 'TagController@create', 'as' => 'tags.create']);
|
||||
Route::get('/tags/show/{tag}', ['uses' => 'TagController@show', 'as' => 'tags.show']);
|
||||
Route::get('/tags/edit/{tag}', ['uses' => 'TagController@edit', 'as' => 'tags.edit']);
|
||||
Route::get('/tags/delete/{tag}', ['uses' => 'TagController@delete', 'as' => 'tags.delete']);
|
||||
|
||||
Route::post('/tags/store', ['uses' => 'TagController@store', 'as' => 'tags.store']);
|
||||
Route::post('/tags/update/{tag}', ['uses' => 'TagController@update', 'as' => 'tags.update']);
|
||||
Route::post('/tags/destroy/{tag}', ['uses' => 'TagController@destroy', 'as' => 'tags.destroy']);
|
||||
|
||||
Route::post('/tags/hideTagHelp/{state}', ['uses' => 'TagController@hideTagHelp', 'as' => 'tags.hideTagHelp']);
|
||||
|
||||
|
||||
/**
|
||||
* Transaction Controller
|
||||
*/
|
||||
|
||||
@@ -51,10 +51,13 @@ class Account extends Model
|
||||
$account = Account::create($fields);
|
||||
if (is_null($account->id)) {
|
||||
// could not create account:
|
||||
App::abort(500, 'Could not create new account with data: ' . json_encode($fields));
|
||||
App::abort(500, 'Could not create new account with data: ' . json_encode($fields).' because ' . json_encode($account->getErrors()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
return $account;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php namespace FireflyIII\Models;
|
||||
|
||||
use Crypt;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Crypt;
|
||||
use App;
|
||||
/**
|
||||
* Class Category
|
||||
*
|
||||
@@ -30,6 +31,39 @@ class Category extends Model
|
||||
return $this->belongsToMany('FireflyIII\Models\TransactionJournal', 'category_transaction_journal', 'category_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fields
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
public static function firstOrCreateEncrypted(array $fields)
|
||||
{
|
||||
// everything but the name:
|
||||
$query = Category::orderBy('id');
|
||||
foreach ($fields as $name => $value) {
|
||||
if ($name != 'name') {
|
||||
$query->where($name, $value);
|
||||
}
|
||||
}
|
||||
$set = $query->get(['categories.*']);
|
||||
/** @var Category $category */
|
||||
foreach ($set as $category) {
|
||||
if ($category->name == $fields['name']) {
|
||||
return $category;
|
||||
}
|
||||
}
|
||||
// create it!
|
||||
$category = Category::create($fields);
|
||||
if (is_null($category->id)) {
|
||||
// could not create account:
|
||||
App::abort(500, 'Could not create new category with data: ' . json_encode($fields));
|
||||
|
||||
}
|
||||
|
||||
return $category;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
@@ -46,6 +80,7 @@ class Category extends Model
|
||||
$this->attributes['name'] = Crypt::encrypt($value);
|
||||
$this->attributes['encrypted'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php namespace FireflyIII\Models;
|
||||
|
||||
use Auth;
|
||||
use DB;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
@@ -26,18 +28,23 @@ class LimitRepetition extends Model
|
||||
return ['created_at', 'updated_at', 'startdate', 'enddate'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function spentInRepetition()
|
||||
{
|
||||
$sum = \DB::table('transactions')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budget_transaction_journal.budget_id')
|
||||
->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('transaction_journals.date', '>=', $this->startdate->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $this->enddate->format('Y-m-d'))
|
||||
->where('transactions.amount', '>', 0)
|
||||
->where('limit_repetitions.id', '=', $this->id)
|
||||
->sum('transactions.amount');
|
||||
$sum = DB::table('transactions')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budget_transaction_journal.budget_id')
|
||||
->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('transaction_journals.date', '>=', $this->startdate->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $this->enddate->format('Y-m-d'))
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->whereNull('transactions.deleted_at')
|
||||
->where('transactions.amount', '>', 0)
|
||||
->where('limit_repetitions.id', '=', $this->id)
|
||||
->sum('transactions.amount');
|
||||
|
||||
return floatval($sum);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php namespace FireflyIII\Models;
|
||||
|
||||
use Crypt;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Crypt;
|
||||
|
||||
/**
|
||||
* Class PiggyBank
|
||||
*
|
||||
@@ -13,7 +14,7 @@ class PiggyBank extends Model
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable
|
||||
= ['name', 'account_id', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder', 'remind_me'];
|
||||
= ['name', 'account_id','order', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder', 'remind_me'];
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
@@ -92,6 +93,7 @@ class PiggyBank extends Model
|
||||
$this->attributes['name'] = Crypt::encrypt($value);
|
||||
$this->attributes['encrypted'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Crypt;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Crypt;
|
||||
|
||||
/**
|
||||
* Class Reminder
|
||||
*
|
||||
@@ -43,6 +44,7 @@ class Reminder extends Model
|
||||
if (intval($this->encrypted) == 1) {
|
||||
return json_decode(Crypt::decrypt($value));
|
||||
}
|
||||
|
||||
return json_decode($value);
|
||||
}
|
||||
|
||||
@@ -90,7 +92,7 @@ class Reminder extends Model
|
||||
public function setMetadataAttribute($value)
|
||||
{
|
||||
$this->attributes['encrypted'] = true;
|
||||
$this->attributes['metadata'] = Crypt::encrypt(json_encode($value));
|
||||
$this->attributes['metadata'] = Crypt::encrypt(json_encode($value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
128
app/Models/Tag.php
Normal file
128
app/Models/Tag.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use App;
|
||||
use Crypt;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
/**
|
||||
* Class Tag
|
||||
*
|
||||
* @package FireflyIII\Models
|
||||
*/
|
||||
class Tag extends Model
|
||||
{
|
||||
use ValidatingTrait;
|
||||
|
||||
protected $fillable = ['user_id', 'tag', 'date', 'description', 'longitude', 'latitude', 'zoomLevel', 'tagMode'];
|
||||
protected $rules
|
||||
= [
|
||||
'tag' => 'required|min:1|uniqueObjectForUser:tags,tag,TRUE',
|
||||
'description' => 'min:1',
|
||||
'date' => 'date',
|
||||
'latitude' => 'numeric|min:-90|max:90',
|
||||
'longitude' => 'numeric|min:-90|max:90',
|
||||
'tagMode' => 'required|in:nothing,balancingAct,advancePayment'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array $fields
|
||||
*
|
||||
* @return Tag|null
|
||||
*/
|
||||
public static function firstOrCreateEncrypted(array $fields)
|
||||
{
|
||||
// everything but the tag:
|
||||
if (isset($fields['tagMode'])) {
|
||||
unset($fields['tagMode']);
|
||||
}
|
||||
$query = Tag::orderBy('id');
|
||||
foreach ($fields as $name => $value) {
|
||||
if ($name != 'tag') {
|
||||
$query->where($name, $value);
|
||||
}
|
||||
}
|
||||
$set = $query->get(['tags.*']);
|
||||
/** @var Tag $tag */
|
||||
foreach ($set as $tag) {
|
||||
if ($tag->tag == $fields['tag']) {
|
||||
return $tag;
|
||||
}
|
||||
}
|
||||
// create it!
|
||||
$fields['tagMode'] = 'nothing';
|
||||
$fields['description'] = isset($fields['description']) && !is_null($fields['description']) ? $fields['description'] : '';
|
||||
$tag = Tag::create($fields);
|
||||
if (is_null($tag->id)) {
|
||||
// could not create account:
|
||||
App::abort(500, 'Could not create new tag with data: ' . json_encode($fields) . ' because ' . json_encode($tag->getErrors()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
return $tag;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getDates()
|
||||
{
|
||||
return ['created_at', 'updated_at', 'date'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescriptionAttribute($value)
|
||||
{
|
||||
return Crypt::decrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTagAttribute($value)
|
||||
{
|
||||
return Crypt::decrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*/
|
||||
public function setDescriptionAttribute($value)
|
||||
{
|
||||
$this->attributes['description'] = Crypt::encrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*/
|
||||
public function setTagAttribute($value)
|
||||
{
|
||||
$this->attributes['tag'] = Crypt::encrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function transactionjournals()
|
||||
{
|
||||
return $this->belongsToMany('FireflyIII\Models\TransactionJournal');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('FireflyIII\User');
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
<?php namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Class Transaction
|
||||
*
|
||||
|
||||
@@ -55,6 +55,47 @@ class TransactionJournal extends Model
|
||||
return $this->belongsToMany('FireflyIII\Models\Category');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getAmountAttribute()
|
||||
{
|
||||
/** @var Transaction $t */
|
||||
foreach ($this->transactions as $t) {
|
||||
if ($t->amount > 0) {
|
||||
return floatval($t->amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getAssetAccountAttribute()
|
||||
{
|
||||
$positive = true; // the asset account is in the transaction with the positive amount.
|
||||
if ($this->transactionType->type === 'Withdrawal') {
|
||||
$positive = false;
|
||||
}
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($this->transactions()->get() as $transaction) {
|
||||
if (floatval($transaction->amount) > 0 && $positive === true) {
|
||||
return $transaction->account;
|
||||
}
|
||||
if (floatval($transaction->amount) < 0 && $positive === false) {
|
||||
return $transaction->account;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->transactions()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function transactions()
|
||||
{
|
||||
return $this->hasMany('FireflyIII\Models\Transaction');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
@@ -188,6 +229,14 @@ class TransactionJournal extends Model
|
||||
$this->attributes['encrypted'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function tags()
|
||||
{
|
||||
return $this->belongsToMany('FireflyIII\Models\Tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
@@ -212,14 +261,6 @@ class TransactionJournal extends Model
|
||||
return $this->belongsToMany('FireflyIII\Models\TransactionGroup');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function transactions()
|
||||
{
|
||||
return $this->hasMany('FireflyIII\Models\Transaction');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
|
||||
@@ -35,6 +35,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
'Illuminate\Contracts\Auth\Registrar',
|
||||
'FireflyIII\Services\Registrar'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,227 @@ class ConfigServiceProvider extends ServiceProvider
|
||||
{
|
||||
config(
|
||||
[
|
||||
//
|
||||
'twigbridge' => [
|
||||
|
||||
'twig' => [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Extension
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| File extension for Twig view files.
|
||||
|
|
||||
*/
|
||||
'extension' => 'twig',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Accepts all Twig environment configuration options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| http://twig.sensiolabs.org/doc/api.html#environment-options
|
||||
|
|
||||
*/
|
||||
'environment' => [
|
||||
|
||||
// When set to true, the generated templates have a __toString() method
|
||||
// that you can use to display the generated nodes.
|
||||
// default: false
|
||||
'debug' => config('app.debug', false),
|
||||
|
||||
// The charset used by the templates.
|
||||
// default: utf-8
|
||||
'charset' => 'utf-8',
|
||||
|
||||
// The base template class to use for generated templates.
|
||||
// default: TwigBridge\Twig\Template
|
||||
'base_template_class' => 'TwigBridge\Twig\Template',
|
||||
|
||||
// An absolute path where to store the compiled templates, or false to disable caching. If null
|
||||
// then the cache file path is used.
|
||||
// default: cache file storage path
|
||||
'cache' => null,
|
||||
|
||||
// When developing with Twig, it's useful to recompile the template
|
||||
// whenever the source code changes. If you don't provide a value
|
||||
// for the auto_reload option, it will be determined automatically based on the debug value.
|
||||
'auto_reload' => true,
|
||||
|
||||
// If set to false, Twig will silently ignore invalid variables
|
||||
// (variables and or attributes/methods that do not exist) and
|
||||
// replace them with a null value. When set to true, Twig throws an exception instead.
|
||||
// default: false
|
||||
'strict_variables' => false,
|
||||
|
||||
// If set to true, auto-escaping will be enabled by default for all templates.
|
||||
// default: true
|
||||
'autoescape' => true,
|
||||
|
||||
// A flag that indicates which optimizations to apply
|
||||
// (default to -1 -- all optimizations are enabled; set it to 0 to disable)
|
||||
'optimizations' => -1,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global variables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These will always be passed in and can be accessed as Twig variables.
|
||||
| NOTE: these will be overwritten if you pass data into the view with the same key.
|
||||
|
|
||||
*/
|
||||
'globals' => [],
|
||||
],
|
||||
|
||||
'extensions' => [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Extensions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enabled extensions.
|
||||
|
|
||||
| `Twig_Extension_Debug` is enabled automatically if twig.debug is TRUE.
|
||||
|
|
||||
*/
|
||||
'enabled' => [
|
||||
'TwigBridge\Extension\Loader\Facades',
|
||||
'TwigBridge\Extension\Loader\Filters',
|
||||
'TwigBridge\Extension\Loader\Functions',
|
||||
|
||||
'TwigBridge\Extension\Laravel\Auth',
|
||||
'TwigBridge\Extension\Laravel\Config',
|
||||
'TwigBridge\Extension\Laravel\Dump',
|
||||
'TwigBridge\Extension\Laravel\Input',
|
||||
'TwigBridge\Extension\Laravel\Session',
|
||||
'TwigBridge\Extension\Laravel\String',
|
||||
'TwigBridge\Extension\Laravel\Translator',
|
||||
'TwigBridge\Extension\Laravel\Url',
|
||||
|
||||
// 'TwigBridge\Extension\Laravel\Form',
|
||||
// 'TwigBridge\Extension\Laravel\Html',
|
||||
// 'TwigBridge\Extension\Laravel\Legacy\Facades',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Facades
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Available facades. Access like `{{ Config.get('foo.bar') }}`.
|
||||
|
|
||||
| Each facade can take an optional array of options. To mark the whole facade
|
||||
| as safe you can set the option `'is_safe' => true`. Setting the facade as
|
||||
| safe means that any HTML returned will not be escaped.
|
||||
|
|
||||
| It is advisable to not set the whole facade as safe and instead mark the
|
||||
| each appropriate method as safe for security reasons. You can do that with
|
||||
| the following syntax:
|
||||
|
|
||||
| <code>
|
||||
| 'Form' => [
|
||||
| 'is_safe' => [
|
||||
| 'open'
|
||||
| ]
|
||||
| ]
|
||||
| </code>
|
||||
|
|
||||
| The values of the `is_safe` array must match the called method on the facade
|
||||
| in order to be marked as safe.
|
||||
|
|
||||
*/
|
||||
'facades' => [
|
||||
'Breadcrumbs' => [
|
||||
'is_safe' => [
|
||||
'renderIfExists'
|
||||
]
|
||||
],
|
||||
'Session',
|
||||
'Route',
|
||||
'Auth',
|
||||
'URL',
|
||||
'Config',
|
||||
'ExpandedForm' => [
|
||||
'is_safe' => [
|
||||
'date', 'text', 'select', 'balance', 'optionsList', 'checkbox', 'amount', 'tags', 'integer', 'textarea', 'location',
|
||||
'multiRadio'
|
||||
]
|
||||
],
|
||||
'Form' => [
|
||||
'is_safe' => [
|
||||
'input', 'select', 'checkbox', 'model', 'open','radio','textarea'
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Functions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Available functions. Access like `{{ secure_url(...) }}`.
|
||||
|
|
||||
| Each function can take an optional array of options. These options are
|
||||
| passed directly to `Twig_SimpleFunction`.
|
||||
|
|
||||
| So for example, to mark a function as safe you can do the following:
|
||||
|
|
||||
| <code>
|
||||
| 'link_to' => [
|
||||
| 'is_safe' => ['html']
|
||||
| ]
|
||||
| </code>
|
||||
|
|
||||
| The options array also takes a `callback` that allows you to name the
|
||||
| function differently in your Twig templates than what it's actually called.
|
||||
|
|
||||
| <code>
|
||||
| 'link' => [
|
||||
| 'callback' => 'link_to'
|
||||
| ]
|
||||
| </code>
|
||||
|
|
||||
*/
|
||||
'functions' => [
|
||||
'elixir',
|
||||
'head',
|
||||
'last',
|
||||
'old'
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Filters
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Available filters. Access like `{{ variable|filter }}`.
|
||||
|
|
||||
| Each filter can take an optional array of options. These options are
|
||||
| passed directly to `Twig_SimpleFilter`.
|
||||
|
|
||||
| So for example, to mark a filter as safe you can do the following:
|
||||
|
|
||||
| <code>
|
||||
| 'studly_case' => [
|
||||
| 'is_safe' => ['html']
|
||||
| ]
|
||||
| </code>
|
||||
|
|
||||
| The options array also takes a `callback` that allows you to name the
|
||||
| filter differently in your Twig templates than what is actually called.
|
||||
|
|
||||
| <code>
|
||||
| 'snake' => [
|
||||
| 'callback' => 'snake_case'
|
||||
| ]
|
||||
| </code>
|
||||
|
|
||||
*/
|
||||
'filters' => [],
|
||||
],
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php namespace FireflyIII\Providers;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
@@ -12,7 +13,8 @@ use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
use Log;
|
||||
use Reminder;
|
||||
use FireflyIII\Models\Reminder;
|
||||
|
||||
/**
|
||||
* Class EventServiceProvider
|
||||
*
|
||||
@@ -60,14 +62,15 @@ class EventServiceProvider extends ServiceProvider
|
||||
);
|
||||
|
||||
|
||||
PiggyBank::deleting(function(PiggyBank $piggyBank) {
|
||||
$reminders = $piggyBank->reminders()->get();
|
||||
/** @var Reminder $reminder */
|
||||
foreach($reminders as $reminder) {
|
||||
$reminder->delete();
|
||||
PiggyBank::deleting(
|
||||
function (PiggyBank $piggyBank) {
|
||||
$reminders = $piggyBank->reminders()->get();
|
||||
/** @var Reminder $reminder */
|
||||
foreach ($reminders as $reminder) {
|
||||
$reminder->delete();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
);
|
||||
|
||||
Account::deleted(
|
||||
function (Account $account) {
|
||||
|
||||
@@ -2,13 +2,21 @@
|
||||
|
||||
namespace FireflyIII\Providers;
|
||||
|
||||
use App;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Support\Amount;
|
||||
use FireflyIII\Support\ExpandedForm;
|
||||
use FireflyIII\Support\Navigation;
|
||||
use FireflyIII\Support\Preferences;
|
||||
use FireflyIII\Support\Steam;
|
||||
use FireflyIII\Support\Twig\Budget;
|
||||
use FireflyIII\Support\Twig\General;
|
||||
use FireflyIII\Support\Twig\Journal;
|
||||
use FireflyIII\Support\Twig\PiggyBank;
|
||||
use FireflyIII\Validation\FireflyValidator;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Twig;
|
||||
use TwigBridge\Extension\Loader\Functions;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
@@ -25,10 +33,22 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
return new FireflyValidator($translator, $data, $rules, $messages);
|
||||
}
|
||||
);
|
||||
/*
|
||||
* Default Twig configuration:
|
||||
*/
|
||||
|
||||
$config = App::make('config');
|
||||
Twig::addExtension(new Functions($config));
|
||||
Twig::addExtension(new PiggyBank);
|
||||
Twig::addExtension(new General);
|
||||
Twig::addExtension(new Journal);
|
||||
Twig::addExtension(new Budget);
|
||||
}
|
||||
|
||||
public function register()
|
||||
{
|
||||
|
||||
|
||||
$this->app->bind(
|
||||
'preferences', function () {
|
||||
return new Preferences;
|
||||
@@ -62,13 +82,17 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
$this->app->bind('FireflyIII\Repositories\Journal\JournalRepositoryInterface', 'FireflyIII\Repositories\Journal\JournalRepository');
|
||||
$this->app->bind('FireflyIII\Repositories\Bill\BillRepositoryInterface', 'FireflyIII\Repositories\Bill\BillRepository');
|
||||
$this->app->bind('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface', 'FireflyIII\Repositories\PiggyBank\PiggyBankRepository');
|
||||
$this->app->bind('FireflyIII\Repositories\Currency\CurrencyRepositoryInterface', 'FireflyIII\Repositories\Currency\CurrencyRepository');
|
||||
$this->app->bind('FireflyIII\Repositories\Tag\TagRepositoryInterface', 'FireflyIII\Repositories\Tag\TagRepository');
|
||||
$this->app->bind('FireflyIII\Support\Search\SearchInterface', 'FireflyIII\Support\Search\Search');
|
||||
|
||||
|
||||
$this->app->bind('FireflyIII\Helpers\Help\HelpInterface', 'FireflyIII\Helpers\Help\Help');
|
||||
$this->app->bind('FireflyIII\Helpers\Reminders\ReminderHelperInterface', 'FireflyIII\Helpers\Reminders\ReminderHelper');
|
||||
$this->app->bind('FireflyIII\Helpers\Report\ReportHelperInterface', 'FireflyIII\Helpers\Report\ReportHelper');
|
||||
$this->app->bind('FireflyIII\Helpers\Report\ReportQueryInterface', 'FireflyIII\Helpers\Report\ReportQuery');
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use App;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use DB;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AccountType;
|
||||
@@ -14,6 +15,7 @@ use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
@@ -29,11 +31,13 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countAssetAccounts()
|
||||
public function countAccounts(array $types)
|
||||
{
|
||||
return Auth::user()->accounts()->accountTypeIn(['Asset account', 'Default account'])->count();
|
||||
return Auth::user()->accounts()->accountTypeIn($types)->count();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,6 +52,40 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAccounts(array $types)
|
||||
{
|
||||
$result = Auth::user()->accounts()->with(
|
||||
['accountmeta' => function (HasMany $query) {
|
||||
$query->where('name', 'accountRole');
|
||||
}]
|
||||
)->accountTypeIn($types)->orderBy('accounts.name', 'ASC')->get(['accounts.*'])->sortBy('name');
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCreditCards()
|
||||
{
|
||||
return Auth::user()->accounts()
|
||||
->hasMetaValue('accountRole', 'ccAsset')
|
||||
->hasMetaValue('ccType', 'monthlyFull')
|
||||
->get(
|
||||
[
|
||||
'accounts.*',
|
||||
'ccType.data as ccType',
|
||||
'accountRole.data as accountRole'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Account $account
|
||||
@@ -108,7 +146,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
* @param Account $account
|
||||
* @param int $page
|
||||
*
|
||||
* @return mixed
|
||||
* @return LengthAwarePaginator
|
||||
*/
|
||||
public function getJournals(Account $account, $page)
|
||||
{
|
||||
@@ -133,6 +171,68 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function getLastActivity(Account $account)
|
||||
{
|
||||
$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) {
|
||||
return $lastTransaction->transactionjournal->date;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the accounts of a user that have piggy banks connected to them.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPiggyBankAccounts()
|
||||
{
|
||||
$ids = [];
|
||||
$start = clone Session::get('start', new Carbon);
|
||||
$end = clone Session::get('end', new Carbon);
|
||||
$accountIds = DB::table('piggy_banks')->distinct()->get(['piggy_banks.account_id']);
|
||||
$accounts = new Collection;
|
||||
|
||||
foreach ($accountIds as $id) {
|
||||
$ids[] = intval($id->account_id);
|
||||
}
|
||||
|
||||
$ids = array_unique($ids);
|
||||
if (count($ids) > 0) {
|
||||
$accounts = Auth::user()->accounts()->whereIn('id', $ids)->get();
|
||||
}
|
||||
|
||||
$accounts->each(
|
||||
function (Account $account) use ($start, $end) {
|
||||
$account->startBalance = Steam::balance($account, $start, true);
|
||||
$account->endBalance = Steam::balance($account, $end, true);
|
||||
$account->piggyBalance = 0;
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($account->piggyBanks as $piggyBank) {
|
||||
$account->piggyBalance += $piggyBank->currentRelevantRep()->currentamount;
|
||||
}
|
||||
// sum of piggy bank amounts on this account:
|
||||
// diff between endBalance and piggyBalance.
|
||||
// then, percentage.
|
||||
$difference = $account->endBalance - $account->piggyBalance;
|
||||
$account->difference = $difference;
|
||||
$account->percentage = $difference != 0 ? round((($difference / $account->endBalance) * 100)) : 100;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
return $accounts;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get savings accounts and the balance difference in the period.
|
||||
*
|
||||
@@ -175,6 +275,34 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
return $accounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all transfers TO this account in this range.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getTransfersInRange(Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
return TransactionJournal::whereIn(
|
||||
'id', function ($q) use ($account, $start, $end) {
|
||||
$q->select('transaction_journals.id')
|
||||
->from('transactions')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->where('transactions.account_id', $account->id)
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->where('transactions.amount', '>', 0)
|
||||
->where('transaction_types.type', 'Transfer');
|
||||
|
||||
}
|
||||
)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
@@ -235,6 +363,14 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function sumOfEverything()
|
||||
{
|
||||
return floatval(Auth::user()->transactions()->sum('amount'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $data
|
||||
@@ -417,7 +553,6 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
protected function updateMetadata(Account $account, array $data)
|
||||
{
|
||||
$validFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType'];
|
||||
$updated = false;
|
||||
|
||||
foreach ($validFields as $field) {
|
||||
$entry = $account->accountMeta()->where('name', $field)->first();
|
||||
|
||||
@@ -7,6 +7,7 @@ use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
@@ -16,6 +17,13 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface AccountRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countAccounts(array $types);
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
@@ -24,9 +32,43 @@ interface AccountRepositoryInterface
|
||||
public function destroy(Account $account);
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @param array $types
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function countAssetAccounts();
|
||||
public function getAccounts(array $types);
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Account $account
|
||||
*
|
||||
* @return Transaction
|
||||
*/
|
||||
public function getFirstTransaction(TransactionJournal $journal, Account $account);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCreditCards();
|
||||
|
||||
/**
|
||||
* Get the accounts of a user that have piggy banks connected to them.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPiggyBankAccounts();
|
||||
|
||||
|
||||
/**
|
||||
* Get all transfers TO this account in this range.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getTransfersInRange(Account $account, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Preference $preference
|
||||
@@ -48,10 +90,36 @@ interface AccountRepositoryInterface
|
||||
* @param Account $account
|
||||
* @param string $range
|
||||
*
|
||||
* @return mixed
|
||||
* @return LengthAwarePaginator
|
||||
*/
|
||||
public function getJournals(Account $account, $page);
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function getLastActivity(Account $account);
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function sumOfEverything();
|
||||
|
||||
/**
|
||||
* Get savings accounts and the balance difference in the period.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getSavingsAccounts();
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function leftOnAccount(Account $account);
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
@@ -73,27 +141,4 @@ interface AccountRepositoryInterface
|
||||
* @return Account
|
||||
*/
|
||||
public function update(Account $account, array $data);
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function leftOnAccount(Account $account);
|
||||
|
||||
/**
|
||||
* Get savings accounts and the balance difference in the period.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getSavingsAccounts();
|
||||
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Account $account
|
||||
*
|
||||
* @return Transaction
|
||||
*/
|
||||
public function getFirstTransaction(TransactionJournal $journal, Account $account);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
|
||||
namespace FireflyIII\Repositories\Bill;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Navigation;
|
||||
|
||||
@@ -15,6 +21,121 @@ use Navigation;
|
||||
*/
|
||||
class BillRepository implements BillRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Create a fake bill to help the chart controller.
|
||||
*
|
||||
* @param string $description
|
||||
* @param Carbon $date
|
||||
* @param float $amount
|
||||
*
|
||||
* @return Bill
|
||||
*/
|
||||
public function createFakeBill($description, Carbon $date, $amount)
|
||||
{
|
||||
$bill = new Bill;
|
||||
$bill->name = $description;
|
||||
$bill->match = $description;
|
||||
$bill->amount_min = $amount;
|
||||
$bill->amount_max = $amount;
|
||||
$bill->date = $date;
|
||||
$bill->repeat_freq = 'monthly';
|
||||
$bill->skip = 0;
|
||||
$bill->automatch = false;
|
||||
$bill->active = false;
|
||||
|
||||
return $bill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function destroy(Bill $bill)
|
||||
{
|
||||
return $bill->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActiveBills()
|
||||
{
|
||||
/** @var Collection $set */
|
||||
$set = Auth::user()->bills()->orderBy('name', 'ASC')->where('active', 1)->get()->sortBy('name');
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBills()
|
||||
{
|
||||
/** @var Collection $set */
|
||||
$set = Auth::user()->bills()->orderBy('name', 'ASC')->get()->sortBy('name');
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournals(Bill $bill)
|
||||
{
|
||||
return $bill->transactionjournals()->withRelevantData()
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transactions.amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->get(['transaction_journals.*', 'transactions.amount']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all journals that were recorded on this bill between these dates.
|
||||
*
|
||||
* @param Bill $bill
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournalsInRange(Bill $bill, Carbon $start, Carbon $end)
|
||||
{
|
||||
return $bill->transactionjournals()->before($end)->after($start)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPossiblyRelatedJournals(Bill $bill)
|
||||
{
|
||||
$set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)->get(
|
||||
['transaction_journal_id']
|
||||
);
|
||||
$ids = [];
|
||||
|
||||
/** @var Transaction $entry */
|
||||
foreach ($set as $entry) {
|
||||
$ids[] = intval($entry->transaction_journal_id);
|
||||
}
|
||||
$journals = new Collection;
|
||||
if (count($ids) > 0) {
|
||||
$journals = Auth::user()->transactionjournals()->whereIn('id', $ids)->get();
|
||||
}
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -58,6 +179,21 @@ class BillRepository implements BillRepositoryInterface
|
||||
return $validRanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function lastFoundMatch(Bill $bill)
|
||||
{
|
||||
$last = $bill->transactionjournals()->orderBy('date', 'DESC')->first();
|
||||
if ($last) {
|
||||
return $last->date;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
@@ -179,6 +315,12 @@ class BillRepository implements BillRepositoryInterface
|
||||
Log::debug('TOTAL match is true!');
|
||||
$journal->bill()->associate($bill);
|
||||
$journal->save();
|
||||
} else {
|
||||
if ((!$wordMatch || !$amountMatch) && $bill->id == $journal->bill_id) {
|
||||
// if no match, but bill used to match, remove it:
|
||||
$journal->bill_id = null;
|
||||
$journal->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace FireflyIII\Repositories\Bill;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface BillRepositoryInterface
|
||||
@@ -14,12 +15,58 @@ use FireflyIII\Models\TransactionJournal;
|
||||
interface BillRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a fake bill to help the chart controller.
|
||||
*
|
||||
* @param string $description
|
||||
* @param Carbon $date
|
||||
* @param float $amount
|
||||
*
|
||||
* @return Bill
|
||||
*/
|
||||
public function createFakeBill($description, Carbon $date, $amount);
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Carbon|null
|
||||
* @return mixed
|
||||
*/
|
||||
public function nextExpectedMatch(Bill $bill);
|
||||
public function destroy(Bill $bill);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActiveBills();
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBills();
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournals(Bill $bill);
|
||||
|
||||
/**
|
||||
* Get all journals that were recorded on this bill between these dates.
|
||||
*
|
||||
* @param Bill $bill
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournalsInRange(Bill $bill, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPossiblyRelatedJournals(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)
|
||||
@@ -34,6 +81,29 @@ interface BillRepositoryInterface
|
||||
*/
|
||||
public function getRanges(Bill $bill, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function lastFoundMatch(Bill $bill);
|
||||
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function nextExpectedMatch(Bill $bill);
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function scan(Bill $bill, TransactionJournal $journal);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
@@ -49,12 +119,4 @@ interface BillRepositoryInterface
|
||||
*/
|
||||
public function update(Bill $bill, array $data);
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function scan(Bill $bill, TransactionJournal $journal);
|
||||
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
|
||||
namespace FireflyIII\Repositories\Budget;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class BudgetRepository
|
||||
@@ -37,7 +40,7 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
}
|
||||
|
||||
// delete limits with amount 0:
|
||||
BudgetLimit::where('amount',0)->delete();
|
||||
BudgetLimit::where('amount', 0)->delete();
|
||||
|
||||
}
|
||||
|
||||
@@ -53,6 +56,101 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function expensesOnDay(Budget $budget, Carbon $date)
|
||||
{
|
||||
return floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($date)->sum('amount'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActiveBudgets()
|
||||
{
|
||||
$budgets = Auth::user()->budgets()->where('active', 1)->get();
|
||||
$budgets->sortBy('name');
|
||||
|
||||
return $budgets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgetLimitRepetitions(Budget $budget, Carbon $start, Carbon $end)
|
||||
{
|
||||
/** @var Collection $repetitions */
|
||||
return LimitRepetition::
|
||||
leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00'))
|
||||
->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.budget_id', $budget->id)
|
||||
->get(['limit_repetitions.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgetLimits(Budget $budget)
|
||||
{
|
||||
return $budget->budgetLimits()->orderBy('startdate', 'DESC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgets()
|
||||
{
|
||||
$budgets = Auth::user()->budgets()->get();
|
||||
$budgets->sortBy('name');
|
||||
|
||||
return $budgets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return LimitRepetition|null
|
||||
*/
|
||||
public function getCurrentRepetition(Budget $budget, Carbon $date)
|
||||
{
|
||||
return $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getFirstBudgetLimitDate(Budget $budget)
|
||||
{
|
||||
$limit = $budget->budgetlimits()->orderBy('startdate', 'ASC')->first();
|
||||
if ($limit) {
|
||||
return $limit->startdate;
|
||||
}
|
||||
|
||||
return Carbon::now()->startOfYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getInactiveBudgets()
|
||||
{
|
||||
return Auth::user()->budgets()->where('active', 0)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the transaction journals for a limit, possibly limited by a limit repetition.
|
||||
*
|
||||
@@ -86,6 +184,91 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
return new LengthAwarePaginator($set, $count, $take, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getLastBudgetLimitDate(Budget $budget)
|
||||
{
|
||||
$limit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first();
|
||||
if ($limit) {
|
||||
return $limit->startdate;
|
||||
}
|
||||
|
||||
return Carbon::now()->startOfYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float|null
|
||||
*/
|
||||
public function getLimitAmountOnDate(Budget $budget, Carbon $date)
|
||||
{
|
||||
$repetition = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('limit_repetitions.startdate', $date->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.budget_id', $budget->id)
|
||||
->first(['limit_repetitions.*']);
|
||||
|
||||
if ($repetition) {
|
||||
return floatval($repetition->amount);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getWithoutBudget(Carbon $start, Carbon $end)
|
||||
{
|
||||
return Auth::user()
|
||||
->transactionjournals()
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->whereNull('budget_transaction_journal.id')
|
||||
->before($end)
|
||||
->after($start)
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->get(['transaction_journals.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getWithoutBudgetSum(Carbon $start, Carbon $end)
|
||||
{
|
||||
$noBudgetSet = Auth::user()
|
||||
->transactionjournals()
|
||||
->whereNotIn(
|
||||
'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) {
|
||||
$query
|
||||
->select('transaction_journals.id')
|
||||
->from('transaction_journals')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'))
|
||||
->whereNotNull('budget_transaction_journal.budget_id');
|
||||
}
|
||||
)
|
||||
->before($end)
|
||||
->after($start)
|
||||
->lessThan(0)
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->get();
|
||||
|
||||
return floatval($noBudgetSet->sum('amount')) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
@@ -120,6 +303,18 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
return $newBudget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function sumBudgetExpensesInPeriod(Budget $budget, $start, $end)
|
||||
{
|
||||
return floatval($budget->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $data
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace FireflyIII\Repositories\Budget;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface BudgetRepositoryInterface
|
||||
@@ -13,6 +14,11 @@ use FireflyIII\Models\LimitRepetition;
|
||||
*/
|
||||
interface BudgetRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function cleanupBudgets();
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
@@ -20,42 +26,59 @@ interface BudgetRepositoryInterface
|
||||
*/
|
||||
public function destroy(Budget $budget);
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function cleanupBudgets();
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInMonth(Budget $budget, Carbon $date);
|
||||
public function expensesOnDay(Budget $budget, Carbon $date);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActiveBudgets();
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgetLimitRepetitions(Budget $budget, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgetLimits(Budget $budget);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgets();
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
* @param $amount
|
||||
*
|
||||
* @return mixed
|
||||
* @return LimitRepetition|null
|
||||
*/
|
||||
public function updateLimitAmount(Budget $budget, Carbon $date, $amount);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
*/
|
||||
public function store(array $data);
|
||||
public function getCurrentRepetition(Budget $budget, Carbon $date);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
* @return Carbon
|
||||
*/
|
||||
public function update(Budget $budget, array $data);
|
||||
public function getFirstBudgetLimitDate(Budget $budget);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getInactiveBudgets();
|
||||
|
||||
/**
|
||||
* Returns all the transaction journals for a limit, possibly limited by a limit repetition.
|
||||
@@ -68,4 +91,76 @@ interface BudgetRepositoryInterface
|
||||
*/
|
||||
public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getLastBudgetLimitDate(Budget $budget);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getLimitAmountOnDate(Budget $budget, Carbon $date);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getWithoutBudget(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getWithoutBudgetSum(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInMonth(Budget $budget, Carbon $date);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
*/
|
||||
public function store(array $data);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function sumBudgetExpensesInPeriod(Budget $budget, $start, $end);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
*/
|
||||
public function update(Budget $budget, array $data);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
* @param $amount
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateLimitAmount(Budget $budget, Carbon $date, $amount);
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
|
||||
namespace FireflyIII\Repositories\Category;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class CategoryRepository
|
||||
@@ -12,6 +18,17 @@ use FireflyIII\Models\Category;
|
||||
class CategoryRepository implements CategoryRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countJournals(Category $category)
|
||||
{
|
||||
return $category->transactionJournals()->count();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
@@ -24,6 +41,150 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCategories()
|
||||
{
|
||||
/** @var Collection $set */
|
||||
$set = Auth::user()->categories()->orderBy('name', 'ASC')->get();
|
||||
$set->sortBy(
|
||||
function (Category $category) {
|
||||
return $category->name;
|
||||
}
|
||||
);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCategoriesAndExpenses($start, $end)
|
||||
{
|
||||
return TransactionJournal::
|
||||
where('transaction_journals.user_id', Auth::user()->id)
|
||||
->leftJoin(
|
||||
'transactions',
|
||||
function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
|
||||
)
|
||||
->leftJoin('categories', 'categories.id', '=', 'category_transaction_journal.category_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->before($end)
|
||||
->where('categories.user_id', Auth::user()->id)
|
||||
->after($start)
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->groupBy('categories.id')
|
||||
->orderBy('sum', 'DESC')
|
||||
->get(['categories.id', 'categories.encrypted', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getFirstActivityDate(Category $category)
|
||||
{
|
||||
/** @var TransactionJournal $first */
|
||||
$first = $category->transactionjournals()->orderBy('date', 'ASC')->first();
|
||||
if ($first) {
|
||||
return $first->date;
|
||||
}
|
||||
|
||||
return new Carbon;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param int $page
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournals(Category $category, $page)
|
||||
{
|
||||
$offset = $page > 0 ? $page * 50 : 0;
|
||||
|
||||
return $category->transactionJournals()->withRelevantData()->take(50)->offset($offset)
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->get(
|
||||
['transaction_journals.*']
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function getLatestActivity(Category $category)
|
||||
{
|
||||
$latest = $category->transactionjournals()
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->first();
|
||||
if ($latest) {
|
||||
return $latest->date;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getWithoutCategory(Carbon $start, Carbon $end)
|
||||
{
|
||||
return 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', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->get(['transaction_journals.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInPeriodSum(Category $category, Carbon $start, Carbon $end)
|
||||
{
|
||||
return floatval($category->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentOnDaySum(Category $category, Carbon $date)
|
||||
{
|
||||
return floatval($category->transactionjournals()->onDate($date)->lessThan(0)->sum('amount')) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
@@ -57,5 +218,4 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
|
||||
return $category;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace FireflyIII\Repositories\Category;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Category;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface CategoryRepositoryInterface
|
||||
@@ -11,6 +13,13 @@ use FireflyIII\Models\Category;
|
||||
*/
|
||||
interface CategoryRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countJournals(Category $category);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
@@ -18,6 +27,66 @@ interface CategoryRepositoryInterface
|
||||
*/
|
||||
public function destroy(Category $category);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCategories();
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCategoriesAndExpenses($start, $end);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getFirstActivityDate(Category $category);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param int $page
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournals(Category $category, $page);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function getLatestActivity(Category $category);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getWithoutCategory(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInPeriodSum(Category $category, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentOnDaySum(Category $category, Carbon $date);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
|
||||
84
app/Repositories/Currency/CurrencyRepository.php
Normal file
84
app/Repositories/Currency/CurrencyRepository.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Repositories\Currency;
|
||||
|
||||
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class CurrencyRepository
|
||||
*
|
||||
* @package FireflyIII\Repositories\Currency
|
||||
*/
|
||||
class CurrencyRepository implements CurrencyRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countJournals(TransactionCurrency $currency)
|
||||
{
|
||||
return $currency->transactionJournals()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return TransactionCurrency::get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Preference $preference
|
||||
*
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function getCurrencyByPreference(Preference $preference)
|
||||
{
|
||||
$preferred = TransactionCurrency::whereCode($preference->data)->first();
|
||||
if (is_null($preferred)) {
|
||||
$preferred = TransactionCurrency::first();
|
||||
}
|
||||
|
||||
return $preferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
$currency = TransactionCurrency::create(
|
||||
[
|
||||
'name' => $data['name'],
|
||||
'code' => $data['code'],
|
||||
'symbol' => $data['symbol'],
|
||||
]
|
||||
);
|
||||
|
||||
return $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function update(TransactionCurrency $currency, array $data)
|
||||
{
|
||||
$currency->code = $data['code'];
|
||||
$currency->symbol = $data['symbol'];
|
||||
$currency->name = $data['name'];
|
||||
$currency->save();
|
||||
|
||||
return $currency;
|
||||
}
|
||||
}
|
||||
52
app/Repositories/Currency/CurrencyRepositoryInterface.php
Normal file
52
app/Repositories/Currency/CurrencyRepositoryInterface.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Repositories\Currency;
|
||||
|
||||
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface CurrencyRepositoryInterface
|
||||
*
|
||||
* @package FireflyIII\Repositories\Currency
|
||||
*/
|
||||
interface CurrencyRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countJournals(TransactionCurrency $currency);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get();
|
||||
|
||||
/**
|
||||
* @param Preference $preference
|
||||
*
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function getCurrencyByPreference(Preference $preference);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function store(array $data);
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function update(TransactionCurrency $currency, array $data);
|
||||
|
||||
}
|
||||
@@ -4,10 +4,12 @@ namespace FireflyIII\Repositories\Journal;
|
||||
|
||||
use App;
|
||||
use Auth;
|
||||
use DB;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
@@ -33,85 +35,46 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the account_id, which is the asset account that paid for the transaction.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAssetAccount(TransactionJournal $journal)
|
||||
{
|
||||
$positive = true; // the asset account is in the transaction with the positive amount.
|
||||
switch ($journal->transactionType->type) {
|
||||
case 'Withdrawal':
|
||||
$positive = false;
|
||||
break;
|
||||
}
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions()->get() as $transaction) {
|
||||
if (floatval($transaction->amount) > 0 && $positive === true) {
|
||||
return $transaction->account_id;
|
||||
}
|
||||
if (floatval($transaction->amount) < 0 && $positive === false) {
|
||||
return $transaction->account_id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $journal->transactions()->first()->account_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param TransactionJournal $journal
|
||||
* @param TransactionType $dbType
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function searchRelated($query, TransactionJournal $journal)
|
||||
public function getJournalsOfType(TransactionType $dbType)
|
||||
{
|
||||
$start = clone $journal->date;
|
||||
$end = clone $journal->date;
|
||||
$start->startOfMonth();
|
||||
$end->endOfMonth();
|
||||
return Auth::user()->transactionjournals()->where('transaction_type_id', $dbType->id)->orderBy('id', 'DESC')->take(50)->get();
|
||||
}
|
||||
|
||||
// get already related transactions:
|
||||
$exclude = [$journal->id];
|
||||
foreach ($journal->transactiongroups()->get() as $group) {
|
||||
foreach ($group->transactionjournals()->get() as $current) {
|
||||
$exclude[] = $current->id;
|
||||
/**
|
||||
* @param $type
|
||||
*
|
||||
* @return TransactionType
|
||||
*/
|
||||
public function getTransactionType($type)
|
||||
{
|
||||
return TransactionType::whereType($type)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* * Remember: a balancingAct takes at most one expense and one transfer.
|
||||
* an advancePayment takes at most one expense, infinite deposits and NO transfers.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function saveTags(TransactionJournal $journal, array $array)
|
||||
{
|
||||
/** @var \FireflyIII\Repositories\Tag\TagRepositoryInterface $tagRepository */
|
||||
$tagRepository = App::make('FireflyIII\Repositories\Tag\TagRepositoryInterface');
|
||||
|
||||
foreach ($array as $name) {
|
||||
if (strlen(trim($name)) > 0) {
|
||||
$tag = Tag::firstOrCreateEncrypted(['tag' => $name, 'user_id' => $journal->user_id]);
|
||||
$tagRepository->connect($journal, $tag);
|
||||
}
|
||||
}
|
||||
$exclude = array_unique($exclude);
|
||||
|
||||
/** @var Collection $collection */
|
||||
$collection = Auth::user()->transactionjournals()
|
||||
->withRelevantData()
|
||||
->before($end)->after($start)->where('encrypted', 0)
|
||||
->whereNotIn('id', $exclude)
|
||||
->where('description', 'LIKE', '%' . $query . '%')
|
||||
->get();
|
||||
|
||||
// manually search encrypted entries:
|
||||
/** @var Collection $encryptedCollection */
|
||||
$encryptedCollection = Auth::user()->transactionjournals()
|
||||
->withRelevantData()
|
||||
->before($end)->after($start)
|
||||
->where('encrypted', 1)
|
||||
->whereNotIn('id', $exclude)
|
||||
->get();
|
||||
$encrypted = $encryptedCollection->filter(
|
||||
function (TransactionJournal $journal) use ($query) {
|
||||
$strPos = strpos(strtolower($journal->description), strtolower($query));
|
||||
if ($strPos !== false) {
|
||||
return $journal;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
return $collection->merge($encrypted);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,7 +103,7 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
|
||||
// store or get category
|
||||
if (strlen($data['category']) > 0) {
|
||||
$category = Category::firstOrCreate(['name' => $data['category'], 'user_id' => $data['user']]);
|
||||
$category = Category::firstOrCreateEncrypted(['name' => $data['category'], 'user_id' => $data['user']]);
|
||||
$journal->categories()->save($category);
|
||||
}
|
||||
|
||||
@@ -171,6 +134,11 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
$journal->completed = 1;
|
||||
$journal->save();
|
||||
|
||||
// store tags
|
||||
if (isset($data['tags']) && is_array($data['tags'])) {
|
||||
$this->saveTags($journal, $data['tags']);
|
||||
}
|
||||
|
||||
return $journal;
|
||||
|
||||
|
||||
@@ -193,7 +161,7 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
// unlink all categories, recreate them:
|
||||
$journal->categories()->detach();
|
||||
if (strlen($data['category']) > 0) {
|
||||
$category = Category::firstOrCreate(['name' => $data['category'], 'user_id' => $data['user']]);
|
||||
$category = Category::firstOrCreateEncrypted(['name' => $data['category'], 'user_id' => $data['user']]);
|
||||
$journal->categories()->save($category);
|
||||
}
|
||||
|
||||
@@ -226,9 +194,54 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
|
||||
$journal->save();
|
||||
|
||||
// update tags:
|
||||
if (isset($data['tags']) && is_array($data['tags'])) {
|
||||
$this->updateTags($journal, $data['tags']);
|
||||
}
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateTags(TransactionJournal $journal, array $array)
|
||||
{
|
||||
// create tag repository
|
||||
/** @var \FireflyIII\Repositories\Tag\TagRepositoryInterface $tagRepository */
|
||||
$tagRepository = App::make('FireflyIII\Repositories\Tag\TagRepositoryInterface');
|
||||
|
||||
|
||||
// find or create all tags:
|
||||
$tags = [];
|
||||
$ids = [];
|
||||
foreach ($array as $name) {
|
||||
if (strlen(trim($name)) > 0) {
|
||||
$tag = Tag::firstOrCreateEncrypted(['tag' => $name, 'user_id' => $journal->user_id]);
|
||||
$tags[] = $tag;
|
||||
$ids[] = $tag->id;
|
||||
}
|
||||
}
|
||||
|
||||
// delete all tags connected to journal not in this array:
|
||||
if (count($ids) > 0) {
|
||||
DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal->id)->whereNotIn('tag_id', $ids)->delete();
|
||||
}
|
||||
// if count is zero, delete them all:
|
||||
if(count($ids) == 0) {
|
||||
DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal->id)->delete();
|
||||
}
|
||||
|
||||
// connect each tag to journal (if not yet connected):
|
||||
/** @var Tag $tag */
|
||||
foreach ($tags as $tag) {
|
||||
$tagRepository->connect($journal, $tag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionType $type
|
||||
* @param array $data
|
||||
@@ -289,5 +302,4 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
|
||||
return [$from, $to];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace FireflyIII\Repositories\Journal;
|
||||
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
@@ -14,22 +15,40 @@ use Illuminate\Support\Collection;
|
||||
interface JournalRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Get users first transaction journal
|
||||
*
|
||||
* Get the account_id, which is the asset account that paid for the transaction.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return int
|
||||
* @return TransactionJournal
|
||||
*/
|
||||
public function getAssetAccount(TransactionJournal $journal);
|
||||
public function first();
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param TransactionJournal $journal
|
||||
* @param TransactionType $dbType
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function searchRelated($query, TransactionJournal $journal);
|
||||
public function getJournalsOfType(TransactionType $dbType);
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
*
|
||||
* @return TransactionType
|
||||
*/
|
||||
public function getTransactionType($type);
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return void
|
||||
|
||||
/**
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function saveTags(TransactionJournal $journal, array $array);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
@@ -47,8 +66,10 @@ interface JournalRepositoryInterface
|
||||
public function update(TransactionJournal $journal, array $data);
|
||||
|
||||
/**
|
||||
* Get users first transaction journal
|
||||
* @return TransactionJournal
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function first();
|
||||
public function updateTags(TransactionJournal $journal, array $array);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
namespace FireflyIII\Repositories\PiggyBank;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\PiggyBankRepetition;
|
||||
use Illuminate\Support\Collection;
|
||||
use Navigation;
|
||||
@@ -17,6 +19,7 @@ use Navigation;
|
||||
class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
@@ -68,6 +71,19 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
return $bars;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param $amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function createEvent(PiggyBank $piggyBank, $amount)
|
||||
{
|
||||
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
@@ -86,6 +102,47 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
return $part;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(PiggyBank $piggyBank)
|
||||
{
|
||||
return $piggyBank->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getEventSummarySet(PiggyBank $piggyBank)
|
||||
{
|
||||
return DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getEvents(PiggyBank $piggyBank)
|
||||
{
|
||||
return $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPiggyBanks()
|
||||
{
|
||||
/** @var Collection $set */
|
||||
$set = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get();
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all piggy banks to order 0.
|
||||
*
|
||||
|
||||
@@ -14,7 +14,6 @@ use Illuminate\Support\Collection;
|
||||
interface PiggyBankRepositoryInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
@@ -28,6 +27,18 @@ interface PiggyBankRepositoryInterface
|
||||
*/
|
||||
public function calculateParts(PiggyBankRepetition $repetition);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPiggyBanks();
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getEvents(PiggyBank $piggyBank);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
@@ -35,6 +46,28 @@ interface PiggyBankRepositoryInterface
|
||||
*/
|
||||
public function createPiggyBankPart(array $data);
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param $amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function createEvent(PiggyBank $piggyBank, $amount);
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getEventSummarySet(PiggyBank $piggyBank);
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(PiggyBank $piggyBank);
|
||||
|
||||
/**
|
||||
* Set all piggy banks to order 0.
|
||||
*
|
||||
|
||||
180
app/Repositories/Tag/TagRepository.php
Normal file
180
app/Repositories/Tag/TagRepository.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Repositories\Tag;
|
||||
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class TagRepository
|
||||
*
|
||||
* @package FireflyIII\Repositories\Tag
|
||||
*/
|
||||
class TagRepository implements TagRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function connect(TransactionJournal $journal, Tag $tag)
|
||||
{
|
||||
|
||||
/*
|
||||
* Already connected:
|
||||
*/
|
||||
if ($journal->tags()->find($tag->id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($tag->tagMode == 'nothing') {
|
||||
// save it, no problem:
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* get some withdrawal types:
|
||||
*/
|
||||
/** @var TransactionType $withdrawal */
|
||||
$withdrawal = TransactionType::whereType('Withdrawal')->first();
|
||||
/** @var TransactionType $deposit */
|
||||
$deposit = TransactionType::whereType('Deposit')->first();
|
||||
/** @var TransactionType $transfer */
|
||||
$transfer = TransactionType::whereType('Transfer')->first();
|
||||
|
||||
$withdrawals = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->count();
|
||||
$transfers = $tag->transactionjournals()->where('transaction_type_id', $transfer->id)->count();
|
||||
|
||||
if ($tag->tagMode == 'balancingAct') {
|
||||
|
||||
// only if this is the only withdrawal.
|
||||
if ($journal->transaction_type_id == $withdrawal->id && $withdrawals < 1) {
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
// and only if this is the only transfer
|
||||
if ($journal->transaction_type_id == $transfer->id && $transfers < 1) {
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ignore expense
|
||||
return false;
|
||||
}
|
||||
if ($tag->tagMode == 'advancePayment') {
|
||||
|
||||
|
||||
// only if this is the only withdrawal
|
||||
if ($journal->transaction_type_id == $withdrawal->id && $withdrawals < 1) {
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// only if this is a deposit.
|
||||
if ($journal->transaction_type_id == $deposit->id) {
|
||||
|
||||
// if this is a deposit, account must match the current only journal
|
||||
// (if already present):
|
||||
$currentWithdrawal = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->first();
|
||||
|
||||
if ($currentWithdrawal && $currentWithdrawal->assetAccount->id == $journal->assetAccount->id) {
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (is_null($currentWithdrawal)) {
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function destroy(Tag $tag)
|
||||
{
|
||||
$tag->delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
/** @var Collection $tags */
|
||||
$tags = Auth::user()->tags()->get();
|
||||
$tags->sortBy(
|
||||
function (Tag $tag) {
|
||||
return $tag->tag;
|
||||
}
|
||||
);
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Tag
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
$tag = new Tag;
|
||||
$tag->tag = $data['tag'];
|
||||
$tag->date = $data['date'];
|
||||
$tag->description = $data['description'];
|
||||
$tag->latitude = $data['latitude'];
|
||||
$tag->longitude = $data['longitude'];
|
||||
$tag->zoomLevel = $data['zoomLevel'];
|
||||
$tag->tagMode = $data['tagMode'];
|
||||
$tag->user()->associate(Auth::user());
|
||||
$tag->save();
|
||||
|
||||
return $tag;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
* @param array $data
|
||||
*
|
||||
* @return Tag
|
||||
*/
|
||||
public function update(Tag $tag, array $data)
|
||||
{
|
||||
$tag->tag = $data['tag'];
|
||||
$tag->date = $data['date'];
|
||||
$tag->description = $data['description'];
|
||||
$tag->latitude = $data['latitude'];
|
||||
$tag->longitude = $data['longitude'];
|
||||
$tag->zoomLevel = $data['zoomLevel'];
|
||||
$tag->tagMode = $data['tagMode'];
|
||||
$tag->save();
|
||||
|
||||
return $tag;
|
||||
}
|
||||
}
|
||||
50
app/Repositories/Tag/TagRepositoryInterface.php
Normal file
50
app/Repositories/Tag/TagRepositoryInterface.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Repositories\Tag;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
|
||||
/**
|
||||
* Interface TagRepositoryInterface
|
||||
*
|
||||
* @package FireflyIII\Repositories\Tag
|
||||
*/
|
||||
interface TagRepositoryInterface {
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Tag
|
||||
*/
|
||||
public function store(array $data);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get();
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
* @param array $data
|
||||
*
|
||||
* @return Tag
|
||||
*/
|
||||
public function update(Tag $tag, array $data);
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function destroy(Tag $tag);
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function connect(TransactionJournal $journal, Tag $tag);
|
||||
}
|
||||
@@ -160,12 +160,15 @@ class Amount
|
||||
|
||||
$currencyPreference = Prefs::get('currencyPreference', 'EUR');
|
||||
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||
if ($currency) {
|
||||
|
||||
\Cache::forever('FFCURRENCYCODE', $currency->code);
|
||||
Cache::forever('FFCURRENCYCODE', $currency->code);
|
||||
define('FFCURRENCYCODE', $currency->code);
|
||||
|
||||
define('FFCURRENCYCODE', $currency->code);
|
||||
return $currency->code;
|
||||
}
|
||||
|
||||
return $currency->code;
|
||||
return 'EUR';
|
||||
}
|
||||
|
||||
public function getDefaultCurrency()
|
||||
|
||||
@@ -62,7 +62,10 @@ class ExpandedForm
|
||||
'account_id' => 'Asset account',
|
||||
'budget_id' => 'Budget',
|
||||
'openingBalance' => 'Opening balance',
|
||||
'tagMode' => 'Tag mode',
|
||||
'tagPosition' => 'Tag location',
|
||||
'virtualBalance' => 'Virtual balance',
|
||||
'longitude_latitude' => 'Location',
|
||||
'targetamount' => 'Target amount',
|
||||
'accountRole' => 'Account role',
|
||||
'openingBalanceDate' => 'Opening balance date',
|
||||
@@ -201,15 +204,17 @@ class ExpandedForm
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function month($name, $value = null, array $options = [])
|
||||
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);
|
||||
$html = View::make('form.month', compact('classes', 'name', 'label', 'value', 'options'))->render();
|
||||
$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;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,14 +224,13 @@ class ExpandedForm
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function integer($name, $value = null, array $options = [])
|
||||
public function location($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();
|
||||
$label = $this->label($name, $options);
|
||||
$options = $this->expandOptionArray($name, $label, $options);
|
||||
$classes = $this->getHolderClasses($name);
|
||||
$value = $this->fillFieldValue($name, $value);
|
||||
$html = View::make('form.location', compact('classes', 'name', 'label', 'value', 'options'))->render();
|
||||
|
||||
return $html;
|
||||
|
||||
@@ -265,6 +269,44 @@ class ExpandedForm
|
||||
return $selectList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function month($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);
|
||||
$html = View::make('form.month', compact('classes', 'name', 'label', 'value', 'options'))->render();
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function multiRadio($name, array $list = [], $selected = null, array $options = [])
|
||||
{
|
||||
$label = $this->label($name, $options);
|
||||
$options = $this->expandOptionArray($name, $label, $options);
|
||||
$classes = $this->getHolderClasses($name);
|
||||
$selected = $this->fillFieldValue($name, $selected);
|
||||
|
||||
unset($options['class']);
|
||||
$html = View::make('form.multiRadio', compact('classes', 'name', 'label', 'selected', 'options', 'list'))->render();
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param $name
|
||||
@@ -336,4 +378,24 @@ class ExpandedForm
|
||||
return $html;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function textarea($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['rows'] = 4;
|
||||
$html = View::make('form.textarea', compact('classes', 'name', 'label', 'value', 'options'))->render();
|
||||
|
||||
return $html;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,8 +67,8 @@ class Steam
|
||||
public function limitArray(array $array, $limit = 10)
|
||||
{
|
||||
$others = [
|
||||
'name' => 'Others',
|
||||
'amount' => 0
|
||||
'name' => 'Others',
|
||||
'queryAmount' => 0
|
||||
];
|
||||
$return = [];
|
||||
$count = 0;
|
||||
@@ -76,7 +76,7 @@ class Steam
|
||||
if ($count < ($limit - 1)) {
|
||||
$return[$id] = $entry;
|
||||
} else {
|
||||
$others['amount'] += $entry['amount'];
|
||||
$others['queryAmount'] += $entry['queryAmount'];
|
||||
}
|
||||
|
||||
$count++;
|
||||
@@ -103,14 +103,16 @@ class Steam
|
||||
$id = intval($entry->id);
|
||||
if (isset($array[$id])) {
|
||||
$array[$id]['amount'] += floatval($entry->amount);
|
||||
$array[$id]['queryAmount'] += floatval($entry->queryAmount);
|
||||
$array[$id]['spent'] += floatval($entry->spent);
|
||||
$array[$id]['encrypted'] = intval($entry->encrypted);
|
||||
} else {
|
||||
$array[$id] = [
|
||||
'amount' => floatval($entry->amount),
|
||||
'spent' => floatval($entry->spent),
|
||||
'encrypted' => intval($entry->encrypted),
|
||||
'name' => $entry->name
|
||||
'amount' => floatval($entry->amount),
|
||||
'queryAmount' => floatval($entry->queryAmount),
|
||||
'spent' => floatval($entry->spent),
|
||||
'encrypted' => intval($entry->encrypted),
|
||||
'name' => $entry->name
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -131,7 +133,7 @@ class Steam
|
||||
foreach ($two as $id => $value) {
|
||||
// $otherId also exists in $one:
|
||||
if (isset($one[$id])) {
|
||||
$one[$id]['amount'] += $value['amount'];
|
||||
$one[$id]['queryAmount'] += $value['queryAmount'];
|
||||
$one[$id]['spent'] += $value['spent'];
|
||||
} else {
|
||||
$one[$id] = $value;
|
||||
@@ -170,11 +172,11 @@ class Steam
|
||||
{
|
||||
uasort(
|
||||
$array, function ($left, $right) {
|
||||
if ($left['amount'] == $right['amount']) {
|
||||
if ($left['queryAmount'] == $right['queryAmount']) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($left['amount'] < $right['amount']) ? 1 : -1;
|
||||
return ($left['queryAmount'] < $right['queryAmount']) ? 1 : -1;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -193,11 +195,11 @@ class Steam
|
||||
{
|
||||
uasort(
|
||||
$array, function ($left, $right) {
|
||||
if ($left['amount'] == $right['amount']) {
|
||||
if ($left['queryAmount'] == $right['queryAmount']) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($left['amount'] < $right['amount']) ? -1 : 1;
|
||||
return ($left['queryAmount'] < $right['queryAmount']) ? -1 : 1;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
53
app/Support/Twig/Budget.php
Normal file
53
app/Support/Twig/Budget.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Support\Twig;
|
||||
|
||||
use Auth;
|
||||
use DB;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFunction;
|
||||
|
||||
/**
|
||||
* Class Budget
|
||||
*
|
||||
* @package FireflyIII\Support\Twig
|
||||
*/
|
||||
class Budget extends Twig_Extension
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'spentInRepetition', function (LimitRepetition $repetition) {
|
||||
$sum = DB::table('transactions')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budget_transaction_journal.budget_id')
|
||||
->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('transaction_journals.date', '>=', $repetition->startdate->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $repetition->enddate->format('Y-m-d'))
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->whereNull('transactions.deleted_at')
|
||||
->where('transactions.amount', '>', 0)
|
||||
->where('limit_repetitions.id', '=', $repetition->id)
|
||||
->sum('transactions.amount');
|
||||
|
||||
return floatval($sum);
|
||||
}
|
||||
);
|
||||
|
||||
return $functions;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'FireflyIII\Support\Twig\Budget';
|
||||
}
|
||||
}
|
||||
146
app/Support/Twig/General.php
Normal file
146
app/Support/Twig/General.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Support\Twig;
|
||||
|
||||
use App;
|
||||
use Config;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use Route;
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFilter;
|
||||
use Twig_SimpleFunction;
|
||||
|
||||
/**
|
||||
* Class TwigSupport
|
||||
*
|
||||
* @package FireflyIII\Support
|
||||
*/
|
||||
class General extends Twig_Extension
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
$filters = [];
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'formatAmount', function ($string) {
|
||||
return App::make('amount')->format($string);
|
||||
}, ['is_safe' => ['html']]
|
||||
);
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'formatTransaction', function (Transaction $transaction) {
|
||||
return App::make('amount')->formatTransaction($transaction);
|
||||
}, ['is_safe' => ['html']]
|
||||
);
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'formatAmountPlain', function ($string) {
|
||||
return App::make('amount')->format($string, false);
|
||||
}
|
||||
);
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'formatJournal', function ($journal) {
|
||||
return App::make('amount')->formatJournal($journal);
|
||||
}, ['is_safe' => ['html']]
|
||||
);
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'balance', function (Account $account = null) {
|
||||
if (is_null($account)) {
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
return App::make('steam')->balance($account);
|
||||
}
|
||||
);
|
||||
|
||||
// should be a function but OK
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'getAccountRole', function ($name) {
|
||||
return Config::get('firefly.accountRoles.' . $name);
|
||||
}
|
||||
);
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
$functions = [];
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'getCurrencyCode', function () {
|
||||
return App::make('amount')->getCurrencyCode();
|
||||
}
|
||||
);
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'getCurrencySymbol', function () {
|
||||
return App::make('amount')->getCurrencySymbol();
|
||||
}
|
||||
);
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'phpdate', function ($str) {
|
||||
return date($str);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'env', function ($name, $default) {
|
||||
return env($name, $default);
|
||||
}
|
||||
);
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'activeRoute', function ($context) {
|
||||
$args = func_get_args();
|
||||
$route = $args[1];
|
||||
$what = isset($args[2]) ? $args[2] : false;
|
||||
$strict = isset($args[3]) ? $args[3] : false;
|
||||
$activeWhat = isset($context['what']) ? $context['what'] : false;
|
||||
|
||||
// activeRoute
|
||||
if (!($what === false)) {
|
||||
if ($what == $activeWhat && Route::getCurrentRoute()->getName() == $route) {
|
||||
return 'active because-active-what';
|
||||
}
|
||||
} else {
|
||||
if (!$strict && !(strpos(Route::getCurrentRoute()->getName(), $route) === false)) {
|
||||
return 'active because-route-matches-non-strict';
|
||||
} else {
|
||||
if ($strict && Route::getCurrentRoute()->getName() == $route) {
|
||||
return 'active because-route-matches-strict';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 'not-xxx-at-all';
|
||||
}, ['needs_context' => true]
|
||||
);
|
||||
|
||||
return $functions;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'FireflyIII\Support\Twig\General';
|
||||
}
|
||||
|
||||
}
|
||||
99
app/Support/Twig/Journal.php
Normal file
99
app/Support/Twig/Journal.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Support\Twig;
|
||||
|
||||
|
||||
use App;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFilter;
|
||||
use Twig_SimpleFunction;
|
||||
|
||||
/**
|
||||
* Class Journal
|
||||
*
|
||||
* @package FireflyIII\Support\Twig
|
||||
*/
|
||||
class Journal extends Twig_Extension
|
||||
{
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
$filters = [];
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'typeIcon', function (TransactionJournal $journal) {
|
||||
$type = $journal->transactionType->type;
|
||||
if ($type == 'Withdrawal') {
|
||||
return '<span class="glyphicon glyphicon-arrow-left" title="Withdrawal"></span>';
|
||||
}
|
||||
if ($type == 'Deposit') {
|
||||
return '<span class="glyphicon glyphicon-arrow-right" title="Deposit"></span>';
|
||||
}
|
||||
if ($type == 'Transfer') {
|
||||
return '<i class="fa fa-fw fa-exchange" title="Transfer"></i>';
|
||||
}
|
||||
if ($type == 'Opening balance') {
|
||||
return '<span class="glyphicon glyphicon-ban-circle" title="Opening balance"></span>';
|
||||
}
|
||||
|
||||
|
||||
}, ['is_safe' => ['html']]
|
||||
);
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
$functions = [];
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'invalidJournal', function (TransactionJournal $journal) {
|
||||
if (!isset($journal->transactions[1]) || !isset($journal->transactions[0])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'relevantTags', function (TransactionJournal $journal) {
|
||||
if ($journal->tags->count() == 0) {
|
||||
return App::make('amount')->formatJournal($journal);
|
||||
}
|
||||
foreach ($journal->tags as $tag) {
|
||||
if ($tag->tagMode == 'balancingAct') {
|
||||
// return tag formatted for a "balancing act".
|
||||
$amount = App::make('amount')->formatJournal($journal, false);
|
||||
|
||||
return '<a href="' . route('tags.show', $tag->id) . '" class="label label-success" title="' . $amount
|
||||
. '"><i class="fa fa-fw fa-refresh"></i> ' . $tag->tag . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 'TODO: ' . $journal->amount;
|
||||
}
|
||||
);
|
||||
|
||||
return $functions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the extension.
|
||||
*
|
||||
* @return string The extension name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'FireflyIII\Support\Twig\Journals';
|
||||
}
|
||||
}
|
||||
41
app/Support/Twig/PiggyBank.php
Normal file
41
app/Support/Twig/PiggyBank.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Support\Twig;
|
||||
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFunction;
|
||||
use FireflyIII\Models\PiggyBank as PB;
|
||||
|
||||
/**
|
||||
* Class PiggyBank
|
||||
*
|
||||
* @package FireflyIII\Support\Twig
|
||||
*/
|
||||
class PiggyBank extends Twig_Extension
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
$functions = [];
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'currentRelevantRepAmount', function (PB $piggyBank) {
|
||||
return $piggyBank->currentRelevantRep()->currentamount;
|
||||
}
|
||||
);
|
||||
return $functions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the extension.
|
||||
*
|
||||
* @return string The extension name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'FireflyIII\Support\Twig\PiggyBank';
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,14 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||
return $this->hasMany('FireflyIII\Models\Account');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function tags()
|
||||
{
|
||||
return $this->hasMany('FireflyIII\Models\Tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,7 @@ use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Validation\Validator;
|
||||
use Log;
|
||||
use Navigation;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Class FireflyValidator
|
||||
@@ -22,6 +23,18 @@ use Navigation;
|
||||
class FireflyValidator extends Validator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param TranslatorInterface $translator
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @param array $messages
|
||||
* @param array $customAttributes
|
||||
*/
|
||||
public function __construct(TranslatorInterface $translator, array $data, array $rules, array $messages = [], array $customAttributes = [])
|
||||
{
|
||||
parent::__construct($translator, $data, $rules, $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $attribute
|
||||
* @param $value
|
||||
@@ -181,10 +194,14 @@ class FireflyValidator extends Validator
|
||||
*/
|
||||
public function validateUniqueObjectForUser($attribute, $value, $parameters)
|
||||
{
|
||||
$table = $parameters[0];
|
||||
$field = $parameters[1];
|
||||
$encrypted = isset($parameters[2]) ? $parameters[2] : 'encrypted';
|
||||
$exclude = isset($parameters[3]) ? $parameters[3] : null;
|
||||
$table = $parameters[0];
|
||||
$field = $parameters[1];
|
||||
$encrypted = isset($parameters[2]) ? $parameters[2] : 'encrypted';
|
||||
$exclude = isset($parameters[3]) ? $parameters[3] : null;
|
||||
$alwaysEncrypted = false;
|
||||
if ($encrypted == 'TRUE') {
|
||||
$alwaysEncrypted = true;
|
||||
}
|
||||
|
||||
$query = DB::table($table)->where('user_id', Auth::user()->id);
|
||||
|
||||
@@ -195,8 +212,12 @@ class FireflyValidator extends Validator
|
||||
|
||||
$set = $query->get();
|
||||
foreach ($set as $entry) {
|
||||
$isEncrypted = intval($entry->$encrypted) == 1 ? true : false;
|
||||
$checkValue = $isEncrypted ? Crypt::decrypt($entry->$field) : $entry->$field;
|
||||
if (!$alwaysEncrypted) {
|
||||
$isEncrypted = intval($entry->$encrypted) == 1 ? true : false;
|
||||
} else {
|
||||
$isEncrypted = true;
|
||||
}
|
||||
$checkValue = $isEncrypted ? Crypt::decrypt($entry->$field) : $entry->$field;
|
||||
if ($checkValue == $value) {
|
||||
return false;
|
||||
}
|
||||
@@ -223,10 +244,10 @@ class FireflyValidator extends Validator
|
||||
}
|
||||
$set = $query->get(['piggy_banks.*']);
|
||||
|
||||
foreach($set as $entry) {
|
||||
foreach ($set as $entry) {
|
||||
$isEncrypted = intval($entry->encrypted) == 1 ? true : false;
|
||||
$checkValue = $isEncrypted ? Crypt::decrypt($entry->name) : $entry->name;
|
||||
if($checkValue == $value) {
|
||||
$checkValue = $isEncrypted ? Crypt::decrypt($entry->name) : $entry->name;
|
||||
if ($checkValue == $value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
$app = new Illuminate\Foundation\Application(
|
||||
realpath(__DIR__ . '/../')
|
||||
);
|
||||
@@ -26,6 +27,8 @@ $app = new Illuminate\Foundation\Application(
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
|
||||
$app->singleton(
|
||||
'Illuminate\Contracts\Http\Kernel',
|
||||
'FireflyIII\Http\Kernel'
|
||||
@@ -41,6 +44,9 @@ $app->singleton(
|
||||
'FireflyIII\Exceptions\Handler'
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Return The Application
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
"watson/validating": "~1.0",
|
||||
"doctrine/dbal": "~2.5",
|
||||
"illuminate/html": "~5.0",
|
||||
"league/commonmark": "0.7.*"
|
||||
"league/commonmark": "0.7.*",
|
||||
"rcrowe/twigbridge": "0.7.x@dev",
|
||||
"twig/extensions": "~1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "@stable",
|
||||
|
||||
410
composer.lock
generated
410
composer.lock
generated
@@ -4,24 +4,24 @@
|
||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "0d43c4c85607c5cdc901cde2d18b75d5",
|
||||
"hash": "e3e90dd365b74f4878cf3b5b4a1c4007",
|
||||
"packages": [
|
||||
{
|
||||
"name": "classpreloader/classpreloader",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ClassPreloader/ClassPreloader.git",
|
||||
"reference": "f0bfbf71fb3335c9473f695d4d966ba2fb879a9f"
|
||||
"reference": "0544616ba33fb2a6b792b3a7822650810c6d65d9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/f0bfbf71fb3335c9473f695d4d966ba2fb879a9f",
|
||||
"reference": "f0bfbf71fb3335c9473f695d4d966ba2fb879a9f",
|
||||
"url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/0544616ba33fb2a6b792b3a7822650810c6d65d9",
|
||||
"reference": "0544616ba33fb2a6b792b3a7822650810c6d65d9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nikic/php-parser": "~1.0",
|
||||
"nikic/php-parser": "^1.2.2",
|
||||
"php": ">=5.3.3",
|
||||
"symfony/console": "~2.1",
|
||||
"symfony/filesystem": "~2.1",
|
||||
@@ -36,7 +36,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
"dev-master": "1.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -64,7 +64,7 @@
|
||||
"class",
|
||||
"preload"
|
||||
],
|
||||
"time": "2015-01-26 22:06:19"
|
||||
"time": "2015-04-15 21:59:30"
|
||||
},
|
||||
{
|
||||
"name": "danielstjules/stringy",
|
||||
@@ -206,16 +206,16 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "v1.2.3",
|
||||
"version": "v1.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/annotations.git",
|
||||
"reference": "eeda578cbe24a170331a1cfdf78be723412df7a4"
|
||||
"reference": "b5202eb9e83f8db52e0e58867e0a46e63be8332e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/annotations/zipball/eeda578cbe24a170331a1cfdf78be723412df7a4",
|
||||
"reference": "eeda578cbe24a170331a1cfdf78be723412df7a4",
|
||||
"url": "https://api.github.com/repos/doctrine/annotations/zipball/b5202eb9e83f8db52e0e58867e0a46e63be8332e",
|
||||
"reference": "b5202eb9e83f8db52e0e58867e0a46e63be8332e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -270,20 +270,20 @@
|
||||
"docblock",
|
||||
"parser"
|
||||
],
|
||||
"time": "2014-12-20 20:49:38"
|
||||
"time": "2014-12-23 22:40:37"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "v1.4.0",
|
||||
"version": "v1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/cache.git",
|
||||
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8"
|
||||
"reference": "c9eadeb743ac6199f7eec423cb9426bc518b7b03"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/2346085d2b027b233ae1d5de59b07440b9f288c8",
|
||||
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/c9eadeb743ac6199f7eec423cb9426bc518b7b03",
|
||||
"reference": "c9eadeb743ac6199f7eec423cb9426bc518b7b03",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -294,13 +294,13 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=3.7",
|
||||
"predis/predis": "~0.8",
|
||||
"predis/predis": "~1.0",
|
||||
"satooshi/php-coveralls": "~0.6"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4.x-dev"
|
||||
"dev-master": "1.5.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -340,25 +340,28 @@
|
||||
"cache",
|
||||
"caching"
|
||||
],
|
||||
"time": "2015-01-15 20:38:55"
|
||||
"time": "2015-04-15 00:11:59"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/collections",
|
||||
"version": "v1.2",
|
||||
"version": "v1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/collections.git",
|
||||
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2"
|
||||
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2",
|
||||
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
|
||||
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@@ -375,17 +378,6 @@
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com",
|
||||
"homepage": "http://www.jwage.com/",
|
||||
"role": "Creator"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com",
|
||||
"homepage": "http://www.instaclick.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
@@ -394,11 +386,17 @@
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com",
|
||||
"homepage": "https://github.com/schmittjoh",
|
||||
"role": "Developer of wrapped JMSSerializerBundle"
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Collections Abstraction library",
|
||||
@@ -408,7 +406,7 @@
|
||||
"collections",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2014-02-03 23:07:43"
|
||||
"time": "2015-04-14 22:21:58"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/common",
|
||||
@@ -677,16 +675,16 @@
|
||||
},
|
||||
{
|
||||
"name": "grumpydictator/gchart",
|
||||
"version": "1.0.8",
|
||||
"version": "1.0.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/JC5/gchart.git",
|
||||
"reference": "24d06101cfda7ff336ecb10f7f0cb0d6004cb83c"
|
||||
"reference": "920a0494a0697472bf81c0111b6825c516099e59"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/JC5/gchart/zipball/24d06101cfda7ff336ecb10f7f0cb0d6004cb83c",
|
||||
"reference": "24d06101cfda7ff336ecb10f7f0cb0d6004cb83c",
|
||||
"url": "https://api.github.com/repos/JC5/gchart/zipball/920a0494a0697472bf81c0111b6825c516099e59",
|
||||
"reference": "920a0494a0697472bf81c0111b6825c516099e59",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -709,7 +707,7 @@
|
||||
}
|
||||
],
|
||||
"description": "GChart is a small package that allows you to easily generate data for the Google Charts API.",
|
||||
"time": "2015-02-20 20:07:26"
|
||||
"time": "2015-04-05 19:17:17"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/html",
|
||||
@@ -945,16 +943,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v5.0.26",
|
||||
"version": "v5.0.28",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "8e53c33e144f94032cc6ecbfee0be2a96ed63be0"
|
||||
"reference": "06a09429322cf53e5bd4587db1060f02a291562e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/8e53c33e144f94032cc6ecbfee0be2a96ed63be0",
|
||||
"reference": "8e53c33e144f94032cc6ecbfee0be2a96ed63be0",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/06a09429322cf53e5bd4587db1060f02a291562e",
|
||||
"reference": "06a09429322cf53e5bd4587db1060f02a291562e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1024,7 +1022,7 @@
|
||||
"predis/predis": "~1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"aws/aws-sdk-php": "Required to use the SQS queue driver (~2.4).",
|
||||
"aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~2.4).",
|
||||
"doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).",
|
||||
"guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers (~5.0).",
|
||||
"iron-io/iron_mq": "Required to use the iron queue driver (~1.5).",
|
||||
@@ -1067,7 +1065,7 @@
|
||||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2015-04-03 02:58:05"
|
||||
"time": "2015-04-21 01:44:32"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
@@ -1377,16 +1375,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v1.2.1",
|
||||
"version": "v1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "dba7524b3724f25b947cd26a580787c55c8a6f9b"
|
||||
"reference": "08f97eb4efa029e2fafb6d8c98b71731bf0cf621"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dba7524b3724f25b947cd26a580787c55c8a6f9b",
|
||||
"reference": "dba7524b3724f25b947cd26a580787c55c8a6f9b",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/08f97eb4efa029e2fafb6d8c98b71731bf0cf621",
|
||||
"reference": "08f97eb4efa029e2fafb6d8c98b71731bf0cf621",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1418,7 +1416,7 @@
|
||||
"parser",
|
||||
"php"
|
||||
],
|
||||
"time": "2015-03-24 19:10:28"
|
||||
"time": "2015-04-03 14:33:59"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
@@ -1529,6 +1527,70 @@
|
||||
],
|
||||
"time": "2015-03-26 18:43:54"
|
||||
},
|
||||
{
|
||||
"name": "rcrowe/twigbridge",
|
||||
"version": "0.7.x-dev",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rcrowe/TwigBridge.git",
|
||||
"reference": "ac0bfb5bcdb4fcd0cd01ab8425620ff07f6af026"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rcrowe/TwigBridge/zipball/ac0bfb5bcdb4fcd0cd01ab8425620ff07f6af026",
|
||||
"reference": "ac0bfb5bcdb4fcd0cd01ab8425620ff07f6af026",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "5.0.*",
|
||||
"illuminate/view": "5.0.*",
|
||||
"php": ">=5.4.0",
|
||||
"twig/twig": "~1.15"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/framework": "5.0.*",
|
||||
"mockery/mockery": "0.9.*",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"satooshi/php-coveralls": "~0.6",
|
||||
"squizlabs/php_codesniffer": "~1.5"
|
||||
},
|
||||
"suggest": {
|
||||
"laravelcollective/html": "For bringing back html/form in Laravel 5.x",
|
||||
"twig/extensions": "~1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"TwigBridge\\": "src",
|
||||
"TwigBridge\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Rob Crowe",
|
||||
"email": "hello@vivalacrowe.com"
|
||||
}
|
||||
],
|
||||
"description": "Adds the power of Twig to Laravel",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"twig"
|
||||
],
|
||||
"time": "2015-04-22 09:19:03"
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
"version": "v5.4.0",
|
||||
@@ -2293,6 +2355,115 @@
|
||||
],
|
||||
"time": "2015-03-31 08:12:29"
|
||||
},
|
||||
{
|
||||
"name": "twig/extensions",
|
||||
"version": "v1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig-extensions.git",
|
||||
"reference": "8cf4b9fe04077bd54fc73f4fde83347040c3b8cd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig-extensions/zipball/8cf4b9fe04077bd54fc73f4fde83347040c3b8cd",
|
||||
"reference": "8cf4b9fe04077bd54fc73f4fde83347040c3b8cd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"twig/twig": "~1.12"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/translation": "~2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/translation": "Allow the time_diff output to be translated"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig_Extensions_": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "Common additional features for Twig that do not directly belong in core",
|
||||
"homepage": "http://twig.sensiolabs.org/doc/extensions/index.html",
|
||||
"keywords": [
|
||||
"i18n",
|
||||
"text"
|
||||
],
|
||||
"time": "2014-10-30 14:30:03"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/9f70492f44398e276d1b81c1b43adfe6751c7b7f",
|
||||
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.18-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig_": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": "http://fabien.potencier.org",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Armin Ronacher",
|
||||
"email": "armin.ronacher@active-4.com",
|
||||
"role": "Project Founder"
|
||||
},
|
||||
{
|
||||
"name": "Twig Team",
|
||||
"homepage": "http://twig.sensiolabs.org/contributors",
|
||||
"role": "Contributors"
|
||||
}
|
||||
],
|
||||
"description": "Twig, the flexible, fast, and secure template language for PHP",
|
||||
"homepage": "http://twig.sensiolabs.org",
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2015-04-19 08:30:27"
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v1.1.0",
|
||||
@@ -3027,23 +3198,23 @@
|
||||
},
|
||||
{
|
||||
"name": "phpspec/phpspec",
|
||||
"version": "2.1.1",
|
||||
"version": "2.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/phpspec.git",
|
||||
"reference": "66a1df93099282b1514e9e001fcf6e9393f7783d"
|
||||
"reference": "9727d75919a00455433e867565bc022f0b985a39"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/phpspec/zipball/66a1df93099282b1514e9e001fcf6e9393f7783d",
|
||||
"reference": "66a1df93099282b1514e9e001fcf6e9393f7783d",
|
||||
"url": "https://api.github.com/repos/phpspec/phpspec/zipball/9727d75919a00455433e867565bc022f0b985a39",
|
||||
"reference": "9727d75919a00455433e867565bc022f0b985a39",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "~1.0,>=1.0.1",
|
||||
"doctrine/instantiator": "^1.0.1",
|
||||
"php": ">=5.3.3",
|
||||
"phpspec/php-diff": "~1.0.0",
|
||||
"phpspec/prophecy": "~1.1",
|
||||
"phpspec/prophecy": "~1.4",
|
||||
"sebastian/exporter": "~1.0",
|
||||
"symfony/console": "~2.3",
|
||||
"symfony/event-dispatcher": "~2.1",
|
||||
@@ -3052,9 +3223,11 @@
|
||||
"symfony/yaml": "~2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"behat/behat": "~3.0,>=3.0.11",
|
||||
"behat/behat": "^3.0.11",
|
||||
"bossa/phpspec2-expect": "~1.0",
|
||||
"symfony/filesystem": "~2.1"
|
||||
"phpunit/phpunit": "~4.4",
|
||||
"symfony/filesystem": "~2.1",
|
||||
"symfony/process": "~2.1"
|
||||
},
|
||||
"suggest": {
|
||||
"phpspec/nyan-formatters": "~1.0 – Adds Nyan formatters"
|
||||
@@ -3065,7 +3238,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
"dev-master": "2.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3099,20 +3272,20 @@
|
||||
"testing",
|
||||
"tests"
|
||||
],
|
||||
"time": "2015-01-09 13:21:45"
|
||||
"time": "2015-04-18 16:22:51"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "1.4.0",
|
||||
"version": "v1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5"
|
||||
"reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5",
|
||||
"reference": "8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
|
||||
"reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3159,20 +3332,20 @@
|
||||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2015-03-27 19:31:25"
|
||||
"time": "2015-04-27 22:15:08"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "2.0.15",
|
||||
"version": "2.0.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "34cc484af1ca149188d0d9e91412191e398e0b67"
|
||||
"reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/34cc484af1ca149188d0d9e91412191e398e0b67",
|
||||
"reference": "34cc484af1ca149188d0d9e91412191e398e0b67",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/934fd03eb6840508231a7f73eb8940cf32c3b66c",
|
||||
"reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3221,35 +3394,37 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2015-01-24 10:06:35"
|
||||
"time": "2015-04-11 04:35:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "1.3.4",
|
||||
"version": "1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
|
||||
"reference": "a923bb15680d0089e2316f7a4af8f437046e96bb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
|
||||
"reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a923bb15680d0089e2316f7a4af8f437046e96bb",
|
||||
"reference": "a923bb15680d0089e2316f7a4af8f437046e96bb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"File/"
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
""
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
@@ -3266,7 +3441,7 @@
|
||||
"filesystem",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2013-10-10 15:34:57"
|
||||
"time": "2015-04-02 05:19:05"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
@@ -3358,16 +3533,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-token-stream",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
|
||||
"reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74"
|
||||
"reference": "eab81d02569310739373308137284e0158424330"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/db32c18eba00b121c145575fcbcd4d4d24e6db74",
|
||||
"reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/eab81d02569310739373308137284e0158424330",
|
||||
"reference": "eab81d02569310739373308137284e0158424330",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3403,20 +3578,20 @@
|
||||
"keywords": [
|
||||
"tokenizer"
|
||||
],
|
||||
"time": "2015-01-17 09:51:32"
|
||||
"time": "2015-04-08 04:46:07"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "4.5.1",
|
||||
"version": "4.6.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "d6429b0995b24a2d9dfe5587ee3a7071c1161af4"
|
||||
"reference": "163232991e652e6efed2f8470326fffa61e848e2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d6429b0995b24a2d9dfe5587ee3a7071c1161af4",
|
||||
"reference": "d6429b0995b24a2d9dfe5587ee3a7071c1161af4",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/163232991e652e6efed2f8470326fffa61e848e2",
|
||||
"reference": "163232991e652e6efed2f8470326fffa61e848e2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3428,17 +3603,17 @@
|
||||
"php": ">=5.3.3",
|
||||
"phpspec/prophecy": "~1.3,>=1.3.1",
|
||||
"phpunit/php-code-coverage": "~2.0,>=2.0.11",
|
||||
"phpunit/php-file-iterator": "~1.3.2",
|
||||
"phpunit/php-file-iterator": "~1.4",
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"phpunit/php-timer": "~1.0.2",
|
||||
"phpunit/php-timer": "~1.0",
|
||||
"phpunit/phpunit-mock-objects": "~2.3",
|
||||
"sebastian/comparator": "~1.1",
|
||||
"sebastian/diff": "~1.1",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/environment": "~1.2",
|
||||
"sebastian/exporter": "~1.2",
|
||||
"sebastian/global-state": "~1.0",
|
||||
"sebastian/version": "~1.0",
|
||||
"symfony/yaml": "~2.0"
|
||||
"symfony/yaml": "~2.1|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"phpunit/php-invoker": "~1.1"
|
||||
@@ -3449,7 +3624,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.5.x-dev"
|
||||
"dev-master": "4.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3475,7 +3650,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2015-03-29 09:24:05"
|
||||
"time": "2015-04-11 05:23:21"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
@@ -3666,16 +3841,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "5843509fed39dee4b356a306401e9dd1a931fec7"
|
||||
"reference": "863df9687835c62aa423a22412d26fa2ebde3fd3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7",
|
||||
"reference": "5843509fed39dee4b356a306401e9dd1a931fec7",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3",
|
||||
"reference": "863df9687835c62aa423a22412d26fa2ebde3fd3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3687,7 +3862,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
"dev-master": "1.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3714,32 +3889,32 @@
|
||||
"keywords": [
|
||||
"diff"
|
||||
],
|
||||
"time": "2014-08-15 10:29:00"
|
||||
"time": "2015-02-22 15:13:53"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7"
|
||||
"reference": "5a8c7d31914337b69923db26c4221b81ff5a196e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e6c71d918088c251b181ba8b3088af4ac336dd7",
|
||||
"reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e",
|
||||
"reference": "5a8c7d31914337b69923db26c4221b81ff5a196e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.3"
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3764,7 +3939,7 @@
|
||||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"time": "2014-10-25 08:00:45"
|
||||
"time": "2015-01-01 10:01:08"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
@@ -3938,16 +4113,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/version.git",
|
||||
"reference": "a77d9123f8e809db3fbdea15038c27a95da4058b"
|
||||
"reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/a77d9123f8e809db3fbdea15038c27a95da4058b",
|
||||
"reference": "a77d9123f8e809db3fbdea15038c27a95da4058b",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
|
||||
"reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@@ -3969,7 +4144,7 @@
|
||||
],
|
||||
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
|
||||
"homepage": "https://github.com/sebastianbergmann/version",
|
||||
"time": "2014-12-15 14:25:24"
|
||||
"time": "2015-02-24 06:35:25"
|
||||
},
|
||||
{
|
||||
"name": "symfony/class-loader",
|
||||
@@ -4177,6 +4352,7 @@
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"rcrowe/twigbridge": 20,
|
||||
"barryvdh/laravel-debugbar": 0
|
||||
},
|
||||
"prefer-stable": false,
|
||||
|
||||
@@ -136,9 +136,11 @@ return [
|
||||
'Illuminate\Validation\ValidationServiceProvider',
|
||||
'Illuminate\View\ViewServiceProvider',
|
||||
'Illuminate\Html\HtmlServiceProvider',
|
||||
'TwigBridge\ServiceProvider',
|
||||
|
||||
'DaveJamesMiller\Breadcrumbs\ServiceProvider',
|
||||
'Barryvdh\Debugbar\ServiceProvider',
|
||||
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
|
||||
'DaveJamesMiller\Breadcrumbs\ServiceProvider',
|
||||
|
||||
/*
|
||||
* Application Service Providers...
|
||||
@@ -151,6 +153,7 @@ return [
|
||||
'FireflyIII\Providers\FireflyServiceProvider',
|
||||
'FireflyIII\Providers\TestingServiceProvider',
|
||||
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
@@ -200,13 +203,14 @@ return [
|
||||
'View' => 'Illuminate\Support\Facades\View',
|
||||
'Form' => 'Illuminate\Html\FormFacade',
|
||||
'Html' => 'Illuminate\Html\HtmlFacade',
|
||||
'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade',
|
||||
|
||||
'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade',
|
||||
'Preferences' => 'FireflyIII\Support\Facades\Preferences',
|
||||
'Navigation' => 'FireflyIII\Support\Facades\Navigation',
|
||||
'Amount' => 'FireflyIII\Support\Facades\Amount',
|
||||
'Steam' => 'FireflyIII\Support\Facades\Steam',
|
||||
'ExpandedForm' => 'FireflyIII\Support\Facades\ExpandedForm',
|
||||
'Twig' => 'TwigBridge\Facade\Twig',
|
||||
|
||||
|
||||
],
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ return [
|
||||
|
||||
'sqlite' => [
|
||||
'driver' => 'sqlite',
|
||||
'database' => ':memory:',
|
||||
'database' => __DIR__.'/../storage/database/testing.db',
|
||||
'prefix' => '',
|
||||
],
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ return [
|
||||
*/
|
||||
|
||||
'paths' => [
|
||||
realpath(base_path('resources/views'))
|
||||
realpath(base_path('resources/twig'))
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@@ -41,6 +41,9 @@ class CreateAccountMetaTable extends Migration
|
||||
|
||||
$table->unique(['account_id', 'name']);
|
||||
|
||||
// link to account!
|
||||
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
@@ -426,7 +426,6 @@ class ChangesForV321 extends Migration
|
||||
|
||||
public function moveComponentIdToBudgetId()
|
||||
{
|
||||
//Log::debug('Now in moveComponentIdToBudgetId()');
|
||||
BudgetLimit::get()->each(
|
||||
function (BudgetLimit $bl) {
|
||||
Log::debug('Now at budgetLimit #' . $bl->id . ' with component_id: ' . $bl->component_id);
|
||||
@@ -447,7 +446,6 @@ class ChangesForV321 extends Migration
|
||||
}
|
||||
}
|
||||
);
|
||||
//Log::debug('Done with moveComponentIdToBudgetId()');
|
||||
|
||||
}
|
||||
|
||||
|
||||
75
database/migrations/2015_04_26_054507_changes_for_v3310.php
Normal file
75
database/migrations/2015_04_26_054507_changes_for_v3310.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class ChangesForV3310 extends Migration
|
||||
{
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('tag_transaction_journal');
|
||||
Schema::drop('tags');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
//
|
||||
Schema::table(
|
||||
'transaction_groups', function (Blueprint $table) {
|
||||
|
||||
// drop column "relation"
|
||||
$table->dropColumn('relation');
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
* New table!
|
||||
*/
|
||||
Schema::create(
|
||||
'tags', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->string('tag', 1024);
|
||||
$table->string('tagMode', 1024);
|
||||
$table->date('date')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->decimal('latitude', 18, 12)->nullable();
|
||||
$table->decimal('longitude', 18, 12)->nullable();
|
||||
$table->smallInteger('zoomLevel', false, true)->nullable();
|
||||
|
||||
// connect reminders to users
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Schema::create('tag_transaction_journal',function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('tag_id')->unsigned();
|
||||
$table->integer('transaction_journal_id')->unsigned();
|
||||
|
||||
// link to foreign tables.
|
||||
$table->foreign('tag_id', 'tag_grp_id')->references('id')->on('tags')->onDelete('cascade');
|
||||
$table->foreign('transaction_journal_id', 'tag_trj_id')->references('id')->on('transaction_journals')->onDelete('cascade');
|
||||
|
||||
// add unique.
|
||||
$table->unique(['tag_id', 'transaction_journal_id'], 'tag_t_joined');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
40
database/migrations/2015_04_28_075215_changes_for_v3310a.php
Normal file
40
database/migrations/2015_04_28_075215_changes_for_v3310a.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
/**
|
||||
* Class ChangesForV3310a
|
||||
*/
|
||||
class ChangesForV3310a extends Migration
|
||||
{
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table(
|
||||
'transaction_groups', function (Blueprint $table) {
|
||||
|
||||
// new column, relation.
|
||||
$table->string('relation', 50)->nullable();
|
||||
}
|
||||
);
|
||||
// make new column "relation"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
32
database/migrations/2015_04_28_075317_changes_for_v3310b.php
Normal file
32
database/migrations/2015_04_28_075317_changes_for_v3310b.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* Class ChangesForV3310b
|
||||
*/
|
||||
class ChangesForV3310b extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// set all current entries to be "balance"
|
||||
DB::table('transaction_groups')->update(['relation' => 'balance']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
stopOnFailure="true"
|
||||
syntaxCheck="false">
|
||||
<testsuites>
|
||||
<testsuite name="Application Test Suite">
|
||||
|
||||
15
pu.sh
15
pu.sh
@@ -1,13 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# backup .env file.
|
||||
cp .env .env.backup
|
||||
|
||||
# set testing environment
|
||||
cp .env.testing .env
|
||||
|
||||
# test!
|
||||
phpunit --verbose
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
phpunit --verbose
|
||||
fi
|
||||
|
||||
if [ ! -z "$1" ]
|
||||
then
|
||||
phpunit --verbose tests/controllers/$1.php
|
||||
fi
|
||||
|
||||
# restore .env file
|
||||
mv .env.backup .env
|
||||
cp .env.local .env
|
||||
|
||||
100
public/css/bootstrap-sortable.css
vendored
Normal file
100
public/css/bootstrap-sortable.css
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
table.sortable span.sign {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 5px;
|
||||
font-size: 12px;
|
||||
margin-top: -10px;
|
||||
color: #bfbfc1;
|
||||
}
|
||||
|
||||
table.sortable th:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 5px;
|
||||
font-size: 12px;
|
||||
margin-top: -10px;
|
||||
color: #bfbfc1;
|
||||
}
|
||||
|
||||
table.sortable th.arrow:after {
|
||||
content: '';
|
||||
}
|
||||
|
||||
table.sortable span.arrow, span.reversed, th.arrow.down:after, th.reversedarrow.down:after, th.arrow.up:after, th.reversedarrow.up:after {
|
||||
border-style: solid;
|
||||
border-width: 5px;
|
||||
font-size: 0;
|
||||
border-color: #ccc transparent transparent transparent;
|
||||
line-height: 0;
|
||||
height: 0;
|
||||
width: 0;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
table.sortable span.arrow.up, th.arrow.up:after {
|
||||
border-color: transparent transparent #ccc transparent;
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
table.sortable span.reversed, th.reversedarrow.down:after {
|
||||
border-color: transparent transparent #ccc transparent;
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
table.sortable span.reversed.up, th.reversedarrow.up:after {
|
||||
border-color: #ccc transparent transparent transparent;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
table.sortable span.az:before, th.az.down:after {
|
||||
content: "a .. z";
|
||||
}
|
||||
|
||||
table.sortable span.az.up:before, th.az.up:after {
|
||||
content: "z .. a";
|
||||
}
|
||||
|
||||
table.sortable th.az.nosort:after, th.AZ.nosort:after, th._19.nosort:after, th.month.nosort:after {
|
||||
content: "..";
|
||||
}
|
||||
|
||||
table.sortable span.AZ:before, th.AZ.down:after {
|
||||
content: "A .. Z";
|
||||
}
|
||||
|
||||
table.sortable span.AZ.up:before, th.AZ.up:after {
|
||||
content: "Z .. A";
|
||||
}
|
||||
|
||||
table.sortable span._19:before, th._19.down:after {
|
||||
content: "1 .. 9";
|
||||
}
|
||||
|
||||
table.sortable span._19.up:before, th._19.up:after {
|
||||
content: "9 .. 1";
|
||||
}
|
||||
|
||||
table.sortable span.month:before, th.month.down:after {
|
||||
content: "jan .. dec";
|
||||
}
|
||||
|
||||
table.sortable span.month.up:before, th.month.up:after {
|
||||
content: "dec .. jan";
|
||||
}
|
||||
|
||||
table.sortable thead th:not([data-defaultsort=disabled]) {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
table.sortable thead th:hover:not([data-defaultsort=disabled]) {
|
||||
background: #efefef;
|
||||
}
|
||||
|
||||
table.sortable thead th div.mozilla {
|
||||
position: relative;
|
||||
}
|
||||
@@ -1,3 +1,13 @@
|
||||
#daterange {cursor:pointer;}
|
||||
.google-chart-error {height:30px;background:url('/images/error.png') no-repeat center center;}
|
||||
.handle {cursor:move;}
|
||||
.handle {cursor:move;}
|
||||
|
||||
.ui-sortable-placeholder {
|
||||
display: inline-block;
|
||||
height: 1px;
|
||||
}
|
||||
#map-canvas {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
padding: 0px
|
||||
}
|
||||
209
public/js/bootstrap-sortable.js
vendored
Normal file
209
public/js/bootstrap-sortable.js
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* TinySort is a small script that sorts HTML elements. It sorts by text- or attribute value, or by that of one of it's children.
|
||||
* @summary A nodeElement sorting script.
|
||||
* @version 2.2.0
|
||||
* @license MIT/GPL
|
||||
* @author Ron Valstar <ron@ronvalstar.nl>
|
||||
* @copyright Ron Valstar <ron@ronvalstar.nl>
|
||||
* @namespace tinysort
|
||||
*/
|
||||
!function (a, b) { "use strict"; function c() { return b } "function" == typeof define && define.amd ? define("tinysort", c) : a.tinysort = b }(this, function () { "use strict"; function a(a, f) { function j() { 0 === arguments.length ? s({}) : d(arguments, function (a) { s(c(a) ? { selector: a } : a) }), p = D.length } function s(a) { var b = !!a.selector, c = b && ":" === a.selector[0], d = e(a || {}, r); D.push(e({ hasSelector: b, hasAttr: !(d.attr === i || "" === d.attr), hasData: d.data !== i, hasFilter: c, sortReturnNumber: "asc" === d.order ? 1 : -1 }, d)) } function t() { d(a, function (a, b) { y ? y !== a.parentNode && (E = !1) : y = a.parentNode; var c = D[0], d = c.hasFilter, e = c.selector, f = !e || d && a.matchesSelector(e) || e && a.querySelector(e), g = f ? B : C, h = { elm: a, pos: b, posn: g.length }; A.push(h), g.push(h) }), x = B.slice(0) } function u() { B.sort(v) } function v(a, e) { var f = 0; for (0 !== q && (q = 0) ; 0 === f && p > q;) { var i = D[q], j = i.ignoreDashes ? n : m; if (d(o, function (a) { var b = a.prepare; b && b(i) }), i.sortFunction) f = i.sortFunction(a, e); else if ("rand" == i.order) f = Math.random() < .5 ? 1 : -1; else { var k = h, r = b(a, i), s = b(e, i), t = "" === r || r === g, u = "" === s || s === g; if (r === s) f = 0; else if (i.emptyEnd && (t || u)) f = t && u ? 0 : t ? 1 : -1; else { if (!i.forceStrings) { var v = c(r) ? r && r.match(j) : h, w = c(s) ? s && s.match(j) : h; if (v && w) { var x = r.substr(0, r.length - v[0].length), y = s.substr(0, s.length - w[0].length); x == y && (k = !h, r = l(v[0]), s = l(w[0])) } } f = r === g || s === g ? 0 : s > r ? -1 : r > s ? 1 : 0 } } d(o, function (a) { var b = a.sort; b && (f = b(i, k, r, s, f)) }), f *= i.sortReturnNumber, 0 === f && q++ } return 0 === f && (f = a.pos > e.pos ? 1 : -1), f } function w() { var a = B.length === A.length; E && a ? F ? B.forEach(function (a, b) { a.elm.style.order = b }) : (B.forEach(function (a) { z.appendChild(a.elm) }), y.appendChild(z)) : (B.forEach(function (a) { var b = a.elm, c = k.createElement("div"); a.ghost = c, b.parentNode.insertBefore(c, b) }), B.forEach(function (a, b) { var c = x[b].ghost; c.parentNode.insertBefore(a.elm, c), c.parentNode.removeChild(c) })) } c(a) && (a = k.querySelectorAll(a)), 0 === a.length && console.warn("No elements to sort"); var x, y, z = k.createDocumentFragment(), A = [], B = [], C = [], D = [], E = !0, F = a.length && (f === g || f.useFlex !== !1) && -1 !== getComputedStyle(a[0].parentNode, null).display.indexOf("flex"); return j.apply(i, Array.prototype.slice.call(arguments, 1)), t(), u(), w(), B.map(function (a) { return a.elm }) } function b(a, b) { var d, e = a.elm; return b.selector && (b.hasFilter ? e.matchesSelector(b.selector) || (e = i) : e = e.querySelector(b.selector)), b.hasAttr ? d = e.getAttribute(b.attr) : b.useVal ? d = e.value || e.getAttribute("value") : b.hasData ? d = e.getAttribute("data-" + b.data) : e && (d = e.textContent), c(d) && (b.cases || (d = d.toLowerCase()), d = d.replace(/\s+/g, " ")), d } function c(a) { return "string" == typeof a } function d(a, b) { for (var c, d = a.length, e = d; e--;) c = d - e - 1, b(a[c], c) } function e(a, b, c) { for (var d in b) (c || a[d] === g) && (a[d] = b[d]); return a } function f(a, b, c) { o.push({ prepare: a, sort: b, sortBy: c }) } var g, h = !1, i = null, j = window, k = j.document, l = parseFloat, m = /(-?\d+\.?\d*)\s*$/g, n = /(\d+\.?\d*)\s*$/g, o = [], p = 0, q = 0, r = { selector: i, order: "asc", attr: i, data: i, useVal: h, place: "start", returns: h, cases: h, forceStrings: h, ignoreDashes: h, sortFunction: i, useFlex: h, emptyEnd: h }; return j.Element && function (a) { a.matchesSelector = a.matchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector || a.webkitMatchesSelector || function (a) { for (var b = this, c = (b.parentNode || b.document).querySelectorAll(a), d = -1; c[++d] && c[d] != b;); return !!c[d] } }(Element.prototype), e(f, { loop: d }), e(a, { plugin: f, defaults: r }) }());
|
||||
|
||||
(function ($) {
|
||||
|
||||
var $document = $(document),
|
||||
signClass,
|
||||
sortEngine;
|
||||
|
||||
$.bootstrapSortable = function (applyLast, sign, customSort) {
|
||||
|
||||
// Check if moment.js is available
|
||||
var momentJsAvailable = (typeof moment !== 'undefined');
|
||||
|
||||
// Set class based on sign parameter
|
||||
signClass = !sign ? "arrow" : sign;
|
||||
|
||||
// Set sorting algorithm
|
||||
if (customSort == 'default')
|
||||
customSort = defaultSortEngine;
|
||||
sortEngine = customSort || sortEngine || defaultSortEngine;
|
||||
|
||||
// Set attributes needed for sorting
|
||||
$('table.sortable').each(function () {
|
||||
var $this = $(this);
|
||||
applyLast = (applyLast === true);
|
||||
$this.find('span.sign').remove();
|
||||
|
||||
// Add placeholder cells for colspans
|
||||
$this.find('thead [colspan]').each(function () {
|
||||
var colspan = parseFloat($(this).attr('colspan'));
|
||||
for (var i = 1; i < colspan; i++) {
|
||||
$(this).after('<th class="colspan-compensate">');
|
||||
}
|
||||
});
|
||||
|
||||
// Add placeholder cells for rowspans
|
||||
$this.find('thead [rowspan]').each(function () {
|
||||
var $cell = $(this);
|
||||
var rowspan = parseFloat($cell.attr('rowspan'));
|
||||
for (var i = 1; i < rowspan; i++) {
|
||||
var parentRow = $cell.parent('tr');
|
||||
var nextRow = parentRow.next('tr');
|
||||
var index = parentRow.children().index($cell);
|
||||
nextRow.children().eq(index).before('<th class="rowspan-compensate">');
|
||||
}
|
||||
});
|
||||
|
||||
// Set indexes to header cells
|
||||
$this.find('thead tr').each(function (rowIndex) {
|
||||
$(this).find('th').each(function (columnIndex) {
|
||||
var $this = $(this);
|
||||
$this.addClass('nosort').removeClass('up down');
|
||||
$this.attr('data-sortcolumn', columnIndex);
|
||||
$this.attr('data-sortkey', columnIndex + '-' + rowIndex);
|
||||
});
|
||||
});
|
||||
|
||||
// Cleanup placeholder cells
|
||||
$this.find('thead .rowspan-compensate, .colspan-compensate').remove();
|
||||
|
||||
// Initialize sorting values
|
||||
$this.find('td').each(function () {
|
||||
var $this = $(this);
|
||||
if ($this.attr('data-dateformat') !== undefined && momentJsAvailable) {
|
||||
$this.attr('data-value', moment($this.text(), $this.attr('data-dateformat')).format('YYYY/MM/DD/HH/mm/ss'));
|
||||
}
|
||||
else {
|
||||
$this.attr('data-value') === undefined && $this.attr('data-value', $this.text());
|
||||
}
|
||||
});
|
||||
|
||||
var context = lookupSortContext($this),
|
||||
bsSort = context.bsSort;
|
||||
|
||||
$this.find('thead th[data-defaultsort!="disabled"]').each(function (index) {
|
||||
var $this = $(this);
|
||||
var $sortTable = $this.closest('table.sortable');
|
||||
$this.data('sortTable', $sortTable);
|
||||
var sortKey = $this.attr('data-sortkey');
|
||||
var thisLastSort = applyLast ? context.lastSort : -1;
|
||||
bsSort[sortKey] = applyLast ? bsSort[sortKey] : $this.attr('data-defaultsort');
|
||||
if (bsSort[sortKey] !== undefined && (applyLast === (sortKey === thisLastSort))) {
|
||||
bsSort[sortKey] = bsSort[sortKey] === 'asc' ? 'desc' : 'asc';
|
||||
doSort($this, $sortTable);
|
||||
}
|
||||
});
|
||||
$this.trigger('sorted');
|
||||
});
|
||||
};
|
||||
|
||||
// Add click event to table header
|
||||
$document.on('click', 'table.sortable thead th[data-defaultsort!="disabled"]', function (e) {
|
||||
var $this = $(this), $table = $this.data('sortTable') || $this.closest('table.sortable');
|
||||
$table.trigger('before-sort');
|
||||
doSort($this, $table);
|
||||
$table.trigger('sorted');
|
||||
});
|
||||
|
||||
// Look up sorting data appropriate for the specified table (jQuery element).
|
||||
// This allows multiple tables on one page without collisions.
|
||||
function lookupSortContext($table) {
|
||||
var context = $table.data("bootstrap-sortable-context");
|
||||
if (context === undefined) {
|
||||
context = { bsSort: [], lastSort: undefined };
|
||||
$table.find('thead th[data-defaultsort!="disabled"]').each(function (index) {
|
||||
var $this = $(this);
|
||||
var sortKey = $this.attr('data-sortkey');
|
||||
context.bsSort[sortKey] = $this.attr('data-defaultsort');
|
||||
if (context.bsSort[sortKey] !== undefined) {
|
||||
context.lastSort = sortKey;
|
||||
}
|
||||
});
|
||||
$table.data("bootstrap-sortable-context", context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
function defaultSortEngine(rows, sortingParams) {
|
||||
tinysort(rows, sortingParams);
|
||||
}
|
||||
|
||||
// Sorting mechanism separated
|
||||
function doSort($this, $table) {
|
||||
var sortColumn = parseFloat($this.attr('data-sortcolumn')),
|
||||
context = lookupSortContext($table),
|
||||
bsSort = context.bsSort;
|
||||
|
||||
var colspan = $this.attr('colspan');
|
||||
if (colspan) {
|
||||
var mainSort = parseFloat($this.data('mainsort')) || 0;
|
||||
var rowIndex = parseFloat($this.data('sortkey').split('-').pop());
|
||||
|
||||
// If there is one more row in header, delve deeper
|
||||
if ($table.find('thead tr').length - 1 > rowIndex) {
|
||||
doSort($table.find('[data-sortkey="' + (sortColumn + mainSort) + '-' + (rowIndex + 1) + '"]'), $table);
|
||||
return;
|
||||
}
|
||||
// Otherwise, just adjust the sortColumn
|
||||
sortColumn = sortColumn + mainSort;
|
||||
}
|
||||
|
||||
var localSignClass = $this.attr('data-defaultsign') || signClass;
|
||||
|
||||
// update arrow icon
|
||||
$table.find('th').each(function () {
|
||||
$(this).removeClass('up').removeClass('down').addClass('nosort');
|
||||
});
|
||||
|
||||
if ($.browser.mozilla) {
|
||||
var moz_arrow = $table.find('div.mozilla');
|
||||
if (moz_arrow !== undefined) {
|
||||
moz_arrow.find('.sign').remove();
|
||||
moz_arrow.parent().html(moz_arrow.html());
|
||||
}
|
||||
$this.wrapInner('<div class="mozilla"></div>');
|
||||
$this.children().eq(0).append('<span class="sign ' + localSignClass + '"></span>');
|
||||
}
|
||||
else {
|
||||
$table.find('span.sign').remove();
|
||||
$this.append('<span class="sign ' + localSignClass + '"></span>');
|
||||
}
|
||||
|
||||
// sort direction
|
||||
var sortKey = $this.attr('data-sortkey');
|
||||
var initialDirection = $this.attr('data-firstsort') !== 'desc' ? 'desc' : 'asc';
|
||||
|
||||
context.lastSort = sortKey;
|
||||
bsSort[sortKey] = (bsSort[sortKey] || initialDirection) === 'asc' ? 'desc' : 'asc';
|
||||
if (bsSort[sortKey] === 'desc') {
|
||||
$this.find('span.sign').addClass('up');
|
||||
$this.addClass('up').removeClass('down nosort');
|
||||
} else {
|
||||
$this.addClass('down').removeClass('up nosort');
|
||||
}
|
||||
|
||||
// sort rows
|
||||
var rows = $table.children('tbody').children('tr');
|
||||
sortEngine(rows, { selector: 'td:nth-child(' + (sortColumn + 1) + ')', order: bsSort[sortKey], data: 'value' });
|
||||
|
||||
// add class to sorted column cells
|
||||
$table.find('td.sorted, th.sorted').removeClass('sorted');
|
||||
rows.find('td:eq(' + sortColumn + ')').addClass('sorted');
|
||||
$this.addClass('sorted');
|
||||
}
|
||||
|
||||
// jQuery 1.9 removed this object
|
||||
if (!$.browser) {
|
||||
$.browser = { chrome: false, mozilla: false, opera: false, msie: false, safari: false };
|
||||
var ua = navigator.userAgent;
|
||||
$.each($.browser, function (c) {
|
||||
$.browser[c] = ((new RegExp(c, 'i').test(ua))) ? true : false;
|
||||
if ($.browser.mozilla && c === 'mozilla') { $.browser.mozilla = ((new RegExp('firefox', 'i').test(ua))) ? true : false; }
|
||||
if ($.browser.chrome && c === 'safari') { $.browser.safari = false; }
|
||||
});
|
||||
}
|
||||
|
||||
// Initialise on DOM ready
|
||||
$($.bootstrapSortable);
|
||||
|
||||
}(jQuery));
|
||||
1
public/js/bootstrap-tagsinput.min.js.map
Executable file
1
public/js/bootstrap-tagsinput.min.js.map
Executable file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"dist/bootstrap-tagsinput-angular.min.js","sources":["src/bootstrap-tagsinput-angular.js"],"names":["angular","module","directive","getItemProperty","scope","property","isFunction","$parent","item","undefined","restrict","model","template","replace","link","element","attrs","$","isArray","select","typeaheadSourceArray","typeaheadSource","split","length","tagsinput","options","typeahead","source","itemValue","itemvalue","itemText","itemtext","confirmKeys","confirmkeys","JSON","parse","tagClass","tagclass","i","on","event","indexOf","push","idx","splice","prev","slice","$watch","added","filter","removed"],"mappings":";;;;;AAAAA,QAAQC,OAAO,0BACdC,UAAU,sBAAuB,WAEhC,QAASC,GAAgBC,EAAOC,GAC9B,MAAKA,GAGDL,QAAQM,WAAWF,EAAMG,QAAQF,IAC5BD,EAAMG,QAAQF,GAEhB,SAASG,GACd,MAAOA,GAAKH,IANLI,OAUX,OACEC,SAAU,KACVN,OACEO,MAAO,YAETC,SAAU,6BACVC,SAAS,EACTC,KAAM,SAASV,EAAOW,EAASC,GAC7BC,EAAE,WACKjB,QAAQkB,QAAQd,EAAMO,SACzBP,EAAMO,SAER,IAAIQ,GAASF,EAAE,SAAUF,GACrBK,EAAuBJ,EAAMK,gBAAkBL,EAAMK,gBAAgBC,MAAM,KAAO,KAClFD,EAAkBD,EACjBA,EAAqBG,OAAS,EAC3BnB,EAAMG,QAAQa,EAAqB,IAAIA,EAAqB,IAC1DhB,EAAMG,QAAQa,EAAqB,IACvC,IAEND,GAAOK,UAAUpB,EAAMG,QAAQS,EAAMS,SAAW,MAC9CC,WACEC,OAAW3B,QAAQM,WAAWe,GAAmBA,EAAkB,MAErEO,UAAWzB,EAAgBC,EAAOY,EAAMa,WACxCC,SAAW3B,EAAgBC,EAAOY,EAAMe,UACxCC,YAAc7B,EAAgBC,EAAOY,EAAMiB,aAAeC,KAAKC,MAAMnB,EAAMiB,cAAgB,IAC3FG,SAAWpC,QAAQM,WAAWF,EAAMG,QAAQS,EAAMqB,WAAajC,EAAMG,QAAQS,EAAMqB,UAAY,WAAiB,MAAOrB,GAAMqB,WAG/H,KAAK,GAAIC,GAAI,EAAGA,EAAIlC,EAAMO,MAAMY,OAAQe,IACtCnB,EAAOK,UAAU,MAAOpB,EAAMO,MAAM2B,GAGtCnB,GAAOoB,GAAG,YAAa,SAASC,GACU,KAApCpC,EAAMO,MAAM8B,QAAQD,EAAMhC,OAC5BJ,EAAMO,MAAM+B,KAAKF,EAAMhC,QAG3BW,EAAOoB,GAAG,cAAe,SAASC,GAChC,GAAIG,GAAMvC,EAAMO,MAAM8B,QAAQD,EAAMhC,KACxB,MAARmC,GACFvC,EAAMO,MAAMiC,OAAOD,EAAK,IAK5B,IAAIE,GAAOzC,EAAMO,MAAMmC,OACvB1C,GAAM2C,OAAO,QAAS,WACpB,GAEIT,GAFAU,EAAQ5C,EAAMO,MAAMsC,OAAO,SAASX,GAAI,MAA2B,KAApBO,EAAKJ,QAAQH,KAC5DY,EAAUL,EAAKI,OAAO,SAASX,GAAI,MAAkC,KAA3BlC,EAAMO,MAAM8B,QAAQH,IAMlE,KAHAO,EAAOzC,EAAMO,MAAMmC,QAGdR,EAAI,EAAGA,EAAIY,EAAQ3B,OAAQe,IAC9BnB,EAAOK,UAAU,SAAU0B,EAAQZ,GAOrC,KAHAnB,EAAOK,UAAU,WAGZc,EAAI,EAAGA,EAAIU,EAAMzB,OAAQe,IAC5BnB,EAAOK,UAAU,MAAOwB,EAAMV,MAE/B"}
|
||||
@@ -3,18 +3,18 @@ google.setOnLoadCallback(drawChart);
|
||||
|
||||
function drawChart() {
|
||||
googleLineChart('chart/home/account', 'accounts-chart');
|
||||
googleBarChart('chart/home/budgets', 'budgets-chart');
|
||||
googleColumnChart('chart/home/budgets', 'budgets-chart');
|
||||
googleColumnChart('chart/home/categories', 'categories-chart');
|
||||
googlePieChart('chart/home/bills', 'bills-chart');
|
||||
getBoxAmounts();
|
||||
}
|
||||
|
||||
function getBoxAmounts() {
|
||||
var boxes = ['in', 'out','bills-unpaid','bills-paid'];
|
||||
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) {
|
||||
$.getJSON('/json/box/' + box).success(function (data) {
|
||||
if (data.amount_raw != 0) {
|
||||
$('#box-' + data.box).html(data.amount);
|
||||
}
|
||||
}).fail(function () {
|
||||
|
||||
@@ -5,14 +5,43 @@ $(function () {
|
||||
if (typeof(googleLineChart) === 'function' && typeof(piggyBankID) !== 'undefined') {
|
||||
googleLineChart('chart/piggy-history/' + piggyBankID, 'piggy-bank-history');
|
||||
}
|
||||
$('#sortable').sortable(
|
||||
|
||||
$('#sortable tbody').sortable(
|
||||
{
|
||||
helper: fixHelper,
|
||||
stop: stopSorting,
|
||||
handle: '.handle'
|
||||
handle: '.handle',
|
||||
start: function (event, ui) {
|
||||
// Build a placeholder cell that spans all the cells in the row
|
||||
var cellCount = 0;
|
||||
$('td, th', ui.helper).each(function () {
|
||||
// For each TD or TH try and get it's colspan attribute, and add that or 1 to the total
|
||||
var colspan = 1;
|
||||
var colspanAttr = $(this).attr('colspan');
|
||||
if (colspanAttr > 1) {
|
||||
colspan = colspanAttr;
|
||||
}
|
||||
cellCount += colspan;
|
||||
});
|
||||
|
||||
// Add the placeholder UI - note that this is the item's content, so TD rather than TR
|
||||
ui.placeholder.html('<td colspan="' + cellCount + '"> </td>');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Return a helper with preserved width of cells
|
||||
var fixHelper = function(e, tr) {
|
||||
var $originals = tr.children();
|
||||
var $helper = tr.clone();
|
||||
$helper.children().each(function (index) {
|
||||
// Set helper cell sizes to match the original sizes
|
||||
$(this).width($originals.eq(index).width());
|
||||
});
|
||||
return $helper;
|
||||
}
|
||||
|
||||
function addMoney(e) {
|
||||
var pigID = parseInt($(e.target).data('id'));
|
||||
$('#moneyManagementModal').empty().load('piggy-banks/add/' + pigID, function () {
|
||||
@@ -33,7 +62,7 @@ function removeMoney(e) {
|
||||
function stopSorting() {
|
||||
$('.loadSpin').addClass('fa fa-refresh fa-spin');
|
||||
var order = [];
|
||||
$.each($('#sortable>div'), function(i,v) {
|
||||
$.each($('#sortable>tbody>tr'), function(i,v) {
|
||||
var holder = $(v);
|
||||
var id = holder.data('id');
|
||||
order.push(id);
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
$(document).ready(function () {
|
||||
$('.relateTransaction').click(relateTransactionDialog);
|
||||
//$('.unrelate-checkbox').click(unrelateTransaction);
|
||||
|
||||
});
|
||||
|
||||
function unrelateTransaction(e) {
|
||||
var target = $(e.target);
|
||||
var id = target.data('id');
|
||||
var parent = target.data('parent');
|
||||
|
||||
if(typeof id == "undefined" && typeof parent == "undefined") {
|
||||
target = target.parent();
|
||||
id = target.data('id');
|
||||
parent = target.data('parent');
|
||||
}
|
||||
console.log('unlink ' + id + ' from ' + parent);
|
||||
|
||||
$.post('related/removeRelation/' + id + '/' + parent, {_token: token}).success(function (data) {
|
||||
target.parent().parent().remove();
|
||||
}).fail(function () {
|
||||
alert('Could not!');
|
||||
});
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
//$.post('related/removeRelation/' + id + '/' + relatedTo, {_token: token}).success(function (data) {
|
||||
// target.parent().parent().remove();
|
||||
//}).fail(function () {
|
||||
// alert('Could not!');
|
||||
//});
|
||||
|
||||
}
|
||||
|
||||
function relateTransactionDialog(e) {
|
||||
var target = $(e.target);
|
||||
var ID = target.data('id');
|
||||
|
||||
|
||||
$('#relationModal').empty().load('related/related/' + ID, function () {
|
||||
|
||||
$('#relationModal').modal('show');
|
||||
getAlreadyRelatedTransactions(e, ID);
|
||||
$('#searchRelated').submit(function (e) {
|
||||
searchRelatedTransactions(e, ID);
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function searchRelatedTransactions(e, ID) {
|
||||
var searchValue = $('#relatedSearchValue').val();
|
||||
if (searchValue != '') {
|
||||
$.post('related/search/' + ID, {searchValue: searchValue, _token: token}).success(function (data) {
|
||||
// post the results to some div.
|
||||
$('#relatedSearchResultsTitle').show();
|
||||
$('#relatedSearchResults').empty().html(data);
|
||||
// remove any clicks.
|
||||
$('.relate').unbind('click').on('click', doRelateNewTransaction);
|
||||
|
||||
}).fail(function () {
|
||||
alert('Could not search. Sorry.');
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function doRelateNewTransaction(e) {
|
||||
// remove the row from the table:
|
||||
var target = $(e.target);
|
||||
var id = target.data('id');
|
||||
var parent = target.data('parent');
|
||||
|
||||
if (typeof id == "undefined" && typeof parent == "undefined") {
|
||||
target = target.parent();
|
||||
console.log(target);
|
||||
id = target.data('id');
|
||||
parent = target.data('parent');
|
||||
}
|
||||
|
||||
console.log('Relate ' + id + ' to ' + parent);
|
||||
$.post('related/relate/' + parent + '/' + id, {_token: token}).success(function (data) {
|
||||
// success! remove entry:
|
||||
target.parent().parent().remove();
|
||||
// get related stuff (again).
|
||||
getAlreadyRelatedTransactions(null, parent);
|
||||
}).fail(function () {
|
||||
// could not relate.
|
||||
alert('Could not relate this transaction to the intended target.');
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
function getAlreadyRelatedTransactions(e, ID) {
|
||||
//#alreadyRelated
|
||||
$.get('related/alreadyRelated/' + ID).success(function (data) {
|
||||
$('#alreadyRelated').empty().html(data);
|
||||
// some event triggers.
|
||||
$('.unrelate').unbind('click').on('click', unrelateTransaction);
|
||||
|
||||
}).fail(function () {
|
||||
alert('Cannot get related stuff.');
|
||||
});
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user