Start testing new rule actions.

This commit is contained in:
James Cole
2020-08-23 07:42:14 +02:00
parent d89a4d8a54
commit 6e074d9b8b
34 changed files with 608 additions and 246 deletions

View File

@@ -37,18 +37,6 @@ use Log;
*/
class TransactionCurrencyFactory
{
/**
* TransactionCurrencyFactory constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
}
/**
* @param array $data
*

View File

@@ -49,6 +49,7 @@ class AddTag implements ActionInterface
/**
* @inheritDoc
* @deprecated
* @codeCoverageIgnore
*/
public function act(TransactionJournal $journal): bool
{
@@ -57,6 +58,7 @@ class AddTag implements ActionInterface
$factory = app(TagFactory::class);
$factory->setUser($journal->user);
$tag = $factory->findOrCreate($this->action->action_value);
if (null === $tag) {
// could not find, could not create tag.
Log::error(sprintf('RuleAction AddTag. Could not find or create tag "%s"', $this->action->action_value));
@@ -86,12 +88,14 @@ class AddTag implements ActionInterface
$factory = app(TagFactory::class);
$factory->setUser(User::find($journal['user_id']));
$tag = $factory->findOrCreate($this->action->action_value);
// @codeCoverageIgnoreStart
if (null === $tag) {
// could not find, could not create tag.
Log::error(sprintf('RuleAction AddTag. Could not find or create tag "%s"', $this->action->action_value));
return false;
}
// @codeCoverageIgnoreEnd
$count = DB::table('tag_transaction_journal')
->where('tag_id', $tag->id)
->where('transaction_journal_id', $journal['transaction_journal_id'])

View File

@@ -48,7 +48,8 @@ class AppendDescription implements ActionInterface
* Append description with X
*
* @param TransactionJournal $journal
*
* @codeCoverageIgnore
* @deprecated
* @return bool
*/
public function act(TransactionJournal $journal): bool

View File

@@ -46,9 +46,9 @@ class AppendNotes implements ActionInterface
}
/**
* Append notes with X
*
* @param TransactionJournal $journal
* @deprecated
* @codeCoverageIgnore
*
* @return bool
*/
@@ -84,8 +84,6 @@ class AppendNotes implements ActionInterface
$dbNote->noteable_id = (int) $journal['transaction_journal_id'];
$dbNote->noteable_type = TransactionJournal::class;
$dbNote->text = '';
}
Log::debug(sprintf('RuleAction AppendNotes appended "%s" to "%s".', $this->action->action_value, $dbNote->text));
$text = sprintf('%s%s', $dbNote->text, $this->action->action_value);

View File

@@ -26,7 +26,7 @@ use FireflyIII\Models\RuleAction;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use Log;
use DB;
/**
* Class ClearBudget.
*/
@@ -45,8 +45,9 @@ class ClearBudget implements ActionInterface
* Clear all budgets
*
* @param TransactionJournal $journal
*
* @codeCoverageIgnore
* @return bool
* @deprecated
*/
public function act(TransactionJournal $journal): bool
{
@@ -63,4 +64,16 @@ class ClearBudget implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
DB::table('budget_transaction_journal')->where('transaction_journal_id', '=', $journal['transaction_journal_id'])->delete();
Log::debug(sprintf('RuleAction ClearBudget removed all budgets from journal %d.', $journal['transaction_journal_id']));
return true;
}
}

View File

@@ -21,7 +21,7 @@
declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions;
use DB;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
@@ -45,6 +45,8 @@ class ClearCategory implements ActionInterface
* Clear all categories
*
* @param TransactionJournal $journal
* @codeCoverageIgnore
* @deprecated
*
* @return bool
*/
@@ -63,4 +65,16 @@ class ClearCategory implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
DB::table('category_transaction_journal')->where('transaction_journal_id', '=', $journal['transaction_journal_id'])->delete();
Log::debug(sprintf('RuleAction ClearCategory removed all categories from journal %d.', $journal['transaction_journal_id']));
return true;
}
}

View File

@@ -27,7 +27,7 @@ use FireflyIII\Models\Note;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal;
use Log;
use DB;
/**
* Class ClearNotes.
*/
@@ -46,7 +46,8 @@ class ClearNotes implements ActionInterface
* Remove notes
*
* @param TransactionJournal $journal
*
* @codeCoverageIgnore
* @deprecated
* @return bool
* @throws Exception
*/
@@ -62,4 +63,17 @@ class ClearNotes implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
DB::table('notes')
->where('noteable_id', $journal['transaction_journal_id'])
->where('noteable_type', TransactionJournal::class)
->delete();
Log::debug(sprintf('RuleAction ClearNotes removed all notes.'));
return true;
}
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions;
use DB;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\AccountFactory;
use FireflyIII\Models\Account;
@@ -31,6 +32,7 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\User;
use Log;
/**
@@ -39,8 +41,7 @@ use Log;
*/
class ConvertToDeposit implements ActionInterface
{
/** @var RuleAction The rule action */
private $action;
private RuleAction $action;
/**
* TriggerInterface constructor.
@@ -56,7 +57,7 @@ class ConvertToDeposit implements ActionInterface
* Execute the action.
*
* @param TransactionJournal $journal
*
* @deprecated
* @return bool
* @throws FireflyException
*/
@@ -120,9 +121,9 @@ class ConvertToDeposit implements ActionInterface
* Output is a deposit from C to B.
*
* @param TransactionJournal $journal
*
* @return bool
* @throws FireflyException
* @deprecated
*/
private function convertTransfer(TransactionJournal $journal): bool
{
@@ -157,12 +158,55 @@ class ConvertToDeposit implements ActionInterface
return true;
}
/**
* Input is a transfer from A to B.
* Output is a deposit from C to B.
*
* @param array $journal
*
* @return bool
* @throws FireflyException
*/
private function convertTransferArray(array $journal): bool
{
$user = User::find($journal['user_id']);
// find or create revenue account.
/** @var AccountFactory $factory */
$factory = app(AccountFactory::class);
$factory->setUser($user);
// get the action value, or use the original source name in case the action value is empty:
// this becomes a new or existing revenue account.
$revenueName = '' === $this->action->action_value ? $journal['source_account_name'] : $this->action->action_value;
$revenue = $factory->findOrCreate($revenueName, AccountType::REVENUE);
Log::debug(sprintf('ConvertToDeposit. Action value is "%s", revenue name is "%s"', $this->action->action_value, $journal['source_account_name']));
unset($source);
// update source transaction(s) to be revenue account
DB::table('transactions')
->where('transaction_journal_id', '=', $journal['transaction_journal_id'])
->where('amount', '<', 0)
->update(['account_id' => $revenue->id]);
// change transaction type of journal:
$newType = TransactionType::whereType(TransactionType::DEPOSIT)->first();
DB::table('transaction_journals')
->where('id', '=', $journal['transaction_journal_id'])
->update(['transaction_type_id' => $newType->id]);
Log::debug('Converted transfer to deposit.');
return true;
}
/**
* Input is a withdrawal from A to B
* Is converted to a deposit from C to A.
*
* @param TransactionJournal $journal
*
* @deprecated
* @return bool
* @throws FireflyException
*/
@@ -209,4 +253,79 @@ class ConvertToDeposit implements ActionInterface
return true;
}
/**
* Input is a withdrawal from A to B
* Is converted to a deposit from C to A.
*
* @param array $journal
*
* @return bool
* @throws FireflyException
*/
private function convertWithdrawalArray(array $journal): bool
{
$user = User::find($journal['user_id']);
// find or create revenue account.
/** @var AccountFactory $factory */
$factory = app(AccountFactory::class);
$factory->setUser($user);
// get the action value, or use the original destination name in case the action value is empty:
// this becomes a new or existing revenue account.
$revenueName = '' === $this->action->action_value ? $journal['destination_account_name'] : $this->action->action_value;
$revenue = $factory->findOrCreate($revenueName, AccountType::REVENUE);
Log::debug(sprintf('ConvertToDeposit. Action value is "%s", revenue name is "%s"', $this->action->action_value, $journal['destination_account_name']));
// update the source transaction and put in the new revenue ID.
DB::table('transactions')
->where('transaction_journal_id', '=', $journal['transaction_journal_id'])
->where('amount', '<', 0)
->update(['account_id' => $revenue->id]);
// update the destination transaction and put in the original source account ID.
DB::table('transactions')
->where('transaction_journal_id', '=', $journal['transaction_journal_id'])
->where('amount', '>', 0)
->update(['account_id' => $journal['source_account_id']]);
// change transaction type of journal:
$newType = TransactionType::whereType(TransactionType::DEPOSIT)->first();
DB::table('transaction_journals')
->where('id', '=', $journal['transaction_journal_id'])
->update(['transaction_type_id' => $newType->id]);
Log::debug('Converted withdrawal to deposit.');
return true;
}
/**
* @inheritDoc
* @throws FireflyException
*/
public function actOnArray(array $journal): bool
{
Log::debug(sprintf('Convert journal #%d to deposit.', $journal['transaction_journal_id']));
$type = $journal['transaction_type_type'];
if (TransactionType::DEPOSIT === $type) {
Log::error(sprintf('Journal #%d is already a deposit (rule #%d).', $journal['transaction_journal_id'], $this->action->rule_id));
return false;
}
if (TransactionType::WITHDRAWAL === $type) {
Log::debug('Going to transform a withdrawal to a deposit.');
return $this->convertWithdrawalArray($journal);
}
if (TransactionType::TRANSFER === $type) {
Log::debug('Going to transform a transfer to a deposit.');
return $this->convertTransferArray($journal);
}
return false;
}
}

View File

@@ -30,7 +30,9 @@ use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\User;
use Log;
use DB;
/**
*
@@ -38,8 +40,7 @@ use Log;
*/
class ConvertToTransfer implements ActionInterface
{
/** @var RuleAction The rule action */
private $action;
private RuleAction $action;
/**
* TriggerInterface constructor.
@@ -53,7 +54,8 @@ class ConvertToTransfer implements ActionInterface
/**
* Execute the action.
*
* @deprecated
* @codeCoverageIgnore
* @param TransactionJournal $journal
*
* @return bool
@@ -135,7 +137,8 @@ class ConvertToTransfer implements ActionInterface
/**
* A deposit is from Revenue to Asset.
* We replace the Revenue with another asset.
*
* @deprecated
* @codeCoverageIgnore
* @param TransactionJournal $journal
* @param Account $assetAccount
*
@@ -173,7 +176,8 @@ class ConvertToTransfer implements ActionInterface
/**
* A withdrawal is from Asset to Expense.
* We replace the Expense with another asset.
*
* @deprecated
* @codeCoverageIgnore
* @param TransactionJournal $journal
* @param Account $assetAccount
*
@@ -207,4 +211,106 @@ class ConvertToTransfer implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
$type = $journal['transaction_type_type'];
$user = User::find($journal['user_id']);
if (TransactionType::TRANSFER === $type) {
Log::error(sprintf('Journal #%d is already a transfer so cannot be converted (rule #%d).', $journal['transaction_journal_id'], $this->action->rule_id));
return false;
}
// find the asset account in the action value.
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($user);
$asset = $repository->findByName($this->action->action_value, [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
if (null === $asset) {
Log::error(sprintf('Journal #%d cannot be converted because no asset with name "%s" exists (rule #%d).', $journal['transaction_journal_id'], $this->action->action_value, $this->action->rule_id));
return false;
}
if (TransactionType::WITHDRAWAL === $type) {
Log::debug('Going to transform a withdrawal to a transfer.');
return $this->convertWithdrawalArray($journal, $asset);
}
if (TransactionType::DEPOSIT === $type) {
Log::debug('Going to transform a deposit to a transfer.');
return $this->convertDepositArray($journal, $asset);
}
return false; // @codeCoverageIgnore
}
/**
* A deposit is from Revenue to Asset.
* We replace the Revenue with another asset.
* @param array $journal
* @param Account $asset
* @return bool
*/
private function convertDepositArray(array $journal, Account $asset): bool
{
if ($journal['destination_account_id'] === $asset->id) {
Log::error(vsprintf('Journal #%d has already has "%s" as a destination asset. ConvertToTransfer failed. (rule #%d).', [$journal['transaction_journal_id'], $asset->name, $this->action->rule_id]));
return false;
}
// update source transaction:
DB::table('transactions')
->where('transaction_journal_id', '=', $journal['transaction_journal_id'])
->where('amount', '<', 0)
->update(['account_id' => $asset->id]);
// change transaction type of journal:
$newType = TransactionType::whereType(TransactionType::TRANSFER)->first();
DB::table('transaction_journals')
->where('id', '=', $journal['transaction_journal_id'])
->update(['transaction_type_id' => $newType->id]);
Log::debug('Converted deposit to transfer.');
return true;
}
/**
* A withdrawal is from Asset to Expense.
* We replace the Expense with another asset.
* @param array $journal
* @param Account $asset
* @return bool
*/
private function convertWithdrawalArray(array $journal, Account $asset): bool
{
if ($journal['source_account_id'] === $asset->id) {
Log::error(vsprintf('Journal #%d has already has "%s" as a source asset. ConvertToTransfer failed. (rule #%d).', [$journal['transaction_journal_id'], $asset->name, $this->action->rule_id]));
return false;
}
// update destination transaction:
DB::table('transactions')
->where('transaction_journal_id', '=', $journal['transaction_journal_id'])
->where('amount', '>', 0)
->update(['account_id' => $asset->id]);
// change transaction type of journal:
$newType = TransactionType::whereType(TransactionType::TRANSFER)->first();
DB::table('transaction_journals')
->where('id', '=', $journal['transaction_journal_id'])
->update(['transaction_type_id' => $newType->id]);
Log::debug('Converted withdrawal to transfer.');
return true;
}
}

View File

@@ -210,4 +210,12 @@ class ConvertToWithdrawal implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -78,4 +78,12 @@ class DeleteTransaction implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -76,4 +76,12 @@ class LinkToBill implements ActionInterface
return false;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -59,4 +59,12 @@ class PrependDescription implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -68,4 +68,12 @@ class PrependNotes implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -55,4 +55,12 @@ class RemoveAllTags implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -68,4 +68,12 @@ class RemoveTag implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -83,4 +83,12 @@ class SetBudget implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -72,4 +72,12 @@ class SetCategory implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -69,4 +69,12 @@ class SetDescription implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -168,4 +168,12 @@ class SetDestinationAccount implements ActionInterface
Log::debug(sprintf('Found or created expense account #%d ("%s")', $account->id, $account->name));
$this->newDestinationAccount = $account;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -68,4 +68,12 @@ class SetNotes implements ActionInterface
return true;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -158,4 +158,12 @@ class SetSourceAccount implements ActionInterface
Log::debug(sprintf('Found or created revenue account #%d ("%s")', $account->id, $account->name));
$this->newSourceAccount = $account;
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -184,4 +184,12 @@ class UpdatePiggybank implements ActionInterface
$repository->removeAmount($piggyBank, $amount);
$repository->createEventWithJournal($piggyBank, app('steam')->negative($amount), $journal);
}
/**
* @inheritDoc
*/
public function actOnArray(array $journal): bool
{
// TODO: Implement actOnArray() method.
}
}

View File

@@ -36,6 +36,7 @@ use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
use Log;
use Mockery;
use Preferences;
@@ -95,7 +96,10 @@ class AccountFactoryTest extends TestCase
$this->assertEquals(0, $account->order);
$this->assertNull($account->virtual_balance);
$account->forceDelete();
// use delete service:
$service = app(AccountDestroyService::class);
$service->destroy($account, null);
}
@@ -141,7 +145,9 @@ class AccountFactoryTest extends TestCase
$this->assertNull($account->virtual_balance);
$this->assertCount(1, $account->locations()->get());
$account->forceDelete();
// use delete service:
$service = app(AccountDestroyService::class);
$service->destroy($account, null);
}
/**
@@ -184,7 +190,9 @@ class AccountFactoryTest extends TestCase
$this->assertNull($account->virtual_balance);
$this->assertNull($account->iban);
$account->forceDelete();
// use delete service:
$service = app(AccountDestroyService::class);
$service->destroy($account, null);
}
/**
@@ -227,7 +235,9 @@ class AccountFactoryTest extends TestCase
$this->assertNull($account->virtual_balance);
$this->assertEquals($data['iban'], $account->iban);
$account->forceDelete();
// use delete service:
$service = app(AccountDestroyService::class);
$service->destroy($account, null);
}
/**
@@ -273,7 +283,9 @@ class AccountFactoryTest extends TestCase
$this->assertNull($account->virtual_balance);
$this->assertCount(1, $account->transactions()->get());
$account->forceDelete();
// use delete service:
$service = app(AccountDestroyService::class);
$service->destroy($account, null);
}
/**
* Create asset, include opening balance.
@@ -318,7 +330,9 @@ class AccountFactoryTest extends TestCase
$this->assertNull($account->virtual_balance);
$this->assertCount(1, $account->transactions()->get());
$account->forceDelete();
// use delete service:
$service = app(AccountDestroyService::class);
$service->destroy($account, null);
}
/**
@@ -364,7 +378,9 @@ class AccountFactoryTest extends TestCase
$this->assertNull($account->virtual_balance);
$this->assertCount(0, $account->transactions()->get());
$account->forceDelete();
// use delete service:
$service = app(AccountDestroyService::class);
$service->destroy($account, null);
}
@@ -410,7 +426,9 @@ class AccountFactoryTest extends TestCase
$this->assertEquals(0, $account->order);
$this->assertNull($account->virtual_balance);
$account->forceDelete();
// use delete service:
$service = app(AccountDestroyService::class);
$service->destroy($account, null);
}

View File

@@ -73,6 +73,7 @@ class AttachmentFactoryTest extends TestCase
$this->assertEquals($data['title'], $result->title);
$this->assertEquals(1, $result->notes()->count());
$result->forceDelete();
}
@@ -104,6 +105,8 @@ class AttachmentFactoryTest extends TestCase
$this->assertEquals(1, $result->notes()->count());
$this->assertEquals($journal->id, $result->attachable_id);
$result->forceDelete();
}
}

View File

@@ -955,10 +955,7 @@ class OperatorQuerySearchTest extends TestCase
// many results, tricky to verify.
$this->assertTrue(count($result) > 2);
// the first one should say "Groceries".
$transaction = array_shift($result->first()['transactions']);
$this->assertEquals('Groceries', $transaction['description'] ?? '');
// TODO better verification.
}
/**
@@ -1033,10 +1030,7 @@ class OperatorQuerySearchTest extends TestCase
// many results, tricky to verify.
$this->assertTrue(count($result) > 2);
// the first one should say "Groceries".
$transaction = array_shift($result->first()['transactions']);
$this->assertEquals('Groceries', $transaction['description'] ?? '');
// todo verify
}
@@ -1304,10 +1298,8 @@ class OperatorQuerySearchTest extends TestCase
// could have many results, grab first transaction:
$this->assertTrue( count($result) > 1);
$transaction = array_shift($result->first()['transactions']);
// check if result is as expected.
$this->assertEquals('Groceries', $transaction['description'] ?? '');
// todo better verification
}
/**

View File

@@ -22,18 +22,15 @@ declare(strict_types=1);
namespace Tests\Unit\TransactionRules\Actions;
use FireflyIII\Factory\TagFactory;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\Tag;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\TransactionRules\Actions\AddTag;
use Log;
use Tests\TestCase;
/**
* Class AddTagTest
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
*/
class AddTagTest extends TestCase
{
@@ -42,9 +39,6 @@ class AddTagTest extends TestCase
*/
public function setUp(): void
{
self::markTestIncomplete('Incomplete for refactor.');
return;
parent::setUp();
Log::info(sprintf('Now in %s.', get_class($this)));
}
@@ -54,9 +48,11 @@ class AddTagTest extends TestCase
*/
public function testActExistingTag(): void
{
$tagFactory = $this->mock(TagFactory::class);
$tag = $this->getRandomTag();
$journal = $this->getRandomWithdrawal();
/** @var Tag $tag */
$tag = $this->user()->tags()->where('tag', 'RuleActionTag')->first();
/** @var TransactionJournal $journal */
$journal = $this->user()->transactionJournals()->where('description', 'Rule action test transaction.')->first();
// make sure journal has no tags:
$journal->tags()->sync([]);
@@ -65,18 +61,20 @@ class AddTagTest extends TestCase
// add single existing tag:
$journal->tags()->sync([$tag->id]);
$tagFactory->shouldReceive('setUser')->once();
$tagFactory->shouldReceive('findOrCreate')->once()->withArgs([$tag->tag])->andReturn($tag);
// assert connection exists.
$this->assertDatabaseHas('tag_transaction_journal', ['tag_id' => $tag->id, 'transaction_journal_id' => $journal->id]);
// file action
// array with data required:
$array = [
'user_id' => $this->user()->id,
'transaction_journal_id' => $journal->id,
];
// run the action:
$ruleAction = new RuleAction;
$ruleAction->action_value = $tag->tag;
$action = new AddTag($ruleAction);
$result = $action->act($journal);
$result = $action->actOnArray($array);
$this->assertFalse($result);
// assert DB is unchanged.
@@ -89,28 +87,30 @@ class AddTagTest extends TestCase
*/
public function testActNewTag(): void
{
$tagFactory = $this->mock(TagFactory::class);
$tag = $this->getRandomTag();
$journal = $this->getRandomWithdrawal();
/** @var Tag $tag */
$tag = $this->user()->tags()->where('tag', 'RuleActionTag')->first();
/** @var TransactionJournal $journal */
$journal = $this->user()->transactionJournals()->where('description', 'Rule action test transaction.')->first();
// make sure journal has no tags:
$journal->tags()->sync([]);
$journal->save();
$tagFactory->shouldReceive('setUser')->once();
$tagFactory->shouldReceive('findOrCreate')->once()->withArgs([$tag->tag])->andReturn($tag);
// array with data required:
$array = [
'user_id' => $this->user()->id,
'transaction_journal_id' => $journal->id,
];
// assert connection does not exist.
$this->assertDatabaseMissing('tag_transaction_journal', ['tag_id' => $tag->id, 'transaction_journal_id' => $journal->id]);
// file action
// run the action:
$ruleAction = new RuleAction;
$ruleAction->action_value = $tag->tag;
$action = new AddTag($ruleAction);
$result = $action->act($journal);
$result = $action->actOnArray($array);
$this->assertTrue($result);
// assert DB is unchanged.
// assert DB is updated! Yay!
$this->assertDatabaseHas('tag_transaction_journal', ['tag_id' => $tag->id, 'transaction_journal_id' => $journal->id]);
}
@@ -119,19 +119,34 @@ class AddTagTest extends TestCase
*/
public function testActNullTag(): void
{
// try to add non-existing tag
$tagFactory = $this->mock(TagFactory::class);
$newTagName = 'TestTag-' . $this->randomInt();
$newTagName = sprintf('TestTag-%d', $this->randomInt());
// should return null:
$tagFactory->shouldReceive('setUser')->once();
$tagFactory->shouldReceive('findOrCreate')->once()->withArgs([$newTagName])->andReturnNull();
/** @var TransactionJournal $journal */
$journal = $this->user()->transactionJournals()->where('description', 'Rule action test transaction.')->first();
$journal = $this->getRandomWithdrawal();
// make sure journal has no tags:
$journal->tags()->sync([]);
$journal->save();
// array with data required:
$array = [
'user_id' => $this->user()->id,
'transaction_journal_id' => $journal->id,
];
// run the action:
$ruleAction = new RuleAction;
$ruleAction->action_value = $newTagName;
$action = new AddTag($ruleAction);
$result = $action->act($journal);
$this->assertFalse($result);
$result = $action->actOnArray($array);
$this->assertTrue($result);
// find the tag in the DB:
$this->assertDatabaseHas('tags', ['tag' => $newTagName]);
$tag = Tag::whereTag($newTagName)->first();
// assert DB is updated! Yay!
$this->assertDatabaseHas('tag_transaction_journal', ['tag_id' => $tag->id, 'transaction_journal_id' => $journal->id]);
}
}

View File

@@ -30,9 +30,6 @@ use Tests\TestCase;
/**
* Class AppendDescriptionTest
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
*/
class AppendDescriptionTest extends TestCase
{
@@ -41,9 +38,6 @@ class AppendDescriptionTest extends TestCase
*/
public function setUp(): void
{
self::markTestIncomplete('Incomplete for refactor.');
return;
parent::setUp();
Log::info(sprintf('Now in %s.', get_class($this)));
}
@@ -53,15 +47,26 @@ class AppendDescriptionTest extends TestCase
*/
public function testActExistingTag(): void
{
/** @var TransactionJournal $journal */
$journal = $this->user()->transactionJournals()->where('description', 'Rule action test transaction.')->first();
$original = $journal->description;
$array = [
'transaction_journal_id' => $journal->id,
'description' => $original,
];
$ruleAction = new RuleAction;
$ruleAction->action_value = 'APPEND';
$journal = $this->getRandomWithdrawal();
$oldDescription = $journal->description;
$action = new AppendDescription($ruleAction);
$result = $action->act($journal);
$result = $action->actOnArray($array);
$this->assertTrue($result);
$journal = TransactionJournal::find($journal->id);
$this->assertEquals($oldDescription . 'APPEND', $journal->description);
$this->assertEquals(sprintf('%s%s', $original, $ruleAction->action_value), $journal->description);
$journal->description = $original;
$journal->save();
}
}

View File

@@ -28,12 +28,9 @@ use FireflyIII\Models\TransactionJournal;
use FireflyIII\TransactionRules\Actions\AppendNotes;
use Log;
use Tests\TestCase;
use DB;
/**
* Class AppendNotesTest
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
*/
class AppendNotesTest extends TestCase
{
@@ -42,9 +39,6 @@ class AppendNotesTest extends TestCase
*/
public function setUp(): void
{
self::markTestIncomplete('Incomplete for refactor.');
return;
parent::setUp();
Log::info(sprintf('Now in %s.', get_class($this)));
}
@@ -52,52 +46,29 @@ class AppendNotesTest extends TestCase
/**
* @covers \FireflyIII\TransactionRules\Actions\AppendNotes
*/
public function testAct(): void
public function testActOnArray(): void
{
// give journal some notes.
$journal = $this->getRandomWithdrawal();
$note = $journal->notes()->first();
$start = 'Default note text';
$toAppend = 'This is appended';
if (null === $note) {
$note = new Note();
$note->noteable()->associate($journal);
}
$note->text = $start;
$note->save();
$journal = $this->user()->transactionJournals()->where('description','Rule action note test transaction.')->first();
// make sure all notes deleted:
DB::table('notes')->where('noteable_id', $journal->id)->where('noteable_type', TransactionJournal::class)->delete();
// array for action:
$array = [
'transaction_journal_id' => $journal->id
];
$toAppend = 'Text to append to note.';
// fire the action:
$ruleAction = new RuleAction;
$ruleAction->action_value = $toAppend;
$action = new AppendNotes($ruleAction);
$result = $action->act($journal);
$this->assertTrue($result);
$newNote = $journal->notes()->first();
$this->assertEquals($start . $toAppend, $newNote->text);
}
/**
* @covers \FireflyIII\TransactionRules\Actions\AppendNotes
*/
public function testActNewNote(): void
{
// give journal some notes.
$journal = TransactionJournal::find(4);
$note = $journal->notes()->first();
if (null !== $note) {
$note->forceDelete();
}
$toAppend = 'This is appended';
// fire the action:
$ruleAction = new RuleAction;
$ruleAction->action_value = $toAppend;
$action = new AppendNotes($ruleAction);
$result = $action->act($journal);
$result = $action->actOnArray($array);
$this->assertTrue($result);
$newNote = $journal->notes()->first();
$this->assertEquals($toAppend, $newNote->text);
}
}

View File

@@ -30,9 +30,6 @@ use Tests\TestCase;
/**
* Class ClearBudgetTest
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
*/
class ClearBudgetTest extends TestCase
{
@@ -41,9 +38,6 @@ class ClearBudgetTest extends TestCase
*/
public function setUp(): void
{
self::markTestIncomplete('Incomplete for refactor.');
return;
parent::setUp();
Log::info(sprintf('Now in %s.', get_class($this)));
}
@@ -54,26 +48,25 @@ class ClearBudgetTest extends TestCase
public function testAct(): void
{
// associate budget with journal:
$journal = $this->getRandomWithdrawal();
$budget = $this->getRandomBudget();
$journal = $this->user()->transactionJournals()->where('description','Rule action test transaction.')->first();
$budget = $this->user()->budgets()->inRandomOrder()->first();
// link a budget.
$journal->budgets()->save($budget);
$this->assertGreaterThan(0, $journal->budgets()->count());
$array = [
'transaction_journal_id' => $journal->id
];
// fire the action:
$ruleAction = new RuleAction;
$ruleAction->action_value = null;
$action = new ClearBudget($ruleAction);
$result = $action->act($journal);
$result = $action->actOnArray($array);
$this->assertTrue($result);
// assert result
$this->assertEquals(0, $journal->budgets()->count());
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
$this->assertEquals(0, $transaction->budgets()->count());
}
}
}

View File

@@ -23,16 +23,12 @@ declare(strict_types=1);
namespace Tests\Unit\TransactionRules\Actions;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\Transaction;
use FireflyIII\TransactionRules\Actions\ClearCategory;
use Log;
use Tests\TestCase;
/**
* Class ClearCategoryTest
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
*/
class ClearCategoryTest extends TestCase
{
@@ -41,9 +37,6 @@ class ClearCategoryTest extends TestCase
*/
public function setUp(): void
{
self::markTestIncomplete('Incomplete for refactor.');
return;
parent::setUp();
Log::info(sprintf('Now in %s.', get_class($this)));
}
@@ -54,24 +47,25 @@ class ClearCategoryTest extends TestCase
public function testAct(): void
{
// associate budget with journal:
$journal = $this->getRandomWithdrawal();
$category = $this->getRandomCategory();;
$journal = $this->user()->transactionJournals()->where('description', 'Rule action test transaction.')->first();
$category = $this->user()->categories()->inRandomOrder()->first();
// link a budget.
$journal->categories()->save($category);
$this->assertGreaterThan(0, $journal->categories()->count());
$array = [
'transaction_journal_id' => $journal->id,
];
// fire the action:
$ruleAction = new RuleAction;
$ruleAction->action_value = null;
$action = new ClearCategory($ruleAction);
$result = $action->act($journal);
$result = $action->actOnArray($array);
$this->assertTrue($result);
// assert result
$this->assertEquals(0, $journal->categories()->count());
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
$this->assertEquals(0, $transaction->categories()->count());
}
}
}

View File

@@ -32,9 +32,6 @@ use Tests\TestCase;
/**
* Class ClearNotesTest
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
*/
class ClearNotesTest extends TestCase
{
@@ -43,9 +40,6 @@ class ClearNotesTest extends TestCase
*/
public function setUp(): void
{
self::markTestIncomplete('Incomplete for refactor.');
return;
parent::setUp();
Log::info(sprintf('Now in %s.', get_class($this)));
}
@@ -56,7 +50,7 @@ class ClearNotesTest extends TestCase
public function testAct(): void
{
// give journal a note:
$journal = $this->getRandomWithdrawal();
$journal = $this->user()->transactionJournals()->where('description', 'Rule action test transaction.')->first();
$note = $journal->notes()->first();
if (null === $note) {
$note = new Note;
@@ -70,8 +64,13 @@ class ClearNotesTest extends TestCase
$ruleAction = new RuleAction;
$ruleAction->action_value = null;
$action = new ClearNotes($ruleAction);
$array = [
'transaction_journal_id' => $journal->id
];
try {
$result = $action->act($journal);
$result = $action->actOnArray($array);
} catch (Exception $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());

View File

@@ -26,8 +26,10 @@ namespace Tests\Unit\TransactionRules\Actions;
use Exception;
use FireflyIII\Factory\AccountFactory;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\TransactionRules\Actions\ConvertToDeposit;
use Log;
@@ -36,9 +38,6 @@ use Tests\TestCase;
/**
*
* Class ConvertToDepositTest
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
*/
class ConvertToDepositTest extends TestCase
{
@@ -47,9 +46,6 @@ class ConvertToDepositTest extends TestCase
*/
public function setUp(): void
{
self::markTestIncomplete('Incomplete for refactor.');
return;
parent::setUp();
Log::info(sprintf('Now in %s.', get_class($this)));
}
@@ -61,35 +57,36 @@ class ConvertToDepositTest extends TestCase
*/
public function testActTransfer(): void
{
$revenue = $this->getRandomRevenue();
$name = 'Random revenue #' . $this->randomInt();
$journal = $this->getRandomTransfer();
/** @var TransactionJournal $transfer */
$transfer = $this->user()->transactionJournals()->where('description', 'Transfer for convertToDeposit.')->first();
$name = sprintf('Random revenue #%d', $this->randomInt());
// journal is a transfer:
$this->assertEquals(TransactionType::TRANSFER, $journal->transactionType->type);
// mock used stuff:
$factory = $this->mock(AccountFactory::class);
$factory->shouldReceive('setUser')->once();
$factory->shouldReceive('findOrCreate')->once()->withArgs([$name, AccountType::REVENUE])->andReturn($revenue);
$this->assertEquals(TransactionType::TRANSFER, $transfer->transactionType->type);
// make array for action:
$array = [
'transaction_journal_id' => $transfer->id,
'transaction_type_type' => $transfer->transactionType->type,
'user_id' => $this->user()->id,
'source_account_name' => 'Checking Account',
];
// fire the action:
$ruleAction = new RuleAction;
$ruleAction->action_value = $name;
$action = new ConvertToDeposit($ruleAction);
try {
$result = $action->act($journal);
$result = $action->actOnArray($array);
} catch (Exception $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$this->assertTrue(false, $e->getMessage());
}
$this->assertTrue($result);
// journal is now a deposit.
$journal->refresh();
$this->assertEquals(TransactionType::DEPOSIT, $journal->transactionType->type);
// get journal:
$transfer->refresh();
$this->assertEquals(TransactionType::DEPOSIT, $transfer->transactionType->type);
}
/**
@@ -99,36 +96,39 @@ class ConvertToDepositTest extends TestCase
*/
public function testActWithdrawal(): void
{
$revenue = $this->getRandomRevenue();
$name = 'Random revenue #' . $this->randomInt();
$journal = $this->getRandomWithdrawal();
/** @var TransactionJournal $withdrawal */
$withdrawal = $this->user()->transactionJournals()->where('description', 'Withdrawal for convertToDeposit.')->first();
$name = sprintf('Random revenue #%d', $this->randomInt());
// journal is a withdrawal:
$this->assertEquals(TransactionType::WITHDRAWAL, $journal->transactionType->type);
$this->assertEquals(TransactionType::WITHDRAWAL, $withdrawal->transactionType->type);
// mock used stuff:
$factory = $this->mock(AccountFactory::class);
$factory->shouldReceive('setUser')->once();
$factory->shouldReceive('findOrCreate')->once()->withArgs([$name, AccountType::REVENUE])->andReturn($revenue);
// quick DB search for original source:
$source = Account::where('name', 'Checking Account')->first();
// make array for action:
$array = [
'transaction_journal_id' => $withdrawal->id,
'transaction_type_type' => $withdrawal->transactionType->type,
'user_id' => $this->user()->id,
'destination_account_name' => 'SuperMarket',
'source_account_id' => $source->id,
];
// fire the action:
$ruleAction = new RuleAction;
$ruleAction->action_value = $name;
$action = new ConvertToDeposit($ruleAction);
try {
$result = $action->act($journal);
$result = $action->actOnArray($array);
} catch (Exception $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$this->assertTrue(false, $e->getMessage());
}
$this->assertTrue($result);
// journal is now a deposit.
$journal->refresh();
$this->assertEquals(TransactionType::DEPOSIT, $journal->transactionType->type);
// get journal:
$withdrawal->refresh();
$this->assertEquals(TransactionType::DEPOSIT, $withdrawal->transactionType->type);
}
}

View File

@@ -25,11 +25,11 @@ namespace Tests\Unit\TransactionRules\Actions;
use Exception;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Account;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\TransactionRules\Actions\ConvertToTransfer;
use Log;
use Tests\TestCase;
@@ -48,9 +48,6 @@ class ConvertToTransferTest extends TestCase
*/
public function setUp(): void
{
self::markTestIncomplete('Incomplete for refactor.');
return;
parent::setUp();
Log::info(sprintf('Now in %s.', get_class($this)));
}
@@ -62,30 +59,33 @@ class ConvertToTransferTest extends TestCase
*/
public function testActDeposit(): void
{
$deposit = $this->getRandomDeposit();
/** @var TransactionJournal $deposit */
$deposit = $this->user()->transactionJournals()->where('description', 'Deposit for ConvertToTransferTest.')->first();
// make sure that $asset is not the destination account of $deposit:
$forbiddenId = (int)$deposit->transactions()->where('amount', '>', 0)->first()->account_id;
$asset = $this->getRandomAsset($forbiddenId);
// get new source account (replaces the revenue account):
$newSource = Account::whereName('Savings Account')->first();
$destination = Account::whereName('Checking Account')->first();
// journal is a withdrawal:
$this->assertEquals(TransactionType::DEPOSIT, $deposit->transactionType->type);
// mock used stuff:
$accountRepos = $this->mock(AccountRepositoryInterface::class);
$accountRepos->shouldReceive('setUser')->once();
$accountRepos->shouldReceive('findByName')->withArgs(
[$asset->name,
[AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]]
)->andReturn($asset);
// make the required array:
$array = [
'transaction_journal_id' => $deposit->id,
'transaction_type_type' => $deposit->transactionType->type,
'user_id' => 1,
'destination_account_id' => $destination->id,
];
// fire the action:
$rule = new Rule;
$rule->title = 'OK';
$ruleAction = new RuleAction;
$ruleAction->action_value = $asset->name;
$ruleAction->action_value = 'Savings Account';
$ruleAction->rule = $rule;
$action = new ConvertToTransfer($ruleAction);
try {
$result = $action->act($deposit);
$result = $action->actOnArray($array);
} catch (Exception $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
@@ -105,27 +105,30 @@ class ConvertToTransferTest extends TestCase
*/
public function testActWithdrawal(): void
{
$withdrawal = $this->getRandomWithdrawal();
/** @var TransactionJournal $withdrawal */
$withdrawal = $this->user()->transactionJournals()->where('description', 'Withdrawal for ConvertToTransferTest.')->first();
// make sure that $asset is not the source account of $withdrawal:
$forbiddenId = (int)$withdrawal->transactions()->where('amount', '<', 0)->first()->account_id;
$asset = $this->getRandomAsset($forbiddenId);
// mock used stuff:
$accountRepos = $this->mock(AccountRepositoryInterface::class);
$accountRepos->shouldReceive('setUser')->once();
$accountRepos->shouldReceive('findByName')->withArgs([$asset->name, [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]])->andReturn($asset);
// new asset to link to destination of withdrawal:
$newDestination = Account::whereName('Savings Account')->first();
$source = Account::whereName('Checking Account')->first();
// array with necessary data:
$array = [
'transaction_journal_id' => $withdrawal->id,
'transaction_type_type' => $withdrawal->transactionType->type,
'user_id' => 1,
'source_account_id' => $source->id,
];
// fire the action:
$rule = new Rule;
$rule->title = 'OK';
$ruleAction = new RuleAction;
$ruleAction->action_value = $asset->name;
$ruleAction->action_value = $newDestination->name;
$ruleAction->rule = $rule;
$action = new ConvertToTransfer($ruleAction);
try {
$result = $action->act($withdrawal);
$result = $action->actOnArray($array);
} catch (Exception $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());