firefly-iii/app/Repositories/Account/AccountRepository.php

455 lines
14 KiB
PHP
Raw Normal View History

2015-02-09 00:23:39 -06:00
<?php
namespace FireflyIII\Repositories\Account;
use App;
2015-02-21 05:16:41 -06:00
use Auth;
use Carbon\Carbon;
2015-02-09 00:56:24 -06:00
use Config;
2015-02-09 00:23:39 -06:00
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
2015-02-09 00:23:39 -06:00
use FireflyIII\Models\AccountType;
2015-02-24 14:10:25 -06:00
use FireflyIII\Models\PiggyBank;
2015-03-13 02:44:07 -05:00
use FireflyIII\Models\Preference;
2015-02-09 00:56:24 -06:00
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
2015-02-21 05:16:41 -06:00
use Illuminate\Pagination\LengthAwarePaginator;
2015-03-13 02:44:07 -05:00
use Illuminate\Support\Collection;
use Log;
2015-02-21 05:16:41 -06:00
use Session;
2015-03-21 02:51:34 -05:00
use Steam;
2015-02-09 00:23:39 -06:00
/**
* Class AccountRepository
*
* @package FireflyIII\Repositories\Account
*/
class AccountRepository implements AccountRepositoryInterface
{
2015-03-13 02:44:07 -05:00
/**
* @return int
*/
public function countAssetAccounts()
{
return Auth::user()->accounts()->accountTypeIn(['Asset account', 'Default account'])->count();
}
/**
* @param Account $account
*
* @return boolean
*/
public function destroy(Account $account)
{
$account->delete();
return true;
}
2015-03-13 02:44:07 -05:00
/**
* @param Preference $preference
*
* @return Collection
*/
public function getFrontpageAccounts(Preference $preference)
{
if ($preference->data == []) {
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
} else {
$accounts = Auth::user()->accounts()->whereIn('id', $preference->data)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
}
return $accounts;
}
/**
2015-03-20 16:39:07 -05:00
* This method is used on the front page where (in turn) its viewed journals-tiny.php which (in turn)
* is almost the only place where formatJournal is used. Aka, we can use some custom querying to get some specific.
* fields using left joins.
*
2015-03-13 02:44:07 -05:00
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end)
{
return Auth::user()
->transactionjournals()
2015-03-20 16:39:07 -05:00
->with(['transactions'])
2015-03-13 02:44:07 -05:00
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id)
2015-03-20 16:39:07 -05:00
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transaction_journals.transaction_currency_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
2015-03-13 02:44:07 -05:00
->before($end)
->after($start)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC')
->take(10)
2015-03-20 16:39:07 -05:00
->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']);
2015-03-13 02:44:07 -05:00
}
2015-02-21 05:16:41 -06:00
/**
* @param Account $account
* @param int $page
*
* @return mixed
*/
2015-03-02 13:05:28 -06:00
public function getJournals(Account $account, $page)
2015-02-21 05:16:41 -06:00
{
$offset = ($page - 1) * 50;
2015-02-21 05:16:41 -06:00
$query = Auth::user()
->transactionJournals()
2015-02-22 01:38:46 -06:00
->withRelevantData()
2015-02-21 05:16:41 -06:00
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
2015-03-27 01:32:06 -05:00
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order','ASC')
->orderBy('transaction_journals.id','DESC');
2015-02-21 05:16:41 -06:00
2015-03-02 13:05:28 -06:00
$query->before(Session::get('end', Carbon::now()->endOfMonth()));
$query->after(Session::get('start', Carbon::now()->startOfMonth()));
2015-02-23 14:55:52 -06:00
$count = $query->count();
$set = $query->take(50)->offset($offset)->get(['transaction_journals.*']);
$paginator = new LengthAwarePaginator($set, $count, 50, $page);
2015-02-22 01:38:46 -06:00
2015-02-21 05:16:41 -06:00
return $paginator;
}
2015-03-21 02:51:34 -05:00
/**
* Get savings accounts and the balance difference in the period.
*
* @return Collection
*/
public function getSavingsAccounts()
{
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
->where('account_meta.name', 'accountRole')
->where('account_meta.data', '"savingAsset"')
->get(['accounts.*']);
$start = clone Session::get('start');
$end = clone Session::get('end');
$accounts->each(
function (Account $account) use ($start, $end) {
$account->startBalance = Steam::balance($account, $start);
$account->endBalance = Steam::balance($account, $end);
// diff (negative when lost, positive when gained)
$diff = $account->endBalance - $account->startBalance;
2015-03-21 02:55:55 -05:00
if ($diff < 0 && $account->startBalance > 0) {
2015-03-21 02:51:34 -05:00
// percentage lost compared to start.
$pct = (($diff * -1) / $account->startBalance) * 100;
} else {
2015-03-21 02:55:55 -05:00
if ($diff >= 0 && $account->startBalance > 0) {
$pct = ($diff / $account->startBalance) * 100;
} else {
2015-03-21 02:56:24 -05:00
$pct = 100;
2015-03-21 02:55:55 -05:00
}
2015-03-21 02:51:34 -05:00
}
2015-03-21 02:55:55 -05:00
$pct = $pct > 100 ? 100 : $pct;
2015-03-21 02:51:34 -05:00
$account->difference = $diff;
$account->percentage = round($pct);
}
);
return $accounts;
}
/**
* @param Account $account
*
* @return float
*/
public function leftOnAccount(Account $account)
{
$balance = \Steam::balance($account);
/** @var PiggyBank $p */
foreach ($account->piggybanks()->get() as $p) {
$balance -= $p->currentRelevantRep()->currentamount;
}
return $balance;
}
/**
* @param Account $account
*
* @return TransactionJournal|null
*/
public function openingBalanceTransaction(Account $account)
{
return TransactionJournal::accountIs($account)
->orderBy('transaction_journals.date', 'ASC')
->orderBy('created_at', 'ASC')
->first(['transaction_journals.*']);
}
2015-02-09 00:23:39 -06:00
/**
* @param array $data
*
* @return Account;
*/
public function store(array $data)
{
$newAccount = $this->_store($data);
$this->_storeMetadata($newAccount, $data);
2015-02-09 00:23:39 -06:00
// continue with the opposing account:
if ($data['openingBalance'] != 0) {
2015-02-09 00:56:24 -06:00
$type = $data['openingBalance'] < 0 ? 'expense' : 'revenue';
$opposingData = [
2015-02-09 00:23:39 -06:00
'user' => $data['user'],
'accountType' => $type,
'name' => $data['name'] . ' initial balance',
'active' => false,
];
2015-02-09 00:56:24 -06:00
$opposing = $this->_store($opposingData);
$this->_storeInitialBalance($newAccount, $opposing, $data);
2015-02-09 00:23:39 -06:00
}
return $newAccount;
}
/**
* @param Account $account
* @param array $data
*/
public function update(Account $account, array $data)
{
// update the account:
$account->name = $data['name'];
$account->active = $data['active'] == '1' ? true : false;
$account->save();
// update meta data:
$this->_updateMetadata($account, $data);
$openingBalance = $this->openingBalanceTransaction($account);
// if has openingbalance?
if ($data['openingBalance'] != 0) {
// if opening balance, do an update:
if ($openingBalance) {
// update existing opening balance.
$this->_updateInitialBalance($account, $openingBalance, $data);
} else {
// create new opening balance.
$type = $data['openingBalance'] < 0 ? 'expense' : 'revenue';
$opposingData = [
'user' => $data['user'],
'accountType' => $type,
'name' => $data['name'] . ' initial balance',
'active' => false,
];
$opposing = $this->_store($opposingData);
$this->_storeInitialBalance($account, $opposing, $data);
}
} else {
// opening balance is zero, should we delete it?
if ($openingBalance) {
// delete existing opening balance.
$openingBalance->delete();
}
}
return $account;
}
2015-02-09 00:23:39 -06:00
/**
* @param array $data
2015-02-09 00:56:24 -06:00
*
* @return Account
2015-02-09 00:23:39 -06:00
*/
protected function _store(array $data)
{
2015-02-09 00:56:24 -06:00
$type = Config::get('firefly.accountTypeByIdentifier.' . $data['accountType']);
$accountType = AccountType::whereType($type)->first();
2015-02-09 00:23:39 -06:00
$newAccount = new Account(
[
'user_id' => $data['user'],
'account_type_id' => $accountType->id,
'name' => $data['name'],
'active' => $data['active'] === true ? true : false,
]
);
2015-03-26 12:05:23 -05:00
2015-02-09 00:23:39 -06:00
if (!$newAccount->isValid()) {
// does the account already exist?
$existingAccount = Account::where('user_id', $data['user'])->where('account_type_id', $accountType->id)->where('name', $data['name'])->first();
if (!$existingAccount) {
Log::error('Account create error: ' . $newAccount->getErrors()->toJson());
2015-03-26 12:05:23 -05:00
App::abort(500);
}
$newAccount = $existingAccount;
2015-02-09 00:23:39 -06:00
}
$newAccount->save();
2015-02-09 00:56:24 -06:00
return $newAccount;
}
/**
* @param Account $account
* @param array $data
*/
protected function _storeMetadata(Account $account, array $data)
{
$metaData = new AccountMeta(
[
'account_id' => $account->id,
'name' => 'accountRole',
'data' => $data['accountRole']
]
);
if (!$metaData->isValid()) {
App::abort(500);
}
$metaData->save();
}
2015-02-09 00:56:24 -06:00
/**
* @param Account $account
* @param Account $opposing
* @param array $data
2015-02-11 00:35:10 -06:00
*
* @return TransactionJournal
2015-02-09 00:56:24 -06:00
*/
protected function _storeInitialBalance(Account $account, Account $opposing, array $data)
{
$type = $data['openingBalance'] < 0 ? 'Withdrawal' : 'Deposit';
$transactionType = TransactionType::whereType($type)->first();
$journal = new TransactionJournal(
[
'user_id' => $data['user'],
'transaction_type_id' => $transactionType->id,
'bill_id' => null,
'transaction_currency_id' => $data['openingBalanceCurrency'],
'description' => 'Initial balance for "' . $account->name . '"',
'completed' => true,
'date' => $data['openingBalanceDate'],
'encrypted' => true
]
);
if (!$journal->isValid()) {
App::abort(500);
}
$journal->save();
if ($data['openingBalance'] < 0) {
$firstAccount = $opposing;
$secondAccount = $account;
$firstAmount = $data['openingBalance'] * -1;
$secondAmount = $data['openingBalance'];
} else {
$firstAccount = $account;
$secondAccount = $opposing;
$firstAmount = $data['openingBalance'];
$secondAmount = $data['openingBalance'] * -1;
}
// first transaction: from
$one = new Transaction(
[
'account_id' => $firstAccount->id,
'transaction_journal_id' => $journal->id,
'amount' => $firstAmount
]
);
if (!$one->isValid()) {
App::abort(500);
}
$one->save();
// second transaction: to
$two = new Transaction(
[
'account_id' => $secondAccount->id,
'transaction_journal_id' => $journal->id,
'amount' => $secondAmount
]
);
if (!$two->isValid()) {
App::abort(500);
}
$two->save();
return $journal;
2015-02-09 00:23:39 -06:00
}
2015-02-24 14:10:25 -06:00
/**
* @param Account $account
* @param array $data
2015-02-24 14:10:25 -06:00
*/
protected function _updateMetadata(Account $account, array $data)
2015-02-24 14:10:25 -06:00
{
$metaEntries = $account->accountMeta()->get();
$updated = false;
/** @var AccountMeta $entry */
foreach ($metaEntries as $entry) {
if ($entry->name == 'accountRole') {
$entry->data = $data['accountRole'];
$updated = true;
$entry->save();
}
2015-02-24 14:10:25 -06:00
}
if ($updated === false) {
$metaData = new AccountMeta(
[
'account_id' => $account->id,
'name' => 'accountRole',
'data' => $data['accountRole']
]
);
if (!$metaData->isValid()) {
App::abort(500);
}
$metaData->save();
}
2015-02-24 14:10:25 -06:00
}
2015-03-02 13:05:28 -06:00
/**
* @param Account $account
* @param TransactionJournal $journal
* @param array $data
*
* @return TransactionJournal
*/
protected function _updateInitialBalance(Account $account, TransactionJournal $journal, array $data)
{
$journal->date = $data['openingBalanceDate'];
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($account->id == $transaction->account_id) {
$transaction->amount = $data['openingBalance'];
$transaction->save();
}
if ($account->id != $transaction->account_id) {
$transaction->amount = $data['openingBalance'] * -1;
$transaction->save();
}
}
return $journal;
}
2015-02-09 00:23:39 -06:00
}