Code removal. The code removed from these classes must move to respective services.

This commit is contained in:
James Cole
2018-02-22 20:07:14 +01:00
parent 4e923057ae
commit b627d42160
16 changed files with 431 additions and 665 deletions

View File

@@ -25,6 +25,7 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Services\Internal\Support\BillServiceTrait;
use FireflyIII\User; use FireflyIII\User;
/** /**
@@ -32,6 +33,7 @@ use FireflyIII\User;
*/ */
class BillFactory class BillFactory
{ {
use BillServiceTrait;
/** @var BillRepositoryInterface */ /** @var BillRepositoryInterface */
private $repository; private $repository;
/** @var User */ /** @var User */
@@ -86,4 +88,37 @@ class BillFactory
} }
/**
* @param array $data
*
* @return Bill|null
*/
public function store(array $data): ?Bill
{
$matchArray = explode(',', $data['match']);
$matchArray = array_unique($matchArray);
$match = join(',', $matchArray);
/** @var Bill $bill */
$bill = Bill::create(
[
'name' => $data['name'],
'match' => $match,
'amount_min' => $data['amount_min'],
'user_id' => $this->user->id,
'amount_max' => $data['amount_max'],
'date' => $data['date'],
'repeat_freq' => $data['repeat_freq'],
'skip' => $data['skip'],
'automatch' => $data['automatch'],
'active' => $data['active'],
]
);
// update note:
if (isset($data['notes'])) {
$this->updateNote($bill, $data['notes']);
}
}
} }

View File

@@ -61,61 +61,6 @@ class StoredJournalEventHandler
$this->ruleGroupRepository = $ruleGroupRepository; $this->ruleGroupRepository = $ruleGroupRepository;
} }
/**
* This method connects a new transfer to a piggy bank.
*
* @param StoredTransactionJournal $event
*
* @return bool
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function connectToPiggyBank(StoredTransactionJournal $event): bool
{
$journal = $event->journal;
$piggyBankId = $event->piggyBankId;
$piggyBank = $this->repository->find($piggyBankId);
// is a transfer?
if (!$this->journalRepository->isTransfer($journal)) {
Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id));
return true;
}
// piggy exists?
if (null === $piggyBank) {
Log::error(sprintf('There is no piggy bank with ID #%d', $piggyBankId));
return true;
}
// repetition exists?
$repetition = $this->repository->getRepetition($piggyBank, $journal->date);
if (null === $repetition->id) {
Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d')));
return true;
}
// get the amount
$amount = $this->repository->getExactAmount($piggyBank, $repetition, $journal);
if (0 === bccomp($amount, '0')) {
Log::debug('Amount is zero, will not create event.');
return true;
}
// update amount
$this->repository->addAmountToRepetition($repetition, $amount);
$event = $this->repository->createEventWithJournal($piggyBank, $amount, $journal);
Log::debug(sprintf('Created piggy bank event #%d', $event->id));
return true;
}
/** /**
* This method grabs all the users rules and processes them. * This method grabs all the users rules and processes them.
* *

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Services\Internal\Update\JournalUpdateService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Log; use Log;
@@ -137,30 +138,35 @@ class BulkController extends Controller
*/ */
public function update(BulkEditJournalRequest $request, JournalRepositoryInterface $repository) public function update(BulkEditJournalRequest $request, JournalRepositoryInterface $repository)
{ {
/** @var JournalUpdateService $service */
$service = app(JournalUpdateService::class);
$journalIds = $request->get('journals'); $journalIds = $request->get('journals');
$ignoreCategory = intval($request->get('ignore_category')) === 1; $ignoreCategory = intval($request->get('ignore_category')) === 1;
$ignoreBudget = intval($request->get('ignore_budget')) === 1; $ignoreBudget = intval($request->get('ignore_budget')) === 1;
$ignoreTags = intval($request->get('ignore_tags')) === 1; $ignoreTags = intval($request->get('ignore_tags')) === 1;
$count = 0; $count = 0;
if (is_array($journalIds)) { if (is_array($journalIds)) {
foreach ($journalIds as $journalId) { foreach ($journalIds as $journalId) {
$journal = $repository->find(intval($journalId)); $journal = $repository->find(intval($journalId));
if (!is_null($journal)) { if (!is_null($journal)) {
// TODO need to move this to update service.
$count++; $count++;
Log::debug(sprintf('Found journal #%d', $journal->id)); Log::debug(sprintf('Found journal #%d', $journal->id));
// update category if not told to ignore // update category if not told to ignore
if ($ignoreCategory === false) { if ($ignoreCategory === false) {
Log::debug(sprintf('Set category to %s', $request->string('category'))); Log::debug(sprintf('Set category to %s', $request->string('category')));
$repository->updateCategory($journal, $request->string('category'));
$service->updateCategory($journal, $request->string('category'));
} }
// update budget if not told to ignore (and is withdrawal) // update budget if not told to ignore (and is withdrawal)
if ($ignoreBudget === false) { if ($ignoreBudget === false) {
Log::debug(sprintf('Set budget to %d', $request->integer('budget_id'))); Log::debug(sprintf('Set budget to %d', $request->integer('budget_id')));
$repository->updateBudget($journal, $request->integer('budget_id')); $service->updateBudget($journal, $request->integer('budget_id'));
} }
if ($ignoreTags === false) { if ($ignoreTags === false) {
Log::debug(sprintf('Set tags to %s', $request->string('budget_id'))); Log::debug(sprintf('Set tags to %s', $request->string('budget_id')));
$repository->updateTags($journal, explode(',', $request->string('tags'))); $service->updateTags($journal, explode(',', $request->string('tags')));
} }
// update tags if not told to ignore (and is withdrawal) // update tags if not told to ignore (and is withdrawal)
} }

View File

@@ -22,7 +22,8 @@ declare(strict_types=1);
namespace FireflyIII\Http\Requests; namespace FireflyIII\Http\Requests;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Models\Account;
use FireflyIII\Rules\UniqueIban;
/** /**
* Class AccountFormRequest. * Class AccountFormRequest.
@@ -67,25 +68,14 @@ class AccountFormRequest extends Request
*/ */
public function rules() public function rules()
{ {
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$accountRoles = join(',', config('firefly.accountRoles')); $accountRoles = join(',', config('firefly.accountRoles'));
$types = join(',', array_keys(config('firefly.subTitlesByIdentifier'))); $types = join(',', array_keys(config('firefly.subTitlesByIdentifier')));
$ccPaymentTypes = join(',', array_keys(config('firefly.ccTypes'))); $ccPaymentTypes = join(',', array_keys(config('firefly.ccTypes')));
$rules = [
$nameRule = 'required|min:1|uniqueAccountForUser'; 'name' => 'required|min:1|uniqueAccountForUser',
$idRule = '';
if (null !== $repository->find(intval($this->get('id')))->id) {
$idRule = 'belongsToUser:accounts';
$nameRule = 'required|min:1|uniqueAccountForUser:' . intval($this->get('id'));
}
return [
'id' => $idRule,
'name' => $nameRule,
'openingBalance' => 'numeric|required_with:openingBalanceDate|nullable', 'openingBalance' => 'numeric|required_with:openingBalanceDate|nullable',
'openingBalanceDate' => 'date|required_with:openingBalance|nullable', 'openingBalanceDate' => 'date|required_with:openingBalance|nullable',
'iban' => 'iban|nullable', 'iban' => ['iban', 'nullable', new UniqueIban(null)],
'BIC' => 'bic|nullable', 'BIC' => 'bic|nullable',
'virtualBalance' => 'numeric|nullable', 'virtualBalance' => 'numeric|nullable',
'currency_id' => 'exists:transaction_currencies,id', 'currency_id' => 'exists:transaction_currencies,id',
@@ -98,5 +88,16 @@ class AccountFormRequest extends Request
'amount_currency_id_virtualBalance' => 'exists:transaction_currencies,id', 'amount_currency_id_virtualBalance' => 'exists:transaction_currencies,id',
'what' => 'in:' . $types, 'what' => 'in:' . $types,
]; ];
/** @var Account $account */
$account = $this->route()->parameter('account');
if (!is_null($account)) {
// add rules:
$rules['id'] = 'belongsToUser:accounts';
$rules['name'] = 'required|min:1|uniqueAccountForUser:' . intval($this->get('id'));
$rules['iban'] = ['iban', 'nullable', new UniqueIban($account)];
}
return $rules;
} }
} }

View File

@@ -77,7 +77,6 @@ class EventServiceProvider extends ServiceProvider
// is a Transaction Journal related event. // is a Transaction Journal related event.
'FireflyIII\Events\StoredTransactionJournal' => [ 'FireflyIII\Events\StoredTransactionJournal' => [
'FireflyIII\Handlers\Events\StoredJournalEventHandler@scanBills', 'FireflyIII\Handlers\Events\StoredJournalEventHandler@scanBills',
'FireflyIII\Handlers\Events\StoredJournalEventHandler@connectToPiggyBank',
'FireflyIII\Handlers\Events\StoredJournalEventHandler@processRules', 'FireflyIII\Handlers\Events\StoredJournalEventHandler@processRules',
], ],
// is a Transaction Journal related event. // is a Transaction Journal related event.

View File

@@ -23,42 +23,29 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Account; namespace FireflyIII\Repositories\Account;
use Carbon\Carbon; use Carbon\Carbon;
use DB; use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\AccountFactory; use FireflyIII\Factory\AccountFactory;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\Category;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\AccountDestroyService; use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
use FireflyIII\Services\Internal\Update\AccountUpdateService; use FireflyIII\Services\Internal\Update\AccountUpdateService;
use FireflyIII\Services\Internal\Update\JournalUpdateService;
use FireflyIII\User; use FireflyIII\User;
use Log;
/** /**
* Class AccountRepository. * Class AccountRepository.
*/ */
class AccountRepository implements AccountRepositoryInterface class AccountRepository implements AccountRepositoryInterface
{ {
use FindAccountsTrait;
/** @var User */ /** @var User */
private $user; private $user;
/** @var array */
private $validAssetFields = ['accountRole', 'accountNumber', 'currency_id', 'BIC'];
use FindAccountsTrait;
/** @var array */
private $validCCFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType', 'accountNumber', 'currency_id', 'BIC'];
/** @var array */
private $validFields = ['accountNumber', 'currency_id', 'BIC'];
/** /**
* Moved here from account CRUD.
*
* @param array $types * @param array $types
* *
* @return int * @return int
@@ -239,6 +226,8 @@ class AccountRepository implements AccountRepositoryInterface
* @param array $data * @param array $data
* *
* @return Account * @return Account
* @throws FireflyException
* @throws Exception
*/ */
public function store(array $data): Account public function store(array $data): Account
{ {
@@ -254,6 +243,8 @@ class AccountRepository implements AccountRepositoryInterface
* @param Account $account * @param Account $account
* @param array $data * @param array $data
* *
* @throws FireflyException
* @throws Exception
* @return Account * @return Account
*/ */
public function update(Account $account, array $data): Account public function update(Account $account, array $data): Account
@@ -270,90 +261,16 @@ class AccountRepository implements AccountRepositoryInterface
* @param array $data * @param array $data
* *
* @return TransactionJournal * @return TransactionJournal
* @throws FireflyException
* @throws Exception
*/ */
public function updateReconciliation(TransactionJournal $journal, array $data): TransactionJournal public function updateReconciliation(TransactionJournal $journal, array $data): TransactionJournal
{ {
// update journal /** @var JournalUpdateService $service */
// update actual journal: $service = app(JournalUpdateService::class);
$data['amount'] = strval($data['amount']); $journal = $service->update($journal, $data);
// unlink all categories, recreate them:
$journal->categories()->detach();
$this->storeCategoryWithJournal($journal, strval($data['category']));
// update amounts
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
$transaction->amount = bcmul($data['amount'], '-1');
if (AccountType::ASSET === $transaction->account->accountType->type) {
$transaction->amount = $data['amount'];
}
$transaction->save();
}
$journal->save();
// update tags:
if (isset($data['tags']) && is_array($data['tags'])) {
$this->updateTags($journal, $data['tags']);
}
return $journal; return $journal;
} }
/**
* @param TransactionJournal $journal
* @param string $category
*/
protected function storeCategoryWithJournal(TransactionJournal $journal, string $category)
{
if (strlen($category) > 0) {
$category = Category::firstOrCreateEncrypted(['name' => $category, 'user_id' => $journal->user_id]);
$journal->categories()->save($category);
}
}
/**
* @param TransactionJournal $journal
* @param array $array
*
* @return bool
*/
protected function updateTags(TransactionJournal $journal, array $array): bool
{
// create tag repository
/** @var TagRepositoryInterface $tagRepository */
$tagRepository = app(TagRepositoryInterface::class);
// 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 (0 === count($ids)) {
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) {
Log::debug(sprintf('Will try to connect tag #%d to journal #%d.', $tag->id, $journal->id));
$tagRepository->connect($journal, $tag);
}
return true;
}
} }

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Account; namespace FireflyIII\Repositories\Account;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\AccountFactory;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\User; use FireflyIII\User;
@@ -44,6 +45,7 @@ trait FindAccountsTrait
*/ */
public function find(int $accountId): Account public function find(int $accountId): Account
{ {
/** @var Account $account */
$account = $this->user->accounts()->find($accountId); $account = $this->user->accounts()->find($accountId);
if (null === $account) { if (null === $account) {
return new Account; return new Account;
@@ -56,6 +58,7 @@ trait FindAccountsTrait
* @param string $number * @param string $number
* @param array $types * @param array $types
* *
* @deprecated
* @return Account * @return Account
*/ */
public function findByAccountNumber(string $number, array $types): Account public function findByAccountNumber(string $number, array $types): Account
@@ -83,6 +86,7 @@ trait FindAccountsTrait
* @param string $iban * @param string $iban
* @param array $types * @param array $types
* *
* @deprecated
* @return Account * @return Account
*/ */
public function findByIban(string $iban, array $types): Account public function findByIban(string $iban, array $types): Account
@@ -213,15 +217,15 @@ trait FindAccountsTrait
* @return Account * @return Account
* *
* @throws FireflyException * @throws FireflyException
* @throws \Exception
*/ */
public function getCashAccount(): Account public function getCashAccount(): Account
{ {
$type = AccountType::where('type', AccountType::CASH)->first(); $type = AccountType::where('type', AccountType::CASH)->first();
$account = Account::firstOrCreateEncrypted( /** @var AccountFactory $factory */
['user_id' => $this->user->id, 'account_type_id' => $type->id, 'name' => 'Cash account'] $factory = app(AccountFactory::class);
); $factory->setUser($this->user);
$account->active = true; $account = $factory->findOrCreate('Cash account', $type->type);
$account->save();
return $account; return $account;
} }
@@ -232,6 +236,7 @@ trait FindAccountsTrait
* @return Account|null * @return Account|null
* *
* @throws FireflyException * @throws FireflyException
* @throws \Exception
*/ */
public function getReconciliation(Account $account): ?Account public function getReconciliation(Account $account): ?Account
{ {
@@ -247,23 +252,12 @@ trait FindAccountsTrait
return $account; return $account;
} }
} }
// assume nothing was found. create it! /** @var AccountFactory $factory */
$data = [ $factory = app(AccountFactory::class);
'accountType' => 'reconcile', $factory->setUser($account->user);
'name' => $name, $account = $factory->findOrCreate($name, $type->type);
'iban' => null,
'virtualBalance' => '0',
'active' => true,
];
$account = $this->storeAccount($data);
return $account; return $account;
} }
/**
* @param array $data
*
* @return Account
*/
abstract protected function storeAccount(array $data): Account;
} }

View File

@@ -24,18 +24,19 @@ namespace FireflyIII\Repositories\Bill;
use Carbon\Carbon; use Carbon\Carbon;
use DB; use DB;
use FireflyIII\Factory\BillFactory;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Note;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Services\Internal\Destroy\BillDestroyService;
use FireflyIII\Services\Internal\Update\BillUpdateService;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Log; use Log;
use Navigation;
/** /**
* Class BillRepository. * Class BillRepository.
@@ -54,7 +55,9 @@ class BillRepository implements BillRepositoryInterface
*/ */
public function destroy(Bill $bill): bool public function destroy(Bill $bill): bool
{ {
$bill->delete(); /** @var BillDestroyService $service */
$service = app(BillDestroyService::class);
$service->destroy($bill);
return true; return true;
} }
@@ -103,12 +106,8 @@ class BillRepository implements BillRepositoryInterface
/** @var Collection $set */ /** @var Collection $set */
$set = $this->user->bills() $set = $this->user->bills()
->where('active', 1) ->where('active', 1)
->get( ->sortBy('name')
[ ->get(['bills.*', DB::raw('((bills.amount_min + bills.amount_max) / 2) AS expectedAmount'),]);
'bills.*',
DB::raw('((bills.amount_min + bills.amount_max) / 2) AS expectedAmount'),
]
)->sortBy('name');
return $set; return $set;
} }
@@ -221,6 +220,7 @@ class BillRepository implements BillRepositoryInterface
* @param Carbon $end * @param Carbon $end
* *
* @return string * @return string
* @throws \FireflyIII\Exceptions\FireflyException
*/ */
public function getBillsUnpaidInRange(Carbon $start, Carbon $end): string public function getBillsUnpaidInRange(Carbon $start, Carbon $end): string
{ {
@@ -302,6 +302,7 @@ class BillRepository implements BillRepositoryInterface
* @param Carbon $end * @param Carbon $end
* *
* @return Collection * @return Collection
* @throws \FireflyIII\Exceptions\FireflyException
*/ */
public function getPayDatesInRange(Bill $bill, Carbon $start, Carbon $end): Collection public function getPayDatesInRange(Bill $bill, Carbon $start, Carbon $end): Collection
{ {
@@ -418,11 +419,11 @@ class BillRepository implements BillRepositoryInterface
while ($start < $date) { while ($start < $date) {
Log::debug(sprintf('$start (%s) < $date (%s)', $start->format('Y-m-d'), $date->format('Y-m-d'))); Log::debug(sprintf('$start (%s) < $date (%s)', $start->format('Y-m-d'), $date->format('Y-m-d')));
$start = Navigation::addPeriod($start, $bill->repeat_freq, $bill->skip); $start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
Log::debug('Start is now ' . $start->format('Y-m-d')); Log::debug('Start is now ' . $start->format('Y-m-d'));
} }
$end = Navigation::addPeriod($start, $bill->repeat_freq, $bill->skip); $end = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
Log::debug('nextDateMatch: Final start is ' . $start->format('Y-m-d')); Log::debug('nextDateMatch: Final start is ' . $start->format('Y-m-d'));
Log::debug('nextDateMatch: Matching end is ' . $end->format('Y-m-d')); Log::debug('nextDateMatch: Matching end is ' . $end->format('Y-m-d'));
@@ -455,11 +456,11 @@ class BillRepository implements BillRepositoryInterface
while ($start < $date) { while ($start < $date) {
Log::debug(sprintf('$start (%s) < $date (%s)', $start->format('Y-m-d'), $date->format('Y-m-d'))); Log::debug(sprintf('$start (%s) < $date (%s)', $start->format('Y-m-d'), $date->format('Y-m-d')));
$start = Navigation::addPeriod($start, $bill->repeat_freq, $bill->skip); $start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
Log::debug('Start is now ' . $start->format('Y-m-d')); Log::debug('Start is now ' . $start->format('Y-m-d'));
} }
$end = Navigation::addPeriod($start, $bill->repeat_freq, $bill->skip); $end = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
// see if the bill was paid in this period. // see if the bill was paid in this period.
$journalCount = $bill->transactionJournals()->before($end)->after($start)->count(); $journalCount = $bill->transactionJournals()->before($end)->after($start)->count();
@@ -468,7 +469,7 @@ class BillRepository implements BillRepositoryInterface
// this period had in fact a bill. The new start is the current end, and we create a new end. // this period had in fact a bill. The new start is the current end, and we create a new end.
Log::debug(sprintf('Journal count is %d, so start becomes %s', $journalCount, $end->format('Y-m-d'))); Log::debug(sprintf('Journal count is %d, so start becomes %s', $journalCount, $end->format('Y-m-d')));
$start = clone $end; $start = clone $end;
$end = Navigation::addPeriod($start, $bill->repeat_freq, $bill->skip); $end = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
} }
Log::debug('nextExpectedMatch: Final start is ' . $start->format('Y-m-d')); Log::debug('nextExpectedMatch: Final start is ' . $start->format('Y-m-d'));
Log::debug('nextExpectedMatch: Matching end is ' . $end->format('Y-m-d')); Log::debug('nextExpectedMatch: Matching end is ' . $end->format('Y-m-d'));
@@ -479,9 +480,12 @@ class BillRepository implements BillRepositoryInterface
} }
/** /**
* TODO move to a service.
*
* @param Bill $bill * @param Bill $bill
* @param TransactionJournal $journal * @param TransactionJournal $journal
* *
* @deprecated
* @return bool * @return bool
*/ */
public function scan(Bill $bill, TransactionJournal $journal): bool public function scan(Bill $bill, TransactionJournal $journal): bool
@@ -533,30 +537,11 @@ class BillRepository implements BillRepositoryInterface
*/ */
public function store(array $data): Bill public function store(array $data): Bill
{ {
$matchArray = explode(',', $data['match']); /** @var BillFactory $factory */
$matchArray = array_unique($matchArray); $factory = app(BillFactory::class);
$match = join(',', $matchArray); $factory->setUser($this->user);
$bill = $factory->store($data);
/** @var Bill $bill */
$bill = Bill::create(
[
'name' => $data['name'],
'match' => $match,
'amount_min' => $data['amount_min'],
'user_id' => $this->user->id,
'amount_max' => $data['amount_max'],
'date' => $data['date'],
'repeat_freq' => $data['repeat_freq'],
'skip' => $data['skip'],
'automatch' => $data['automatch'],
'active' => $data['active'],
]
);
// update note:
if (isset($data['notes'])) {
$this->updateNote($bill, $data['notes']);
}
return $bill; return $bill;
} }
@@ -569,27 +554,10 @@ class BillRepository implements BillRepositoryInterface
*/ */
public function update(Bill $bill, array $data): Bill public function update(Bill $bill, array $data): Bill
{ {
$matchArray = explode(',', $data['match']); /** @var BillUpdateService $service */
$matchArray = array_unique($matchArray); $service = app(BillUpdateService::class);
$match = join(',', $matchArray);
$bill->name = $data['name']; return $service->update($bill, $data);
$bill->match = $match;
$bill->amount_min = $data['amount_min'];
$bill->amount_max = $data['amount_max'];
$bill->date = $data['date'];
$bill->repeat_freq = $data['repeat_freq'];
$bill->skip = $data['skip'];
$bill->automatch = $data['automatch'];
$bill->active = $data['active'];
$bill->save();
// update note:
if (isset($data['notes']) && null !== $data['notes']) {
$this->updateNote($bill, strval($data['notes']));
}
return $bill;
} }
/** /**
@@ -629,31 +597,4 @@ class BillRepository implements BillRepositoryInterface
return $wordMatch; return $wordMatch;
} }
/**
* @param Bill $bill
* @param string $note
*
* @return bool
*/
protected function updateNote(Bill $bill, string $note): bool
{
if (0 === strlen($note)) {
$dbNote = $bill->notes()->first();
if (null !== $dbNote) {
$dbNote->delete();
}
return true;
}
$dbNote = $bill->notes()->first();
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($bill);
}
$dbNote->text = trim($note);
$dbNote->save();
return true;
}
} }

View File

@@ -22,16 +22,16 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Journal; namespace FireflyIII\Repositories\Journal;
use Carbon\Carbon; use Exception;
use DB; use FireflyIII\Factory\TransactionJournalFactory;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
use FireflyIII\Services\Internal\Update\JournalUpdateService;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag; use Illuminate\Support\MessageBag;
@@ -109,7 +109,9 @@ class JournalRepository implements JournalRepositoryInterface
*/ */
public function destroy(TransactionJournal $journal): bool public function destroy(TransactionJournal $journal): bool
{ {
$journal->delete(); /** @var JournalDestroyService $service */
$service = app(JournalDestroyService::class);
$service->destroy($journal);
return true; return true;
} }
@@ -229,31 +231,6 @@ class JournalRepository implements JournalRepositoryInterface
return $set; return $set;
} }
/**
* @param TransactionJournal $journal
*
* @return bool
*/
public function isTransfer(TransactionJournal $journal): bool
{
return TransactionType::TRANSFER === $journal->transactionType->type;
}
/**
* Mark journal as completed and return it.
*
* @param TransactionJournal $journal
*
* @return TransactionJournal
*/
public function markCompleted(TransactionJournal $journal): TransactionJournal
{
$journal->completed = true;
$journal->save();
return $journal;
}
/** /**
* @param Transaction $transaction * @param Transaction $transaction
* *
@@ -311,109 +288,11 @@ class JournalRepository implements JournalRepositoryInterface
*/ */
public function store(array $data): TransactionJournal public function store(array $data): TransactionJournal
{ {
// find transaction type. /** @var TransactionJournalFactory $factory */
/** @var TransactionType $transactionType */ $factory = app(TransactionJournalFactory::class);
$transactionType = TransactionType::where('type', ucfirst($data['what']))->first(); $factory->setUser($this->user);
$accounts = $this->storeAccounts($this->user, $transactionType, $data);
$data = $this->verifyNativeAmount($data, $accounts);
$amount = strval($data['amount']);
$dateString = $data['date'];
if ($data['date'] instanceof Carbon) {
$dateString = $data['date']->format('Y-m-d 00:00:00');
}
$journal = new TransactionJournal(
[
'user_id' => $this->user->id,
'transaction_type_id' => $transactionType->id,
'transaction_currency_id' => $data['currency_id'], // no longer used.
'description' => $data['description'],
'completed' => 0,
'date' => $dateString,
]
);
$journal->save();
// store stuff: return $factory->create($data);
$this->storeCategoryWithJournal($journal, strval($data['category']));
$this->storeBudgetWithJournal($journal, $data['budget_id']);
// store two transactions:
$one = [
'journal' => $journal,
'account' => $accounts['source'],
'amount' => bcmul($amount, '-1'),
'transaction_currency_id' => $data['currency_id'],
'foreign_amount' => null === $data['foreign_amount'] ? null : bcmul(strval($data['foreign_amount']), '-1'),
'foreign_currency_id' => $data['foreign_currency_id'],
'description' => null,
'category' => null,
'budget' => null,
'identifier' => 0,
];
$this->storeTransaction($one);
$two = [
'journal' => $journal,
'account' => $accounts['destination'],
'amount' => $amount,
'transaction_currency_id' => $data['currency_id'],
'foreign_amount' => $data['foreign_amount'],
'foreign_currency_id' => $data['foreign_currency_id'],
'description' => null,
'category' => null,
'budget' => null,
'identifier' => 0,
];
$this->storeTransaction($two);
// store tags
if (isset($data['tags']) && is_array($data['tags'])) {
$this->saveTags($journal, $data['tags']);
}
// update note:
if (isset($data['notes'])) {
$this->updateNote($journal, $data['notes']);
}
foreach ($data as $key => $value) {
if (in_array($key, $this->validMetaFields)) {
$journal->setMeta($key, $value);
continue;
}
Log::debug(sprintf('Could not store meta field "%s" with value "%s" for journal #%d', json_encode($key), json_encode($value), $journal->id));
}
$journal->completed = 1;
$journal->save();
return $journal;
}
/**
* Store a new transaction journal based on the values given.
*
* @param array $values
*
* @return TransactionJournal
*/
public function storeBasic(array $values): TransactionJournal
{
return TransactionJournal::create($values);
}
/**
* Store a new transaction based on the values given.
*
* @param array $values
*
* @return Transaction
*/
public function storeBasicTransaction(array $values): Transaction
{
return Transaction::create($values);
} }
/** /**
@@ -423,201 +302,14 @@ class JournalRepository implements JournalRepositoryInterface
* @return TransactionJournal * @return TransactionJournal
* *
* @throws \FireflyIII\Exceptions\FireflyException * @throws \FireflyIII\Exceptions\FireflyException
* @throws \FireflyIII\Exceptions\FireflyException * @throws Exception
* @throws \FireflyIII\Exceptions\FireflyException
* @throws \FireflyIII\Exceptions\FireflyException
*/ */
public function update(TransactionJournal $journal, array $data): TransactionJournal public function update(TransactionJournal $journal, array $data): TransactionJournal
{ {
// update actual journal: /** @var JournalUpdateService $service */
$journal->description = $data['description']; $service = app(JournalUpdateService::class);
$journal->date = $data['date'];
$accounts = $this->storeAccounts($this->user, $journal->transactionType, $data);
$data = $this->verifyNativeAmount($data, $accounts);
$data['amount'] = strval($data['amount']);
$data['foreign_amount'] = null === $data['foreign_amount'] ? null : strval($data['foreign_amount']);
// unlink all categories, recreate them: return $service->update($journal, $data);
$journal->categories()->detach();
$journal->budgets()->detach();
$this->storeCategoryWithJournal($journal, strval($data['category']));
$this->storeBudgetWithJournal($journal, $data['budget_id']);
// negative because source loses money.
$this->updateSourceTransaction($journal, $accounts['source'], $data);
// positive because destination gets money.
$this->updateDestinationTransaction($journal, $accounts['destination'], $data);
$journal->save();
// update tags:
if (isset($data['tags']) && is_array($data['tags'])) {
$this->updateTags($journal, $data['tags']);
}
// update note:
if (isset($data['notes']) && null !== $data['notes']) {
$this->updateNote($journal, strval($data['notes']));
}
// update meta fields:
$result = $journal->save();
if ($result) {
foreach ($data as $key => $value) {
if (in_array($key, $this->validMetaFields)) {
$journal->setMeta($key, $value);
continue;
}
Log::debug(sprintf('Could not store meta field "%s" with value "%s" for journal #%d', json_encode($key), json_encode($value), $journal->id));
}
return $journal;
}
return $journal;
} }
/**
* @param TransactionJournal $journal
* @param int $budgetId
*
* @return TransactionJournal
*/
public function updateBudget(TransactionJournal $journal, int $budgetId): TransactionJournal
{
if ($budgetId === 0) {
$journal->budgets()->detach();
$journal->save();
return $journal;
}
$this->storeBudgetWithJournal($journal, $budgetId);
return $journal;
}
/**
* @param TransactionJournal $journal
* @param string $category
*
* @return TransactionJournal
*/
public function updateCategory(TransactionJournal $journal, string $category): TransactionJournal
{
Log::debug(sprintf('In updateCategory("%s")', $category));
$journal->categories()->detach();
if (strlen($category) === 0) {
return $journal;
}
$this->storeCategoryWithJournal($journal, $category);
return $journal;
}
/**
* Same as above but for transaction journal with multiple transactions.
*
* @param TransactionJournal $journal
* @param array $data
*
* @return TransactionJournal
*/
public function updateSplitJournal(TransactionJournal $journal, array $data): TransactionJournal
{
// update actual journal:
$journal->description = $data['journal_description'];
$journal->date = $data['date'];
$journal->save();
Log::debug(sprintf('Updated split journal #%d', $journal->id));
// unlink all categories:
$journal->categories()->detach();
$journal->budgets()->detach();
// update note:
if (isset($data['notes']) && null !== $data['notes']) {
$this->updateNote($journal, strval($data['notes']));
}
// update meta fields:
$result = $journal->save();
if ($result) {
foreach ($data as $key => $value) {
if (in_array($key, $this->validMetaFields)) {
$journal->setMeta($key, $value);
continue;
}
Log::debug(sprintf('Could not store meta field "%s" with value "%s" for journal #%d', json_encode($key), json_encode($value), $journal->id));
}
}
// update tags:
if (isset($data['tags']) && is_array($data['tags'])) {
$this->updateTags($journal, $data['tags']);
}
// delete original transactions, and recreate them.
$journal->transactions()->delete();
// store each transaction.
$identifier = 0;
Log::debug(sprintf('Count %d transactions in updateSplitJournal()', count($data['transactions'])));
foreach ($data['transactions'] as $transaction) {
Log::debug(sprintf('Split journal update split transaction %d', $identifier));
$transaction = $this->appendTransactionData($transaction, $data);
$this->storeSplitTransaction($journal, $transaction, $identifier);
++$identifier;
}
$journal->save();
return $journal;
}
/**
* Update tags.
*
* @param TransactionJournal $journal
* @param array $array
*
* @return bool
*/
public function updateTags(TransactionJournal $journal, array $array): bool
{
// create tag repository
/** @var TagRepositoryInterface $tagRepository */
$tagRepository = app(TagRepositoryInterface::class);
// 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 (0 === count($ids)) {
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) {
Log::debug(sprintf('Will try to connect tag #%d to journal #%d.', $tag->id, $journal->id));
$tagRepository->connect($journal, $tag);
}
return true;
}
} }

View File

@@ -118,22 +118,6 @@ interface JournalRepositoryInterface
*/ */
public function getTransactionsById(array $transactionIds): Collection; public function getTransactionsById(array $transactionIds): Collection;
/**
* @param TransactionJournal $journal
*
* @return bool
*/
public function isTransfer(TransactionJournal $journal): bool;
/**
* Mark journal as completed and return it.
*
* @param TransactionJournal $journal
*
* @return TransactionJournal
*/
public function markCompleted(TransactionJournal $journal): TransactionJournal;
/** /**
* @param Transaction $transaction * @param Transaction $transaction
* *
@@ -161,24 +145,6 @@ interface JournalRepositoryInterface
*/ */
public function store(array $data): TransactionJournal; public function store(array $data): TransactionJournal;
/**
* Store a new transaction journal based on the values given.
*
* @param array $values
*
* @return TransactionJournal
*/
public function storeBasic(array $values): TransactionJournal;
/**
* Store a new transaction based on the values given.
*
* @param array $values
*
* @return Transaction
*/
public function storeBasicTransaction(array $values): Transaction;
/** /**
* @param TransactionJournal $journal * @param TransactionJournal $journal
* @param array $data * @param array $data
@@ -186,36 +152,4 @@ interface JournalRepositoryInterface
* @return TransactionJournal * @return TransactionJournal
*/ */
public function update(TransactionJournal $journal, array $data): TransactionJournal; public function update(TransactionJournal $journal, array $data): TransactionJournal;
/**
* @param TransactionJournal $journal
* @param int $budgetId
*
* @return TransactionJournal
*/
public function updateBudget(TransactionJournal $journal, int $budgetId): TransactionJournal;
/**
* @param TransactionJournal $journal
* @param string $category
*
* @return TransactionJournal
*/
public function updateCategory(TransactionJournal $journal, string $category): TransactionJournal;
/**
* @param TransactionJournal $journal
* @param array $data
*
* @return TransactionJournal
*/
public function updateSplitJournal(TransactionJournal $journal, array $data): TransactionJournal;
/**
* @param TransactionJournal $journal
* @param array $tags
*
* @return bool
*/
public function updateTags(TransactionJournal $journal, array $tags): bool;
} }

View File

@@ -231,7 +231,7 @@ trait SupportJournalsTrait
protected function verifyNativeAmount(array $data, array $accounts): array protected function verifyNativeAmount(array $data, array $accounts): array
{ {
/** @var TransactionType $transactionType */ /** @var TransactionType $transactionType */
$transactionType = TransactionType::where('type', ucfirst($data['what']))->first(); $transactionType = TransactionType::where('type', ucfirst($data['type']))->first();
$submittedCurrencyId = $data['currency_id']; $submittedCurrencyId = $data['currency_id'];
$data['foreign_amount'] = null; $data['foreign_amount'] = null;
$data['foreign_currency_id'] = null; $data['foreign_currency_id'] = null;

89
app/Rules/UniqueIban.php Normal file
View File

@@ -0,0 +1,89 @@
<?php
/**
* UniqueIban.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Rules;
use FireflyIII\Models\Account;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Collection;
/**
* Class UniqueIban
*/
class UniqueIban implements Rule
{
/** @var Account */
private $account;
/**
* Create a new rule instance.
*
* @return void
*/
public function __construct(?Account $account)
{
$this->account = $account;
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return trans('validation.unique_iban_for_user');
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
*
* @return bool
*/
public function passes($attribute, $value)
{
if (!auth()->check()) {
return true; // @codeCoverageIgnore
}
$query = auth()->user()->accounts();
if (!is_null($this->account)) {
$query->where('accounts.id', '!=', $this->account->id);
}
/** @var Collection $accounts */
$accounts = $query->get();
/** @var Account $account */
foreach ($accounts as $account) {
if ($account->iban === $value) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* BillDestroyService.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Services\Internal\Destroy;
use Exception;
use FireflyIII\Models\Bill;
/**
* Class BillDestroyService
*/
class BillDestroyService
{
/**
* @param Bill $bill
*/
public function destroy(Bill $bill): void
{
try {
$bill->delete();
} catch (Exception $e) {
// don't care.
}
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* JournalDestroyService.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Services\Internal\Destroy;
use FireflyIII\Models\TransactionJournal;
/**
* Class JournalDestroyService
*/
class JournalDestroyService
{
/**
* @param TransactionJournal $journal
*/
public function destroy(TransactionJournal $journal): void {
}
}

View File

@@ -0,0 +1,62 @@
<?php
/**
* BillServiceTrait.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Services\Internal\Support;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Note;
/**
* Trait BillServiceTrait
*
* @package FireflyIII\Services\Internal\Support
*/
trait BillServiceTrait
{
/**
* @param Bill $bill
* @param string $note
*
* @return bool
*/
public function updateNote(Bill $bill, string $note): bool
{
if (0 === strlen($note)) {
$dbNote = $bill->notes()->first();
if (null !== $dbNote) {
$dbNote->delete();
}
return true;
}
$dbNote = $bill->notes()->first();
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($bill);
}
$dbNote->text = trim($note);
$dbNote->save();
return true;
}
}

View File

@@ -0,0 +1,66 @@
<?php
/**
* BillUpdateService.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Services\Internal\Update;
use FireflyIII\Models\Bill;
use FireflyIII\Services\Internal\Support\BillServiceTrait;
/**
* Class BillUpdateService
*/
class BillUpdateService
{
use BillServiceTrait;
/**
* @param Bill $bill
* @param array $data
*/
public function update(Bill $bill, array $data): Bill
{
$matchArray = explode(',', $data['match']);
$matchArray = array_unique($matchArray);
$match = join(',', $matchArray);
$bill->name = $data['name'];
$bill->match = $match;
$bill->amount_min = $data['amount_min'];
$bill->amount_max = $data['amount_max'];
$bill->date = $data['date'];
$bill->repeat_freq = $data['repeat_freq'];
$bill->skip = $data['skip'];
$bill->automatch = $data['automatch'];
$bill->active = $data['active'];
$bill->save();
// update note:
if (isset($data['notes']) && null !== $data['notes']) {
$this->updateNote($bill, strval($data['notes']));
}
return $bill;
}
}