mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-19 02:45:58 +00:00
598 lines
20 KiB
PHP
598 lines
20 KiB
PHP
<?php
|
|
|
|
|
|
namespace Firefly\Storage\TransactionJournal;
|
|
|
|
use Carbon\Carbon;
|
|
use Illuminate\Queue\Jobs\Job;
|
|
use Illuminate\Support\MessageBag;
|
|
|
|
/**
|
|
* Class EloquentTransactionJournalRepository
|
|
*
|
|
* @package Firefly\Storage\TransactionJournal
|
|
*/
|
|
class EloquentTransactionJournalRepository implements TransactionJournalRepositoryInterface
|
|
{
|
|
protected $_user = null;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->_user = \Auth::user();
|
|
}
|
|
|
|
/**
|
|
* @param Job $job
|
|
* @param array $payload
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function importTransfer(Job $job, array $payload)
|
|
{
|
|
/** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */
|
|
$repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface');
|
|
|
|
/** @var \Importmap $importMap */
|
|
$importMap = $repository->findImportmap($payload['mapID']);
|
|
$user = $importMap->user;
|
|
$this->overruleUser($user);
|
|
|
|
|
|
if ($job->attempts() > 10) {
|
|
\Log::error('Never found accounts for transfer "' . $payload['data']['description'] . '". KILL!');
|
|
|
|
$importMap->jobsdone++;
|
|
$importMap->save();
|
|
|
|
$job->delete(); // count fixed
|
|
return;
|
|
}
|
|
|
|
/** @var \Firefly\Helper\Controllers\TransactionInterface $transactions */
|
|
$transactions = \App::make('Firefly\Helper\Controllers\TransactionInterface');
|
|
$transactions->overruleUser($this->_user);
|
|
|
|
/*
|
|
* Prep some variables from the payload:
|
|
*/
|
|
$fromAccountId = intval($payload['data']['accountfrom_id']);
|
|
$toAccountId = intval($payload['data']['accountto_id']);
|
|
$description = $payload['data']['description'];
|
|
$transferId = intval($payload['data']['id']);
|
|
$amount = floatval($payload['data']['amount']);
|
|
$date = new Carbon($payload['data']['date']);
|
|
|
|
/*
|
|
* maybe Journal is already imported:
|
|
*/
|
|
$importEntry = $repository->findImportEntry($importMap, 'Transfer', $transferId);
|
|
|
|
/*
|
|
* if so, delete job and return:
|
|
*/
|
|
if (!is_null($importEntry)) {
|
|
\Log::debug('Already imported transfer ' . $description);
|
|
|
|
$importMap->jobsdone++;
|
|
$importMap->save();
|
|
|
|
$job->delete(); // count fixed
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Find the 'from' account:
|
|
*/
|
|
$oldFromAccountEntry = $repository->findImportEntry($importMap, 'Account', $fromAccountId);
|
|
|
|
/*
|
|
* Find the 'to' account:
|
|
*/
|
|
$oldToAccountEntry = $repository->findImportEntry($importMap, 'Account', $toAccountId);
|
|
|
|
/*
|
|
* Import transfer:
|
|
*/
|
|
$set = [
|
|
'account_from_id' => $oldFromAccountEntry->new,
|
|
'account_to_id' => $oldToAccountEntry->new,
|
|
'amount' => $amount,
|
|
'description' => $description,
|
|
'date' => $date->format('Y-m-d'),
|
|
'category' => '',
|
|
'what' => 'transfer',
|
|
'return_journal' => true
|
|
];
|
|
$journal = $transactions->store($set);
|
|
|
|
/*
|
|
* Validate the store action:
|
|
*/
|
|
if ($journal instanceof MessageBag) {
|
|
/*
|
|
* It's a message bag; clearly something went wrong.
|
|
*/
|
|
\Log::notice('Could not import TJ "' . $description . '": ' . $journal->first());
|
|
if (\Config::get('queue.default') == 'sync') {
|
|
$importMap->jobsdone++;
|
|
$importMap->save();
|
|
$job->delete(); // count fixed
|
|
} else {
|
|
$job->release(300); // proper release.
|
|
}
|
|
return;
|
|
} else if ($journal instanceof \TransactionJournal && $journal->errors()->count() > 0) {
|
|
/*
|
|
* It's a journal but it still failed somehow.
|
|
*/
|
|
\Log::notice('Could not import TJ "' . $description . '": ' . $journal->errors()->first());
|
|
if (\Config::get('queue.default') == 'sync') {
|
|
$importMap->jobsdone++;
|
|
$importMap->save();
|
|
$job->delete(); // count fixed
|
|
} else {
|
|
$job->release(300); // proper release.
|
|
}
|
|
return;
|
|
}
|
|
$repository->store($importMap, 'Transfer', $transferId, $journal->id);
|
|
\Log::debug('Imported transfer "' . $description . '" (' . $amount . ') (' . $date->format('Y-m-d') . ')');
|
|
|
|
// update map:
|
|
$importMap->jobsdone++;
|
|
$importMap->save();
|
|
|
|
$job->delete(); // count fixed.
|
|
|
|
}
|
|
|
|
/**
|
|
* @param \User $user
|
|
*
|
|
* @return mixed|void
|
|
*/
|
|
public function overruleUser(\User $user)
|
|
{
|
|
$this->_user = $user;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @param array $data
|
|
*
|
|
* @return \TransactionJournal
|
|
*/
|
|
public function store(array $data)
|
|
{
|
|
/*
|
|
* Create the journal and fill relevant fields.
|
|
*/
|
|
$journal = new \TransactionJournal;
|
|
$journal->description = trim($data['description']);
|
|
$journal->date = new Carbon($data['date']);
|
|
$journal->user_id = $this->_user->id;
|
|
$journal->completed = false;
|
|
|
|
/*
|
|
* Find the more complex fields and fill those:
|
|
*/
|
|
$currency = \TransactionCurrency::where('code', 'EUR')->first();
|
|
$journal->transaction_currency_id = $currency->id;
|
|
$transactionType = \TransactionType::where('type', $data['what'])->first();
|
|
$journal->transaction_type_id = $transactionType->id;
|
|
|
|
/*
|
|
* Validatre & save journal
|
|
*/
|
|
$journal->validate();
|
|
$journal->save();
|
|
|
|
/*
|
|
* Return regardless.
|
|
*/
|
|
return $journal;
|
|
}
|
|
|
|
/**
|
|
* @param \TransactionJournal $journal
|
|
* @param \Account $account
|
|
* @param $amount
|
|
*
|
|
* @return \Transaction|null
|
|
*/
|
|
public function saveTransaction(\TransactionJournal $journal, \Account $account, $amount)
|
|
{
|
|
$transaction = new \Transaction;
|
|
$transaction->account_id = $account->id;
|
|
$transaction->transaction_journal_id = $journal->id;
|
|
$transaction->amount = $amount;
|
|
if ($transaction->validate()) {
|
|
$transaction->save();
|
|
}
|
|
return $transaction;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @param Job $job
|
|
* @param array $payload
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function importTransaction(Job $job, array $payload)
|
|
{
|
|
/** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */
|
|
$repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface');
|
|
|
|
/** @var \Importmap $importMap */
|
|
$importMap = $repository->findImportmap($payload['mapID']);
|
|
$user = $importMap->user;
|
|
$this->overruleUser($user);
|
|
|
|
if ($job->attempts() > 10) {
|
|
\Log::error('Never found asset account for transaction "' . $payload['data']['description'] . '". KILL!');
|
|
|
|
$importMap->jobsdone++;
|
|
$importMap->save();
|
|
|
|
$job->delete(); // count fixed
|
|
return;
|
|
}
|
|
|
|
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
|
|
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
|
|
$accounts->overruleUser($user);
|
|
|
|
/** @var \Firefly\Helper\Controllers\TransactionInterface $transactions */
|
|
$transactions = \App::make('Firefly\Helper\Controllers\TransactionInterface');
|
|
$transactions->overruleUser($this->_user);
|
|
|
|
|
|
/*
|
|
* Prep some vars coming out of the pay load:
|
|
*/
|
|
$amount = floatval($payload['data']['amount']);
|
|
$date = new Carbon($payload['data']['date']);
|
|
$description = $payload['data']['description'];
|
|
$transactionId = intval($payload['data']['id']);
|
|
$accountId = intval($payload['data']['account_id']);
|
|
|
|
/*
|
|
* maybe Journal is already imported:
|
|
*/
|
|
$importEntry = $repository->findImportEntry($importMap, 'Transaction', $transactionId);
|
|
|
|
/*
|
|
* if so, delete job and return:
|
|
*/
|
|
if (!is_null($importEntry)) {
|
|
\Log::debug('Already imported transaction ' . $description);
|
|
|
|
$importMap->jobsdone++;
|
|
$importMap->save();
|
|
|
|
$job->delete(); // count fixed
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Find or create the "import account" which is used because at this point, Firefly
|
|
* doesn't know which beneficiary (expense account) should be connected to this transaction.
|
|
*/
|
|
$accountType = $accounts->findAccountType('Import account');
|
|
$importAccount = $accounts->firstOrCreate(
|
|
[
|
|
'account_type_id' => $accountType->id,
|
|
'name' => 'Import account',
|
|
'user_id' => $user->id,
|
|
'active' => 1,
|
|
]
|
|
);
|
|
unset($accountType);
|
|
|
|
/*
|
|
* Find the asset account this transaction is paid from / paid to:
|
|
*/
|
|
$accountEntry = $repository->findImportEntry($importMap, 'Account', $accountId);
|
|
|
|
/*
|
|
* Prep some data for the import routine:
|
|
*/
|
|
$set = [
|
|
'category' => '',
|
|
'description' => $description,
|
|
'date' => $date->format('Y-m-d'),
|
|
'return_journal' => true,
|
|
'account_id' => $accountEntry->new
|
|
];
|
|
|
|
|
|
/*
|
|
* If the amount is less than zero, we move money to the $importAccount. Otherwise,
|
|
* we move it from the $importAccount.
|
|
*/
|
|
|
|
if ($amount < 0) {
|
|
// if amount is less than zero, move to $importAccount
|
|
$set['what'] = 'withdrawal';
|
|
$set['expense_account'] = $importAccount->name;
|
|
} else {
|
|
$set['what'] = 'deposit';
|
|
$set['revenue_account'] = $importAccount->name;
|
|
}
|
|
|
|
/*
|
|
* Modify the amount so it will work with or new transaction journal structure.
|
|
*/
|
|
$set['amount'] = $amount < 0 ? $amount * -1 : $amount;
|
|
|
|
/*
|
|
* Import it:
|
|
*/
|
|
$journal = $transactions->store($set);
|
|
|
|
/*
|
|
* Validate the store action:
|
|
*/
|
|
if ($journal instanceof MessageBag) {
|
|
|
|
/*
|
|
* It's a message bag; clearly something went wrong.
|
|
*/
|
|
\Log::notice('Could not import transfer "' . $description . '": ' . $journal->first());
|
|
if (\Config::get('queue.default') == 'sync') {
|
|
$importMap->jobsdone++;
|
|
$importMap->save();
|
|
$job->delete(); // count fixed
|
|
} else {
|
|
$job->release(300); // proper release.
|
|
}
|
|
return;
|
|
} else if ($journal instanceof \TransactionJournal && $journal->errors()->count() > 0) {
|
|
/*
|
|
* It's a journal but it still failed somehow.
|
|
*/
|
|
\Log::notice('Could not import transfer "' . $description . '": ' . $journal->errors()->first());
|
|
if (\Config::get('queue.default') == 'sync') {
|
|
$importMap->jobsdone++;
|
|
$importMap->save();
|
|
$job->delete(); // count fixed
|
|
} else {
|
|
$job->release(300); // proper release.
|
|
}
|
|
return;
|
|
}
|
|
|
|
$repository->store($importMap, 'Transaction', $transactionId, $journal->id);
|
|
\Log::debug('Imported transaction "' . $description . '" (' . $amount . ') (' . $date->format('Y-m-d') . ')');
|
|
|
|
// update map:
|
|
$importMap->jobsdone++;
|
|
$importMap->save();
|
|
|
|
$job->delete(); // count fixed
|
|
return;
|
|
|
|
}
|
|
|
|
/**
|
|
* @param $journalId
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function find($journalId)
|
|
{
|
|
return $this->_user->transactionjournals()->with(
|
|
['transactions' => function ($q) {
|
|
return $q->orderBy('amount', 'ASC');
|
|
}, 'transactioncurrency', 'transactiontype', 'components', 'transactions.account',
|
|
'transactions.account.accounttype']
|
|
)
|
|
->where('id', $journalId)->first();
|
|
}
|
|
|
|
/**
|
|
* @param \Account $account
|
|
* @param int $count
|
|
* @param Carbon $start
|
|
* @param Carbon $end
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getByAccountInDateRange(\Account $account, $count = 25, Carbon $start, Carbon $end)
|
|
{
|
|
$accountID = $account->id;
|
|
$query = $this->_user->transactionjournals()->with(
|
|
[
|
|
'transactions',
|
|
'transactioncurrency',
|
|
'transactiontype'
|
|
]
|
|
)
|
|
->leftJoin(
|
|
'transactions', 'transactions.transaction_journal_id', '=',
|
|
'transaction_journals.id'
|
|
)
|
|
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
|
->where('accounts.id', $accountID)
|
|
->where('date', '>=', $start->format('Y-m-d'))
|
|
->where('date', '<=', $end->format('Y-m-d'))
|
|
->orderBy('transaction_journals.date', 'DESC')
|
|
->orderBy('transaction_journals.id', 'DESC')
|
|
->take($count)
|
|
->get(['transaction_journals.*']);
|
|
|
|
return $query;
|
|
}
|
|
/**
|
|
* @param \TransactionJournal $journal
|
|
* @param $data
|
|
*
|
|
* @return mixed|\TransactionJournal
|
|
* @throws \Firefly\Exception\FireflyException
|
|
*/
|
|
public function update(\TransactionJournal $journal, $data)
|
|
{
|
|
/*
|
|
* Update the basic fields:
|
|
*/
|
|
$journal->description = trim($data['description']);
|
|
$journal->date = new Carbon($data['date']);
|
|
|
|
/*
|
|
* Validate & save journal
|
|
*/
|
|
$journal->validate();
|
|
$journal->save();
|
|
|
|
/*
|
|
* Return regardless.
|
|
*/
|
|
return $journal;
|
|
|
|
|
|
}
|
|
// /*
|
|
// * Grab some of the repositories we need:
|
|
// */
|
|
// /** @var \Firefly\Storage\Category\CategoryRepositoryInterface $catRepository */
|
|
// $catRepository = \App::make('Firefly\Storage\Category\CategoryRepositoryInterface');
|
|
// $catRepository->overruleUser($this->_user);
|
|
//
|
|
// /** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budgetRepository */
|
|
// $budRepository = \App::make('Firefly\Storage\Budget\BudgetRepositoryInterface');
|
|
// $budRepository->overruleUser($this->_user);
|
|
//
|
|
// /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accountRepository */
|
|
// $accountRepository = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
|
|
// $accountRepository->overruleUser($this->_user);
|
|
//
|
|
//
|
|
// update basics first:
|
|
// $journal->description = $data['description'];
|
|
// $journal->date = $data['date'];
|
|
// $amount = floatval($data['amount']);
|
|
//
|
|
// // remove previous category, if any:
|
|
// if (!is_null($journal->categories()->first())) {
|
|
// $journal->categories()->detach($journal->categories()->first()->id);
|
|
// }
|
|
// // remove previous budget, if any:
|
|
// if (!is_null($journal->budgets()->first())) {
|
|
// $journal->budgets()->detach($journal->budgets()->first()->id);
|
|
// }
|
|
// // remove previous piggy bank, if any:
|
|
//
|
|
//
|
|
// $category = isset($data['category']) ? $catRepository->findByName($data['category']) : null;
|
|
// if (!is_null($category)) {
|
|
// $journal->categories()->attach($category);
|
|
// }
|
|
// // update the amounts:
|
|
// $transactions = $journal->transactions()->orderBy('amount', 'ASC')->get();
|
|
//
|
|
// // remove previous piggy bank, if any:
|
|
// /** @var \Transaction $transaction */
|
|
// foreach ($transactions as $transaction) {
|
|
// if (!is_null($transaction->piggybank()->first())) {
|
|
// $transaction->piggybank_id = null;
|
|
// $transaction->save();
|
|
// }
|
|
// }
|
|
// unset($transaction);
|
|
//
|
|
// $transactions[0]->amount = $amount * -1;
|
|
// $transactions[1]->amount = $amount;
|
|
//
|
|
// // switch on type to properly change things:
|
|
// $fireEvent = false;
|
|
// switch ($journal->transactiontype->type) {
|
|
// case 'Withdrawal':
|
|
// // means transaction[0] is the users account.
|
|
// $account = $accountRepository->find($data['account_id']);
|
|
// $beneficiary = $accountRepository->createOrFindBeneficiary($data['beneficiary']);
|
|
// $transactions[0]->account()->associate($account);
|
|
// $transactions[1]->account()->associate($beneficiary);
|
|
//
|
|
// // do budget:
|
|
// $budget = $budRepository->find($data['budget_id']);
|
|
// if (!is_null($budget)) {
|
|
// $journal->budgets()->attach($budget);
|
|
// }
|
|
//
|
|
// break;
|
|
// case 'Deposit':
|
|
// // means transaction[0] is the beneficiary.
|
|
// $account = $accountRepository->find($data['account_id']);
|
|
// $beneficiary = $accountRepository->createOrFindBeneficiary($data['beneficiary']);
|
|
// $journal->transactions[0]->account()->associate($beneficiary);
|
|
// $journal->transactions[1]->account()->associate($account);
|
|
// break;
|
|
// case 'Transfer':
|
|
// // means transaction[0] is account that sent the money (from).
|
|
// /** @var \Account $fromAccount */
|
|
// $fromAccount = $accountRepository->find($data['account_from_id']);
|
|
// /** @var \Account $toAccount */
|
|
// $toAccount = $accountRepository->find($data['account_to_id']);
|
|
// $journal->transactions[0]->account()->associate($fromAccount);
|
|
// $journal->transactions[1]->account()->associate($toAccount);
|
|
//
|
|
// // attach the new piggy bank, if valid:
|
|
// /** @var \Firefly\Storage\Piggybank\PiggybankRepositoryInterface $piggyRepository */
|
|
// $piggyRepository = \App::make('Firefly\Storage\Piggybank\PiggybankRepositoryInterface');
|
|
// $piggyRepository->overruleUser($this->_user);
|
|
//
|
|
// if (isset($data['piggybank_id'])) {
|
|
// /** @var \Piggybank $piggyBank */
|
|
// $piggyBank = $piggyRepository->find(intval($data['piggybank_id']));
|
|
//
|
|
// // loop transactions and re-attach the piggy bank:
|
|
//
|
|
// if ($piggyBank) {
|
|
//
|
|
// $connected = false;
|
|
// foreach ($journal->transactions()->get() as $transaction) {
|
|
// if ($transaction->account_id == $piggyBank->account_id) {
|
|
// $connected = true;
|
|
// $transaction->piggybank()->associate($piggyBank);
|
|
// $transaction->save();
|
|
// $fireEvent = true;
|
|
// break;
|
|
// }
|
|
// }
|
|
// if ($connected === false) {
|
|
// \Session::flash(
|
|
// 'warning', 'Piggy bank "' . e($piggyBank->name)
|
|
// . '" is not set to draw money from any of the accounts in this transfer'
|
|
// );
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
//
|
|
// break;
|
|
// default:
|
|
// throw new FireflyException('Cannot edit this!');
|
|
// break;
|
|
// }
|
|
//
|
|
// $transactions[0]->save();
|
|
// $transactions[1]->save();
|
|
// if ($journal->validate()) {
|
|
// $journal->save();
|
|
// }
|
|
// if ($fireEvent) {
|
|
// \Event::fire('piggybanks.updateRelatedTransfer', [$piggyBank]);
|
|
// }
|
|
//
|
|
// return $journal;
|
|
//
|
|
//
|
|
// }
|
|
|
|
|
|
} |