Move import to factory #1222

This commit is contained in:
James Cole
2018-03-24 14:05:29 +01:00
parent 796ab4bf2c
commit 3c9b7c07af
8 changed files with 180 additions and 225 deletions

View File

@@ -68,6 +68,7 @@ class TransactionJournalFactory
); );
// store basic transactions: // store basic transactions:
/** @var TransactionFactory $factory */
$factory = app(TransactionFactory::class); $factory = app(TransactionFactory::class);
$factory->setUser($this->user); $factory->setUser($this->user);
@@ -91,13 +92,12 @@ class TransactionJournalFactory
$this->storeNote($journal, strval($data['notes'])); $this->storeNote($journal, strval($data['notes']));
// store date meta fields (if present): // store date meta fields (if present):
$this->storeMeta($journal, $data, 'interest_date'); $fields = ['sepa-cc', 'sepa-ct-op', 'sepa-ct-id', 'sepa-db', 'sepa-country', 'sepa-ep', 'sepa-ci', 'interest_date', 'book_date', 'process_date',
$this->storeMeta($journal, $data, 'book_date'); 'due_date', 'payment_date', 'invoice_date', 'internal_reference',];
$this->storeMeta($journal, $data, 'process_date');
$this->storeMeta($journal, $data, 'due_date'); foreach ($fields as $field) {
$this->storeMeta($journal, $data, 'payment_date'); $this->storeMeta($journal, $data, $field);
$this->storeMeta($journal, $data, 'invoice_date'); }
$this->storeMeta($journal, $data, 'internal_reference');
Log::debug('End of TransactionJournalFactory::create()'); Log::debug('End of TransactionJournalFactory::create()');
return $journal; return $journal;

View File

@@ -53,9 +53,9 @@ class ImportBudget
} }
/** /**
* @return Budget * @return Budget|null
*/ */
public function getBudget(): Budget public function getBudget(): ?Budget
{ {
if (null === $this->budget) { if (null === $this->budget) {
$this->store(); $this->store();

View File

@@ -53,9 +53,9 @@ class ImportCategory
} }
/** /**
* @return Category * @return null|Category
*/ */
public function getCategory(): Category public function getCategory(): ?Category
{ {
if (null === $this->category) { if (null === $this->category) {
$this->store(); $this->store();

View File

@@ -24,6 +24,7 @@ namespace FireflyIII\Import\Object;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Import\Converter\Amount;
use FireflyIII\Import\Converter\ConverterInterface; use FireflyIII\Import\Converter\ConverterInterface;
use FireflyIII\Import\MapperPreProcess\PreProcessorInterface; use FireflyIII\Import\MapperPreProcess\PreProcessorInterface;
use FireflyIII\User; use FireflyIII\User;
@@ -36,6 +37,7 @@ use Steam;
*/ */
class ImportJournal class ImportJournal
{ {
/** @var ImportAccount */ /** @var ImportAccount */
public $asset; public $asset;
/** @var ImportBill */ /** @var ImportBill */
@@ -156,6 +158,80 @@ class ImportJournal
return $this->description; return $this->description;
} }
/**
* @return string|null
*/
public function getForeignAmount(): ?string
{
Log::debug('Now in getForeignAmount()');
Log::debug(sprintf('foreign amount is %s', var_export($this->foreignAmount, true)));
// no foreign amount? return null
if (null === $this->foreignAmount) {
Log::debug('Return NULL for foreign amount');
return null;
}
// converter is default amount converter: no special stuff
$converter = app(Amount::class);
$amount = $converter->convert($this->foreignAmount['value']);
Log::debug(sprintf('First attempt to convert foreign gives "%s"', $amount));
// modify
foreach ($this->modifiers as $modifier) {
$class = sprintf('FireflyIII\Import\Converter\%s', config(sprintf('csv.import_roles.%s.converter', $modifier['role'])));
/** @var ConverterInterface $converter */
$converter = app($class);
Log::debug(sprintf('Now launching converter %s', $class));
if ($converter->convert($modifier['value']) === -1) {
$this->convertedAmount = Steam::negative($amount);
}
Log::debug(sprintf('Foreign amount after conversion is %s', $amount));
}
Log::debug(sprintf('After modifiers the result is: "%s"', $amount));
Log::debug(sprintf('converted foreign amount is: "%s"', $amount));
if (0 === bccomp($amount, '0')) {
return null;
}
return $amount;
}
/**
* Get date field or NULL
*
* @param string $field
*
* @return Carbon|null
*/
public function getMetaDate(string $field): ?Carbon
{
if (isset($this->metaDates[$field])) {
return new Carbon($this->metaDates[$field]);
}
return null;
}
/**
* Get string field or NULL
*
* @param string $field
*
* @return string|null
*/
public function getMetaString(string $field): ?string
{
if (isset($this->metaFields[$field]) && strlen($this->metaFields[$field]) > 0) {
return strval($this->metaFields[$field]);
}
return null;
}
/** /**
* @param string $hash * @param string $hash
*/ */
@@ -213,7 +289,7 @@ class ImportJournal
$this->foreignAmount = $array; $this->foreignAmount = $array;
break; break;
case 'foreign-currency-code': case 'foreign-currency-code':
$this->foreignCurrency->setId($array); $this->foreignCurrency->setCode($array);
break; break;
case 'amount_debit': case 'amount_debit':
$this->amountDebit = $array; $this->amountDebit = $array;

View File

@@ -25,9 +25,9 @@ namespace FireflyIII\Import\Storage;
use ErrorException; use ErrorException;
use Exception; use Exception;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\TransactionJournalFactory;
use FireflyIII\Import\Object\ImportJournal; use FireflyIII\Import\Object\ImportJournal;
use FireflyIII\Models\ImportJob; use FireflyIII\Models\ImportJob;
use FireflyIII\Models\Note;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
@@ -75,6 +75,8 @@ class ImportStorage
private $applyRules = false; private $applyRules = false;
/** @var string */ /** @var string */
private $dateFormat = 'Ymd'; private $dateFormat = 'Ymd';
/** @var TransactionJournalFactory */
private $factory;
/** @var bool */ /** @var bool */
private $matchBills = false; private $matchBills = false;
/** @var Collection */ /** @var Collection */
@@ -92,6 +94,7 @@ class ImportStorage
$this->objects = new Collection; $this->objects = new Collection;
$this->journals = new Collection; $this->journals = new Collection;
$this->errors = new Collection; $this->errors = new Collection;
} }
/** /**
@@ -111,6 +114,8 @@ class ImportStorage
$this->journalRepository = app(JournalRepositoryInterface::class); $this->journalRepository = app(JournalRepositoryInterface::class);
$this->repository->setUser($job->user); $this->repository->setUser($job->user);
$this->journalRepository->setUser($job->user); $this->journalRepository->setUser($job->user);
$this->factory = app(TransactionJournalFactory::class);
$this->factory->setUser($job->user);
$config = $this->repository->getConfiguration($job); $config = $this->repository->getConfiguration($job);
$currency = app('amount')->getDefaultCurrencyByUser($job->user); $currency = app('amount')->getDefaultCurrencyByUser($job->user);
@@ -158,6 +163,7 @@ class ImportStorage
} catch (FireflyException | ErrorException | Exception $e) { } catch (FireflyException | ErrorException | Exception $e) {
$this->errors->push($e->getMessage()); $this->errors->push($e->getMessage());
Log::error(sprintf('Cannot import row #%d because: %s', $index, $e->getMessage())); Log::error(sprintf('Cannot import row #%d because: %s', $index, $e->getMessage()));
Log::error($e->getTraceAsString());
} }
} }
); );
@@ -179,12 +185,12 @@ class ImportStorage
Log::debug(sprintf('Going to store object #%d/%d with description "%s"', ($index + 1), $this->total, $importJournal->getDescription())); Log::debug(sprintf('Going to store object #%d/%d with description "%s"', ($index + 1), $this->total, $importJournal->getDescription()));
$assetAccount = $importJournal->asset->getAccount(); $assetAccount = $importJournal->asset->getAccount();
$amount = $importJournal->getAmount(); $amount = $importJournal->getAmount();
$foreignAmount = $importJournal->getForeignAmount();
$currencyId = $this->getCurrencyId($importJournal); $currencyId = $this->getCurrencyId($importJournal);
$foreignCurrencyId = $this->getForeignCurrencyId($importJournal, $currencyId); $foreignCurrencyId = $this->getForeignCurrencyId($importJournal, $currencyId);
$date = $importJournal->getDate($this->dateFormat)->format('Y-m-d'); $date = $importJournal->getDate($this->dateFormat)->format('Y-m-d');
$opposingAccount = $this->getOpposingAccount($importJournal->opposing, $assetAccount->id, $amount); $opposingAccount = $this->getOpposingAccount($importJournal->opposing, $assetAccount->id, $amount);
$transactionType = $this->getTransactionType($amount, $opposingAccount); $transactionType = $this->getTransactionType($amount, $opposingAccount);
$description = $importJournal->getDescription();
$this->addStep(); $this->addStep();
/** /**
@@ -192,7 +198,7 @@ class ImportStorage
*/ */
$parameters = [ $parameters = [
'type' => $transactionType, 'type' => $transactionType,
'description' => $description, 'description' => $importJournal->getDescription(),
'amount' => $amount, 'amount' => $amount,
'date' => $date, 'date' => $date,
'asset' => $assetAccount->name, 'asset' => $assetAccount->name,
@@ -211,52 +217,83 @@ class ImportStorage
unset($parameters); unset($parameters);
$this->addStep(); $this->addStep();
// store journal and create transactions:
$parameters = [ try {
$budget = $importJournal->budget->getBudget();
$category = $importJournal->category->getCategory();
$bill = $importJournal->bill->getBill();
$source = $assetAccount;
$destination = $opposingAccount;
if ($transactionType === TransactionType::DEPOSIT) {
$destination = $assetAccount;
$source = $opposingAccount;
}
Log::debug(
sprintf('Will make #%s (%s) the source and #%s (%s) the destination.', $source->id, $source->name, $destination->id, $destination->name)
);
$data = [
'user' => $this->job->user_id,
'type' => $transactionType, 'type' => $transactionType,
'currency' => $currencyId, 'date' => $importJournal->getDate($this->dateFormat),
'foreign_currency' => $foreignCurrencyId, 'description' => $importJournal->getDescription(),
'asset' => $assetAccount, 'piggy_bank_id' => null,
'opposing' => $opposingAccount, 'piggy_bank_name' => null,
'description' => $description, 'bill_id' => is_null($bill) ? null : $bill->id,
'date' => $date, 'bill_name' => null,
'hash' => $importJournal->hash, 'tags' => $importJournal->tags,
'interest_date' => $importJournal->getMetaDate('interest_date'),
'book_date' => $importJournal->getMetaDate('book_date'),
'process_date' => $importJournal->getMetaDate('process_date'),
'due_date' => $importJournal->getMetaDate('due_date'),
'payment_date' => $importJournal->getMetaDate('payment_date'),
'invoice_date' => $importJournal->getMetaDate('invoice_date'),
'internal_reference' => $importJournal->metaFields['internal_reference'] ?? null,
'notes' => $importJournal->notes,
'sepa-cc' => $importJournal->getMetaString('sepa-cc'),
'sepa-ct-op' => $importJournal->getMetaString('sepa-ct-op'),
'sepa-ct-id' => $importJournal->getMetaString('sepa-ct-id'),
'sepa-db' => $importJournal->getMetaString('sepa-db'),
'sepa-country' => $importJournal->getMetaString('sepa-country'),
'sepa-ep' => $importJournal->getMetaString('sepa-ep'),
'sepa-ci' => $importJournal->getMetaString('sepa-ci'),
'transactions' => [
// single transaction:
[
'description' => null,
'amount' => $amount, 'amount' => $amount,
'currency_id' => intval($currencyId),
'currency_code' => null,
'foreign_amount' => $foreignAmount,
'foreign_currency_id' => $foreignCurrencyId,
'foreign_currency_code' => null,
'budget_id' => is_null($budget) ? null : $budget->id,
'budget_name' => null,
'category_id' => is_null($category) ? null : $category->id,
'category_name' => null,
'source_id' => $source->id,
'source_name' => null,
'destination_id' => $destination->id,
'destination_name' => null,
'reconciled' => false,
'identifier' => 0,
],
],
]; ];
$journal = $this->storeJournal($parameters); $factoryJournal = $this->factory->create($data);
unset($parameters); $this->journals->push($factoryJournal);
$this->addStep(); } catch (FireflyException $e) {
Log::error(sprintf('Could not use factory to store journal: %s', $e->getMessage()));
// store meta object things: Log::error($e->getTraceAsString());
$this->storeCategory($journal, $importJournal->category->getCategory());
$this->storeBudget($journal, $importJournal->budget->getBudget());
// to save bill, also give it the amount:
$importJournal->bill->setAmount($amount);
$this->storeBill($journal, $importJournal->bill->getBill());
$this->storeMetaDates($journal, $importJournal->metaDates);
$this->storeTags($importJournal->tags, $journal);
foreach ($importJournal->metaFields as $field => $value) {
$this->journalRepository->setMetaString($journal, $field, $value);
} }
// set notes for journal: $this->addStep();
$dbNote = new Note();
$dbNote->noteable()->associate($journal);
$dbNote->text = trim($importJournal->notes);
$dbNote->save();
// set journal completed:
$journal->completed = true;
$journal->save();
$this->addStep(); $this->addStep();
// run rules if config calls for it: // run rules if config calls for it:
if (true === $this->applyRules) { if (true === $this->applyRules) {
Log::info('Will apply rules to this journal.'); Log::info('Will apply rules to this journal.');
$this->applyRules($journal); $this->applyRules($factoryJournal);
} }
Preferences::setForUser($this->job->user, 'lastActivity', microtime()); Preferences::setForUser($this->job->user, 'lastActivity', microtime());
@@ -268,7 +305,7 @@ class ImportStorage
// match bills if config calls for it. // match bills if config calls for it.
if (true === $this->matchBills) { if (true === $this->matchBills) {
Log::info('Will match bills.'); Log::info('Will match bills.');
$this->matchBills($journal); $this->matchBills($factoryJournal);
} }
if (!(true === $this->matchBills)) { if (!(true === $this->matchBills)) {
@@ -276,9 +313,14 @@ class ImportStorage
} }
$this->addStep(); $this->addStep();
$this->journals->push($journal); $this->journals->push($factoryJournal);
Log::info(sprintf('Imported new journal #%d: "%s", amount %s %s.', $journal->id, $journal->description, $journal->transactionCurrency->code, $amount)); Log::info(
sprintf(
'Imported new journal #%d: "%s", amount %s %s.', $factoryJournal->id, $factoryJournal->description, $factoryJournal->transactionCurrency->code,
$amount
)
);
return true; return true;
} }

View File

@@ -22,25 +22,19 @@ declare(strict_types=1);
namespace FireflyIII\Import\Storage; namespace FireflyIII\Import\Storage;
use Carbon\Carbon;
use Exception;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Import\Object\ImportAccount; use FireflyIII\Import\Object\ImportAccount;
use FireflyIII\Import\Object\ImportJournal; use FireflyIII\Import\Object\ImportJournal;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\ImportJob; use FireflyIII\Models\ImportJob;
use FireflyIII\Models\Rule; use FireflyIII\Models\Rule;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalMeta; use FireflyIII\Models\TransactionJournalMeta;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\TransactionRules\Processor; use FireflyIII\TransactionRules\Processor;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -113,32 +107,6 @@ trait ImportSupport
return true; return true;
} }
/**
* @param array $parameters
*
* @return bool
*
* @throws FireflyException
*/
private function createTransaction(array $parameters): bool
{
$transaction = new Transaction;
$transaction->account_id = $parameters['account'];
$transaction->transaction_journal_id = intval($parameters['id']);
$transaction->transaction_currency_id = intval($parameters['currency']);
$transaction->amount = $parameters['amount'];
$transaction->foreign_currency_id = 0 === intval($parameters['foreign_currency']) ? null : intval($parameters['foreign_currency']);
$transaction->foreign_amount = null === $transaction->foreign_currency_id ? null : $parameters['foreign_amount'];
$transaction->save();
if (null === $transaction->id) {
$errorText = join(', ', $transaction->getErrors()->all());
throw new FireflyException($errorText);
}
Log::debug(sprintf('Created transaction with ID #%d, account #%d, amount %s', $transaction->id, $parameters['account'], $parameters['amount']));
return true;
}
/** /**
* @return Collection * @return Collection
*/ */
@@ -196,7 +164,7 @@ trait ImportSupport
private function getForeignCurrencyId(ImportJournal $importJournal, int $currencyId): ?int private function getForeignCurrencyId(ImportJournal $importJournal, int $currencyId): ?int
{ {
// use given currency by import journal. // use given currency by import journal.
$currency = $importJournal->currency->getTransactionCurrency(); $currency = $importJournal->foreignCurrency->getTransactionCurrency();
if (null !== $currency && intval($currency->id) !== intval($currencyId)) { if (null !== $currency && intval($currency->id) !== intval($currencyId)) {
return $currency->id; return $currency->id;
} }
@@ -379,139 +347,4 @@ trait ImportSupport
return false; return false;
} }
/**
* @param TransactionJournal $journal
* @param Bill $bill
*/
private function storeBill(TransactionJournal $journal, Bill $bill)
{
if (null !== $bill) {
Log::debug(sprintf('Linked bill #%d to journal #%d', $bill->id, $journal->id));
$journal->bill()->associate($bill);
$journal->save();
}
}
/**
* @param TransactionJournal $journal
* @param Budget $budget
*/
private function storeBudget(TransactionJournal $journal, Budget $budget)
{
if (null !== $budget) {
Log::debug(sprintf('Linked budget #%d to journal #%d', $budget->id, $journal->id));
$journal->budgets()->save($budget);
}
}
/**
* @param TransactionJournal $journal
* @param Category $category
*/
private function storeCategory(TransactionJournal $journal, Category $category)
{
if (null !== $category) {
Log::debug(sprintf('Linked category #%d to journal #%d', $category->id, $journal->id));
$journal->categories()->save($category);
}
}
/**
* @param array $parameters
*
* @return TransactionJournal
*
* @throws FireflyException
*/
private function storeJournal(array $parameters): TransactionJournal
{
// find transaction type:
$transactionType = TransactionType::whereType($parameters['type'])->first();
// create a journal:
$journal = new TransactionJournal;
$journal->user_id = $this->job->user_id;
$journal->transaction_type_id = $transactionType->id;
$journal->transaction_currency_id = $parameters['currency'];
$journal->description = $parameters['description'];
$journal->date = $parameters['date'];
$journal->order = 0;
$journal->tag_count = 0;
$journal->completed = false;
if (!$journal->save()) {
$errorText = join(', ', $journal->getErrors()->all());
// throw error
throw new FireflyException($errorText);
}
// save meta data:
$this->journalRepository->setMetaString($journal, 'importHash', $parameters['hash']);
Log::debug(sprintf('Created journal with ID #%d', $journal->id));
// create transactions:
$one = [
'id' => $journal->id,
'account' => $parameters['asset']->id,
'currency' => $parameters['currency'],
'amount' => $parameters['amount'],
'foreign_currency' => $parameters['foreign_currency'],
'foreign_amount' => null === $parameters['foreign_currency'] ? null : $parameters['amount'],
];
$opposite = app('steam')->opposite($parameters['amount']);
$two = [
'id' => $journal->id,
'account' => $parameters['opposing']->id,
'currency' => $parameters['currency'],
'amount' => $opposite,
'foreign_currency' => $parameters['foreign_currency'],
'foreign_amount' => null === $parameters['foreign_currency'] ? null : $opposite,
];
$this->createTransaction($one);
$this->createTransaction($two);
return $journal;
}
/**
* @param TransactionJournal $journal
* @param array $dates
*/
private function storeMetaDates(TransactionJournal $journal, array $dates)
{
// all other date fields as meta thing:
foreach ($dates as $name => $value) {
try {
$date = new Carbon($value);
$this->journalRepository->setMetaDate($journal, $name, $date);
} catch (Exception $e) {
// don't care, ignore:
Log::warning(sprintf('Could not parse "%s" into a valid Date object for field %s', $value, $name));
}
}
}
/**
* @param array $tags
* @param TransactionJournal $journal
*/
private function storeTags(array $tags, TransactionJournal $journal): void
{
$repository = app(TagRepositoryInterface::class);
$repository->setUser($journal->user);
foreach ($tags as $tag) {
$dbTag = $repository->findByTag($tag);
if (null === $dbTag->id) {
$dbTag = $repository->store(
['tag' => $tag, 'date' => null, 'description' => null, 'latitude' => null, 'longitude' => null,
'zoomLevel' => null, 'tagMode' => 'nothing',]
);
}
$journal->tags()->save($dbTag);
Log::debug(sprintf('Linked tag %d ("%s") to journal #%d', $dbTag->id, $dbTag->tag, $journal->id));
}
return;
}
} }

View File

@@ -265,6 +265,7 @@ trait TransactionServiceTrait
return; return;
} }
$transaction->foreign_currency_id = $currency->id; $transaction->foreign_currency_id = $currency->id;
$transaction->save(); $transaction->save();

View File

@@ -290,10 +290,13 @@ class Steam
/** /**
* @param string $amount * @param string $amount
* *
* @return string * @return string|null
*/ */
public function opposite(string $amount): string public function opposite(string $amount = null): ?string
{ {
if (is_null($amount)) {
return null;
}
$amount = bcmul($amount, '-1'); $amount = bcmul($amount, '-1');
return $amount; return $amount;