Improve factories and tests.

This commit is contained in:
James Cole
2019-03-18 16:52:49 +01:00
parent 200a4b18a8
commit 3545d894fd
11 changed files with 1901 additions and 1398 deletions

View File

@@ -35,6 +35,7 @@ use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\NullArrayObject;
use FireflyIII\User;
use Illuminate\Database\QueryException;
use Illuminate\Support\Collection;
use Log;
@@ -61,8 +62,6 @@ class TransactionFactory
$this->accountRepository = app(AccountRepositoryInterface::class);
}
//use TransactionServiceTrait;
/**
* @param Account $account
* @param TransactionCurrency $currency
@@ -72,19 +71,23 @@ class TransactionFactory
*/
public function create(Account $account, TransactionCurrency $currency, string $amount): ?Transaction
{
$result = Transaction::create(
[
'reconciled' => false,
'account_id' => $account->id,
'transaction_journal_id' => $this->journal->id,
'description' => null,
'transaction_currency_id' => $currency->id,
'amount' => $amount,
'foreign_amount' => null,
'foreign_currency_id' => null,
'identifier' => 0,
]
);
$result = null;
$data = [
'reconciled' => false,
'account_id' => $account->id,
'transaction_journal_id' => $this->journal->id,
'description' => null,
'transaction_currency_id' => $currency->id,
'amount' => $amount,
'foreign_amount' => null,
'foreign_currency_id' => null,
'identifier' => 0,
];
try {
$result = Transaction::create($data);
} catch (QueryException $e) {
Log::error(sprintf('Could not create transaction: %s', $e->getMessage()), $data);
}
if (null !== $result) {
Log::debug(
sprintf(
@@ -107,11 +110,14 @@ class TransactionFactory
*/
public function createPair(NullArrayObject $data, TransactionCurrency $currency, ?TransactionCurrency $foreignCurrency): Collection
{
$sourceAccount = $this->getAccount('source', $data['source'], $data['source_id'], $data['source_name']);
$destinationAccount = $this->getAccount('destination', $data['destination'], $data['destination_id'], $data['destination_name']);
$sourceAccount = $this->getAccount('source', $data['source'], (int)$data['source_id'], $data['source_name']);
$destinationAccount = $this->getAccount('destination', $data['destination'], (int)$data['destination_id'], $data['destination_name']);
$amount = $this->getAmount($data['amount']);
$foreignAmount = $this->getForeignAmount($data['foreign_amount']);
$this->makeDramaOverAccountTypes($sourceAccount, $destinationAccount);
$one = $this->create($sourceAccount, $currency, app('steam')->negative($amount));
$two = $this->create($destinationAccount, $currency, app('steam')->positive($amount));
@@ -134,24 +140,6 @@ class TransactionFactory
}
/**
* @param TransactionJournal $journal
*/
public function setJournal(TransactionJournal $journal): void
{
$this->journal = $journal;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->accountRepository->setUser($user);
}
/**
* @param string $direction
* @param Account|null $source
@@ -161,7 +149,7 @@ class TransactionFactory
* @return Account
* @throws FireflyException
*/
private function getAccount(string $direction, ?Account $source, ?int $sourceId, ?string $sourceName): Account
public function getAccount(string $direction, ?Account $source, ?int $sourceId, ?string $sourceName): Account
{
Log::debug(sprintf('Now in getAccount(%s)', $direction));
Log::debug(sprintf('Parameters: ((account), %s, %s)', var_export($sourceId, true), var_export($sourceName, true)));
@@ -169,21 +157,21 @@ class TransactionFactory
$array = [
'source' => [
TransactionType::WITHDRAWAL => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
TransactionType::DEPOSIT => [AccountType::REVENUE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
TransactionType::DEPOSIT => [AccountType::REVENUE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE,
AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION],
TransactionType::TRANSFER => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
TransactionType::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
AccountType::MORTGAGE],
TransactionType::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
AccountType::MORTGAGE],
TransactionType::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
],
'destination' => [
TransactionType::WITHDRAWAL => [AccountType::EXPENSE, AccountType::ASSET],
TransactionType::WITHDRAWAL => [AccountType::EXPENSE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT,
AccountType::MORTGAGE],
TransactionType::DEPOSIT => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
TransactionType::TRANSFER => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
TransactionType::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
AccountType::MORTGAGE],
TransactionType::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
AccountType::MORTGAGE],
TransactionType::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
],
];
$expectedTypes = $array[$direction];
@@ -208,12 +196,10 @@ class TransactionFactory
// second attempt, find by ID.
if (null !== $sourceId) {
$source = $this->accountRepository->findNull($sourceId);
if (null !== $source) {
Log::debug(sprintf('Found account #%d ("%s" of type "%s") based on #%d.', $source->id, $source->name, $source->accountType->type, $sourceId));
}
if (null !== $source && \in_array($source->accountType->type, $expectedTypes[$transactionType], true)) {
Log::debug(sprintf('Found "account_id" object for %s: #%d, %s', $direction, $source->id, $source->name));
Log::debug(
sprintf('Found "account_id" object for %s: #%d, "%s" of type %s', $direction, $source->id, $source->name, $source->accountType->type)
);
return $source;
}
@@ -232,6 +218,9 @@ class TransactionFactory
return $source;
}
}
if (null === $sourceName && \in_array(AccountType::CASH, $expectedTypes[$transactionType], true)) {
return $this->accountRepository->getCashAccount();
}
$sourceName = $sourceName ?? '(no name)';
// final attempt, create it.
$preferredType = $expectedTypes[$transactionType][0];
@@ -256,7 +245,7 @@ class TransactionFactory
* @return string
* @throws FireflyException
*/
private function getAmount(string $amount): string
public function getAmount(string $amount): string
{
if ('' === $amount) {
throw new FireflyException(sprintf('The amount cannot be an empty string: "%s"', $amount));
@@ -273,7 +262,7 @@ class TransactionFactory
*
* @return string
*/
private function getForeignAmount(?string $amount): ?string
public function getForeignAmount(?string $amount): ?string
{
if (null === $amount) {
Log::debug('No foreign amount info in array. Return NULL');
@@ -294,29 +283,78 @@ class TransactionFactory
return $amount;
}
//
// /**
// * @param string $sourceType
// * @param string $destinationType
// * @param string $transactionType
// *
// * @throws FireflyException
// */
// private function validateTransaction(string $sourceType, string $destinationType, string $transactionType): void
// {
// // throw big fat error when source type === dest type and it's not a transfer or reconciliation.
// if ($sourceType === $destinationType && $transactionType !== TransactionType::TRANSFER) {
// throw new FireflyException(sprintf('Source and destination account cannot be both of the type "%s"', $destinationType));
// }
// // source must be in this list AND dest must be in this list:
// $list = [AccountType::DEFAULT, AccountType::ASSET, AccountType::CREDITCARD, AccountType::CASH, AccountType::DEBT, AccountType::MORTGAGE,
// AccountType::LOAN, AccountType::MORTGAGE];
// if (
// !\in_array($sourceType, $list, true)
// && !\in_array($destinationType, $list, true)) {
// throw new FireflyException(sprintf('At least one of the accounts must be an asset account (%s, %s).', $sourceType, $destinationType));
// }
// }
/**
* This method will throw a Firefly III Exception of the source and destination account types are not OK.
*
* @throws FireflyException
*
* @param Account $source
* @param Account $destination
*/
public function makeDramaOverAccountTypes(Account $source, Account $destination): void
{
// if the source is X, then Y is allowed as destination.
$combinations = [
TransactionType::WITHDRAWAL => [
AccountType::ASSET => [AccountType::EXPENSE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE, AccountType::CASH],
AccountType::LOAN => [AccountType::EXPENSE],
AccountType::DEBT => [AccountType::EXPENSE],
AccountType::MORTGAGE => [AccountType::EXPENSE],
],
TransactionType::DEPOSIT => [
AccountType::REVENUE => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
AccountType::CASH => [AccountType::ASSET],
AccountType::LOAN => [AccountType::ASSET],
AccountType::DEBT => [AccountType::ASSET],
AccountType::MORTGAGE => [AccountType::ASSET],
],
TransactionType::TRANSFER => [
AccountType::ASSET => [AccountType::ASSET],
AccountType::LOAN => [AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
AccountType::DEBT => [AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
AccountType::MORTGAGE => [AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
],
TransactionType::OPENING_BALANCE => [
AccountType::ASSET => [AccountType::INITIAL_BALANCE],
AccountType::LOAN => [AccountType::INITIAL_BALANCE],
AccountType::DEBT => [AccountType::INITIAL_BALANCE],
AccountType::MORTGAGE => [AccountType::INITIAL_BALANCE],
AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
],
TransactionType::RECONCILIATION => [
AccountType::RECONCILIATION => [AccountType::ASSET],
AccountType::ASSET => [AccountType::RECONCILIATION],
],
];
$sourceType = $source->accountType->type;
$destType = $destination->accountType->type;
$journalType = $this->journal->transactionType->type;
$allowed = $combinations[$journalType][$sourceType] ?? [];
if (!\in_array($destType, $allowed, true)) {
throw new FireflyException(
sprintf(
'Journal of type "%s" has a source account of type "%s" and cannot accept a "%s"-account as destination, but only accounts of: %s', $journalType, $sourceType,
$destType, implode(', ', $combinations[$journalType][$sourceType])
)
);
}
}
/**
* @param TransactionJournal $journal
*/
public function setJournal(TransactionJournal $journal): void
{
$this->journal = $journal;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->accountRepository->setUser($user);
}
}

View File

@@ -58,8 +58,12 @@ class TransactionJournalFactory
private $currencyRepository;
/** @var array */
private $fields;
/** @var PiggyBankEventFactory */
private $piggyEventFactory;
/** @var PiggyBankRepositoryInterface */
private $piggyRepository;
/** @var TagFactory */
private $tagFactory;
/** @var TransactionFactory */
private $transactionFactory;
/** @var TransactionTypeRepositoryInterface */
@@ -89,6 +93,8 @@ class TransactionJournalFactory
$this->budgetRepository = app(BudgetRepositoryInterface::class);
$this->categoryRepository = app(CategoryRepositoryInterface::class);
$this->piggyRepository = app(PiggyBankRepositoryInterface::class);
$this->piggyEventFactory = app(PiggyBankEventFactory::class);
$this->tagFactory = app(TagFactory::class);
}
/**
@@ -101,6 +107,7 @@ class TransactionJournalFactory
*/
public function create(array $data): Collection
{
$data = new NullArrayObject($data);
Log::debug('Start of TransactionJournalFactory::create()');
$collection = new Collection;
$transactions = $data['transactions'] ?? [];
@@ -111,7 +118,7 @@ class TransactionJournalFactory
Log::debug(sprintf('Going to store a %s.', $type->type));
if (0 === \count($transactions)) {
Log::error('There are no transactions in the array, cannot continue.');
Log::error('There are no transactions in the array, the TransactionJournalFactory cannot continue.');
return new Collection;
}
@@ -122,12 +129,12 @@ class TransactionJournalFactory
Log::debug(sprintf('Now creating journal %d/%d', $index + 1, \count($transactions)));
/** Get basic fields */
$currency = $this->currencyRepository->findCurrency($transaction['currency'], $transaction['currency_id'], $transaction['currency_code']);
$currency = $this->currencyRepository->findCurrency($transaction['currency'], (int)$transaction['currency_id'], $transaction['currency_code']);
$foreignCurrency = $this->findForeignCurrency($transaction);
$bill = $this->billRepository->findBill($transaction['bill'], $transaction['bill_id'], $transaction['bill_name']);
$bill = $this->billRepository->findBill($transaction['bill'], (int)$transaction['bill_id'], $transaction['bill_name']);
$billId = TransactionType::WITHDRAWAL === $type->type && null !== $bill ? $bill->id : null;
$description = app('steam')->cleanString($transaction['description']);
$description = app('steam')->cleanString((string)$transaction['description']);
/** Create a basic journal. */
$journal = TransactionJournal::create(
@@ -136,7 +143,7 @@ class TransactionJournalFactory
'transaction_type_id' => $type->id,
'bill_id' => $billId,
'transaction_currency_id' => $currency->id,
'description' => $description,
'description' => '' === $description ? '(empty description)' : $description,
'date' => $carbon->format('Y-m-d H:i:s'),
'order' => 0,
'tag_count' => 0,
@@ -149,6 +156,17 @@ class TransactionJournalFactory
$this->transactionFactory->setJournal($journal);
$this->transactionFactory->createPair($transaction, $currency, $foreignCurrency);
// verify that journal has two transactions. Otherwise, delete and cancel.
$count = $journal->transactions()->count();
if (2 !== $count) {
// @codeCoverageIgnoreStart
Log::error(sprintf('The journal unexpectedly has %d transaction(s). This is not OK. Cancel operation.', $count));
$journal->delete();
return new Collection;
// @codeCoverageIgnoreEnd
}
/** Link all other data to the journal. */
/** Link budget */
@@ -206,7 +224,7 @@ class TransactionJournalFactory
public function storeGroup(Collection $collection, ?string $title): ?TransactionGroup
{
if ($collection->count() < 2) {
return null;
return null; // @codeCoverageIgnore
}
/** @var TransactionJournal $first */
$first = $collection->first();
@@ -235,32 +253,11 @@ class TransactionJournalFactory
return;
}
$piggyBank = $this->piggyRepository->findPiggyBank($data['piggy_bank'], $data['piggy_bank_id'], $data['piggy_bank_name']);
$piggyBank = $this->piggyRepository->findPiggyBank($data['piggy_bank'], (int)$data['piggy_bank_id'], $data['piggy_bank_name']);
if (null !== $piggyBank) {
/** @var PiggyBankEventFactory $factory */
$factory = app(PiggyBankEventFactory::class);
$factory->create($journal, $piggyBank);
$this->piggyEventFactory->create($journal, $piggyBank);
Log::debug('Create piggy event.');
}
/** @var PiggyBankFactory $factory */
$factory = app(PiggyBankFactory::class);
$factory->setUser($this->user);
$piggyBank = null;
if (isset($data['piggy_bank']) && $data['piggy_bank'] instanceof PiggyBank && $data['piggy_bank']->account->user_id === $this->user->id) {
Log::debug('Piggy found and belongs to user');
$piggyBank = $data['piggy_bank'];
}
if (null === $data['piggy_bank']) {
Log::debug('Piggy not found, search by piggy data.');
$piggyBank = $factory->find($data['piggy_bank_id'], $data['piggy_bank_name']);
}
if (null !== $piggyBank) {
return;
}
@@ -276,16 +273,14 @@ class TransactionJournalFactory
*/
public function storeTags(TransactionJournal $journal, ?array $tags): void
{
/** @var TagFactory $factory */
$factory = app(TagFactory::class);
$factory->setUser($journal->user);
$this->tagFactory->setUser($journal->user);
$set = [];
if (!\is_array($tags)) {
return; // @codeCoverageIgnore
return;
}
foreach ($tags as $string) {
if ('' !== $string) {
$tag = $factory->findOrCreate($string);
$tag = $this->tagFactory->findOrCreate($string);
if (null !== $tag) {
$set[] = $tag->id;
}
@@ -333,14 +328,6 @@ class TransactionJournalFactory
return;
}
$note = $journal->notes()->first();
if (null !== $note) {
try {
$note->delete();
} catch (Exception $e) {
Log::debug(sprintf('Journal service trait could not delete note: %s', $e->getMessage()));
}
}
}
/**
@@ -357,7 +344,7 @@ class TransactionJournalFactory
}
return $this->currencyRepository->findCurrency(
$transaction['foreign_currency'], $transaction['foreign_currency_id'], $transaction['foreign_currency_code']
$transaction['foreign_currency'], (int)$transaction['foreign_currency_id'], $transaction['foreign_currency_code']
);
}

View File

@@ -36,37 +36,31 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class Account.
*
* @property int $id
* @property string $name
* @property string $iban
* @property AccountType $accountType
* @property bool $active
* @property string $virtual_balance
* @property User $user
* @property string startBalance
* @property string endBalance
* @property string difference
* @property Carbon lastActivityDate
* @property Collection accountMeta
* @property bool encrypted
* @property int account_type_id
* @property Collection piggyBanks
* @property string $interest
* @property string $interestPeriod
* @property string accountTypeString
* @property Carbon created_at
* @property Carbon updated_at
* @property int $id
* @property string $name
* @property string $iban
* @property AccountType $accountType
* @property bool $active
* @property string $virtual_balance
* @property User $user
* @property string startBalance
* @property string endBalance
* @property string difference
* @property Carbon lastActivityDate
* @property Collection accountMeta
* @property bool encrypted
* @property int account_type_id
* @property Collection piggyBanks
* @property string $interest
* @property string $interestPeriod
* @property string accountTypeString
* @property Carbon created_at
* @property Carbon updated_at
* @SuppressWarnings (PHPMD.CouplingBetweenObjects)
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Support\Carbon|null $deleted_at
* @property int $user_id
* @property int $account_type_id
* @property bool $encrypted
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\AccountMeta[] $accountMeta
* @property-read string $edit_name
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Note[] $notes
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBank[] $piggyBanks
* @property \Illuminate\Support\Carbon|null $deleted_at
* @property int $user_id
* @property-read string $edit_name
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Note[] $notes
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Transaction[] $transactions
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\Account accountTypeIn($types)
* @method static bool|null forceDelete()
@@ -103,6 +97,7 @@ class Account extends Model
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'user_id' => 'integer',
'deleted_at' => 'datetime',
'active' => 'boolean',
'encrypted' => 'boolean',

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Journal;
use Carbon\Carbon;
use DB;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\TransactionJournalFactory;
@@ -320,6 +321,28 @@ class JournalRepository implements JournalRepositoryInterface
return 0;
}
/**
* Return the ID of the category linked to the journal (if any) or to the transactions (if any).
*
* @param TransactionJournal $journal
*
* @return int
*/
public function getJournalCategoryId(TransactionJournal $journal): int
{
$category = $journal->categories()->first();
if (null !== $category) {
return $category->id;
}
/** @noinspection NullPointerExceptionInspection */
$category = $journal->transactions()->first()->categories()->first();
if (null !== $category) {
return $category->id;
}
return 0;
}
/**
* Return the name of the category linked to the journal (if any) or to the transactions (if any).
*
@@ -615,6 +638,27 @@ class JournalRepository implements JournalRepositoryInterface
return $transaction->transactionJournal->piggyBankEvents()->get();
}
/**
* Returns all journals with more than 2 transactions. Should only return empty collections
* in Firefly III > v4.8.0.
*
* @return Collection
*/
public function getSplitJournals(): Collection
{
// grab all split transactions:
$all = Transaction::groupBy('transaction_journal_id')->get(['transaction_journal_id', DB::raw('COUNT(transaction_journal_id) as result')]);
/** @var Collection $filtered */
$filtered = $all->filter(
function (Transaction $transaction) {
return (int)$transaction->result > 2;
}
);
$journalIds = array_unique($filtered->pluck('transaction_journal_id')->toArray());
return TransactionJournal::whereIn('id', $journalIds)->get();
}
/**
* Return all tags as strings in an array.
*

View File

@@ -149,6 +149,15 @@ interface JournalRepositoryInterface
*/
public function getJournalBudgetId(TransactionJournal $journal): int;
/**
* Return the ID of the category linked to the journal (if any) or to the transactions (if any).
*
* @param TransactionJournal $journal
*
* @return int
*/
public function getJournalCategoryId(TransactionJournal $journal): int;
/**
* Return the name of the category linked to the journal (if any) or to the transactions (if any).
*
@@ -256,6 +265,14 @@ interface JournalRepositoryInterface
*/
public function getPiggyBankEventsbyTr(Transaction $transaction): Collection;
/**
* Returns all journals with more than 2 transactions. Should only return empty collections
* in Firefly III > v4.8.0.
*
* @return Collection
*/
public function getSplitJournals(): Collection;
/**
* Return all tags as strings in an array.
*

View File

@@ -81,16 +81,16 @@ trait RecurringTransactionTrait
$destination = null;
switch ($recurrence->transactionType->type) {
case TransactionType::WITHDRAWAL:
$source = $this->findAccount(AccountType::ASSET, $array['source_id'], $array['source_name']);
$destination = $this->findAccount(AccountType::EXPENSE, $array['destination_id'], $array['destination_name']);
$source = $this->findAccount(AccountType::ASSET, null, $array['source_id'], $array['source_name']);
$destination = $this->findAccount(AccountType::EXPENSE,null, $array['destination_id'], $array['destination_name']);
break;
case TransactionType::DEPOSIT:
$source = $this->findAccount(AccountType::REVENUE, $array['source_id'], $array['source_name']);
$destination = $this->findAccount(AccountType::ASSET, $array['destination_id'], $array['destination_name']);
$source = $this->findAccount(AccountType::REVENUE, null, $array['source_id'], $array['source_name']);
$destination = $this->findAccount(AccountType::ASSET, null, $array['destination_id'], $array['destination_name']);
break;
case TransactionType::TRANSFER:
$source = $this->findAccount(AccountType::ASSET, $array['source_id'], $array['source_name']);
$destination = $this->findAccount(AccountType::ASSET, $array['destination_id'], $array['destination_name']);
$source = $this->findAccount(AccountType::ASSET,null, $array['source_id'], $array['source_name']);
$destination = $this->findAccount(AccountType::ASSET, null, $array['destination_id'], $array['destination_name']);
break;
}
@@ -172,13 +172,14 @@ trait RecurringTransactionTrait
}
/**
* @param null|string $expectedType
* @param int|null $accountId
* @param null|string $accountName
* @param null|string $expectedType
* @param Account|null $account
* @param int|null $accountId
* @param null|string $accountName
*
* @return Account|null
*/
abstract public function findAccount(?string $expectedType, ?int $accountId, ?string $accountName): ?Account;
abstract public function findAccount(?string $expectedType, ?Account $account, ?int $accountId, ?string $accountName): ?Account;
/**
* Update meta data for recurring transaction.

View File

@@ -122,6 +122,14 @@ abstract class TestCase extends BaseTestCase
return $this->getRandomAccount(AccountType::ASSET);
}
/**
* @return Account
*/
public function getRandomLoan(): Account
{
return $this->getRandomAccount(AccountType::LOAN);
}
/**
* @return TransactionJournal
*/

View File

@@ -0,0 +1,176 @@
<?php
/**
* MigrateToGroupsTest.php
* Copyright (c) 2019 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 Tests\Unit\Console\Commands\Upgrade;
use Carbon\Carbon;
use FireflyConfig;
use FireflyIII\Factory\TransactionJournalFactory;
use FireflyIII\Models\Configuration;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
use Mockery;
use Tests\TestCase;
/**
* Class MigrateToGroupsTest
*/
class MigrateToGroupsTest extends TestCase
{
/**
*
*/
public function setUp(): void
{
parent::setUp();
Log::info(sprintf('Now in %s.', \get_class($this)));
}
/**
* @covers \FireflyIII\Console\Commands\Upgrade\MigrateToGroups
*/
public function testAlreadyExecuted(): void
{
$this->mock(TransactionJournalFactory::class);
$this->mock(JournalRepositoryInterface::class);
$configObject = new Configuration;
$configObject->data = true;
FireflyConfig::shouldReceive('get')->withArgs(['migrated_to_groups_4780', false])->andReturn($configObject)->once();
$this->artisan('firefly:migrate-to-groups')
->expectsOutput('Database already seems to be migrated.')
->assertExitCode(0);
}
/**
* @covers \FireflyIII\Console\Commands\Upgrade\MigrateToGroups
*/
public function testBasic(): void
{
$journalFactory = $this->mock(TransactionJournalFactory::class);
$journalRepos = $this->mock(JournalRepositoryInterface::class);
$withdrawal = $this->getRandomSplitWithdrawal();
$collection = new Collection([$withdrawal]);
$date = new Carbon;
$opposing = new Transaction;
$opposing->account_id = 13;
// not yet executed:
$configObject = new Configuration;
$configObject->data = false;
FireflyConfig::shouldReceive('get')->withArgs(['migrated_to_groups_4780', false])->andReturn($configObject)->once();
FireflyConfig::shouldReceive('set')->withArgs(['migrated_to_groups_4780', true])->once();
// calls to repository:
$journalRepos->shouldReceive('setUser')->atLeast()->once();
$journalRepos->shouldReceive('getJournalBudgetId')->atLeast()->once()->andReturn(1);
$journalRepos->shouldReceive('getJournalCategoryId')->atLeast()->once()->andReturn(2);
$journalRepos->shouldReceive('findOpposingTransaction')->atLeast()->once()->andReturn($opposing);
$journalRepos->shouldReceive('getNoteText')->atLeast()->once()->andReturn('I am some notes.');
$journalRepos->shouldReceive('getTags')->atLeast()->once()->andReturn(['a', 'b']);
$journalRepos->shouldReceive('getSplitJournals')->once()->andReturn($collection);
// all meta field calls.
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'internal-reference'])->andReturn('ABC');
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'sepa-cc'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'sepa-ct-op'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'sepa-ct-id'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'sepa-db'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'sepa-country'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'sepa-ep'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'sepa-ci'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'sepa-batch-id'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'external-id'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'original-source'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'recurrence_id'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'bunq_payment_id'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'importHash'])->andReturnNull();
$journalRepos->shouldReceive('getMetaField')->atLeast()->once()->withArgs([Mockery::any(), 'importHashV2'])->andReturnNull();
$journalRepos->shouldReceive('getMetaDate')->atLeast()->once()->withArgs([Mockery::any(), 'interest_date'])->andReturn($date);
$journalRepos->shouldReceive('getMetaDate')->atLeast()->once()->withArgs([Mockery::any(), 'book_date'])->andReturnNull();
$journalRepos->shouldReceive('getMetaDate')->atLeast()->once()->withArgs([Mockery::any(), 'process_date'])->andReturnNull();
$journalRepos->shouldReceive('getMetaDate')->atLeast()->once()->withArgs([Mockery::any(), 'due_date'])->andReturnNull();
$journalRepos->shouldReceive('getMetaDate')->atLeast()->once()->withArgs([Mockery::any(), 'payment_date'])->andReturnNull();
$journalRepos->shouldReceive('getMetaDate')->atLeast()->once()->withArgs([Mockery::any(), 'invoice_date'])->andReturnNull();
// calls to factory
$journalFactory->shouldReceive('setUser')->atLeast()->once();
$journalFactory->shouldReceive('create')->atLeast()->once()->withAnyArgs()->andReturn(new Collection());
$this->artisan('firefly:migrate-to-groups')
->expectsOutput('Going to un-split 1 transaction(s). This could take some time.')
->assertExitCode(0);
}
/**
* @covers \FireflyIII\Console\Commands\Upgrade\MigrateToGroups
*/
public function testForced(): void
{
$this->mock(TransactionJournalFactory::class);
$repository = $this->mock(JournalRepositoryInterface::class);
$repository->shouldReceive('getSplitJournals')->andReturn(new Collection);
$configObject = new Configuration;
$configObject->data = true;
FireflyConfig::shouldReceive('get')->withArgs(['migrated_to_groups_4780', false])->andReturn($configObject)->once();
FireflyConfig::shouldReceive('set')->withArgs(['migrated_to_groups_4780', true])->once();
$this->artisan('firefly:migrate-to-groups --force')
->expectsOutput('Forcing the migration.')
->expectsOutput('Found no split journals. Nothing to do.')
->assertExitCode(0);
}
/**
* @covers \FireflyIII\Console\Commands\Upgrade\MigrateToGroups
*/
public function testNotSplit(): void
{
$this->mock(TransactionJournalFactory::class);
$repository = $this->mock(JournalRepositoryInterface::class);
$withdrawal = $this->getRandomWithdrawal();
$repository->shouldReceive('getSplitJournals')->andReturn(new Collection([$withdrawal]));
$configObject = new Configuration;
$configObject->data = false;
FireflyConfig::shouldReceive('get')->withArgs(['migrated_to_groups_4780', false])->andReturn($configObject)->once();
FireflyConfig::shouldReceive('set')->withArgs(['migrated_to_groups_4780', true])->once();
$this->artisan('firefly:migrate-to-groups')
->expectsOutput('Going to un-split 1 transaction(s). This could take some time.')
->assertExitCode(0);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff