2015-07-05 06:18:02 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace FireflyIII\Helpers\Csv;
|
|
|
|
|
|
|
|
use App;
|
2015-07-05 06:59:05 +02:00
|
|
|
use Auth;
|
2015-07-05 06:18:02 +02:00
|
|
|
use Config;
|
|
|
|
use FireflyIII\Exceptions\FireflyException;
|
|
|
|
use FireflyIII\Helpers\Csv\Converter\ConverterInterface;
|
2015-07-05 19:31:58 +02:00
|
|
|
use FireflyIII\Helpers\Csv\PostProcessing\PostProcessorInterface;
|
2015-07-05 06:59:05 +02:00
|
|
|
use FireflyIII\Models\Transaction;
|
2015-07-05 14:37:36 +02:00
|
|
|
use FireflyIII\Models\TransactionCurrency;
|
2015-07-05 06:59:05 +02:00
|
|
|
use FireflyIII\Models\TransactionJournal;
|
|
|
|
use FireflyIII\Models\TransactionType;
|
|
|
|
use Illuminate\Support\MessageBag;
|
|
|
|
use Log;
|
2015-07-05 14:37:36 +02:00
|
|
|
use Preferences;
|
2015-07-05 06:18:02 +02:00
|
|
|
|
2015-07-05 07:18:48 +02:00
|
|
|
set_time_limit(0);
|
|
|
|
|
2015-07-05 06:18:02 +02:00
|
|
|
/**
|
|
|
|
* Class Importer
|
|
|
|
*
|
|
|
|
* @package FireflyIII\Helpers\Csv
|
|
|
|
*/
|
|
|
|
class Importer
|
|
|
|
{
|
|
|
|
|
|
|
|
/** @var Data */
|
|
|
|
protected $data;
|
2015-07-05 06:59:05 +02:00
|
|
|
/** @var array */
|
|
|
|
protected $errors;
|
2015-07-05 14:37:36 +02:00
|
|
|
/** @var int */
|
|
|
|
protected $imported;
|
2015-07-05 06:18:02 +02:00
|
|
|
/** @var array */
|
|
|
|
protected $map;
|
|
|
|
/** @var array */
|
|
|
|
protected $mapped;
|
|
|
|
/** @var array */
|
|
|
|
protected $roles;
|
2015-07-05 14:37:36 +02:00
|
|
|
/** @var int */
|
|
|
|
protected $rows = 0;
|
2015-07-05 06:18:02 +02:00
|
|
|
|
|
|
|
/**
|
2015-07-05 14:37:36 +02:00
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getErrors()
|
|
|
|
{
|
|
|
|
return $this->errors;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function getImported()
|
|
|
|
{
|
|
|
|
return $this->imported;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function getRows()
|
|
|
|
{
|
|
|
|
return $this->rows;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @throws FireflyException
|
2015-07-05 06:18:02 +02:00
|
|
|
*/
|
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
$this->map = $this->data->getMap();
|
|
|
|
$this->roles = $this->data->getRoles();
|
|
|
|
$this->mapped = $this->data->getMapped();
|
2015-07-05 18:18:44 +02:00
|
|
|
|
2015-07-05 06:59:05 +02:00
|
|
|
foreach ($this->data->getReader() as $index => $row) {
|
2015-07-05 18:18:44 +02:00
|
|
|
if ($this->parseRow($index)) {
|
2015-07-05 14:37:36 +02:00
|
|
|
$this->rows++;
|
|
|
|
$result = $this->importRow($row);
|
|
|
|
if (!($result === true)) {
|
|
|
|
Log::error('Caught error at row #' . $index . ': ' . $result);
|
|
|
|
$this->errors[$index] = $result;
|
|
|
|
} else {
|
|
|
|
$this->imported++;
|
|
|
|
}
|
2015-07-05 06:59:05 +02:00
|
|
|
}
|
2015-07-05 06:18:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-05 18:18:44 +02:00
|
|
|
/**
|
|
|
|
* @param int $index
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
protected function parseRow($index)
|
|
|
|
{
|
|
|
|
return (($this->data->getHasHeaders() && $index > 1) || !$this->data->getHasHeaders());
|
|
|
|
}
|
|
|
|
|
2015-07-05 06:18:02 +02:00
|
|
|
/**
|
|
|
|
* @param $row
|
|
|
|
*
|
|
|
|
* @throws FireflyException
|
2015-07-05 06:59:05 +02:00
|
|
|
* @return string|bool
|
2015-07-05 06:18:02 +02:00
|
|
|
*/
|
|
|
|
protected function importRow($row)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* These fields are necessary to create a new transaction journal. Some are optional:
|
|
|
|
*/
|
2015-07-05 06:59:05 +02:00
|
|
|
$data = $this->getFiller();
|
2015-07-05 06:18:02 +02:00
|
|
|
foreach ($row as $index => $value) {
|
|
|
|
$role = isset($this->roles[$index]) ? $this->roles[$index] : '_ignore';
|
|
|
|
$class = Config::get('csv.roles.' . $role . '.converter');
|
|
|
|
$field = Config::get('csv.roles.' . $role . '.field');
|
|
|
|
|
2015-07-05 18:18:44 +02:00
|
|
|
/** @var ConverterInterface $converter */
|
|
|
|
$converter = App::make('FireflyIII\Helpers\Csv\Converter\\' . $class);
|
2015-07-05 06:18:02 +02:00
|
|
|
$converter->setData($data); // the complete array so far.
|
2015-07-05 06:26:34 +02:00
|
|
|
$converter->setField($field);
|
2015-07-05 06:18:02 +02:00
|
|
|
$converter->setIndex($index);
|
2015-07-05 08:45:05 +02:00
|
|
|
$converter->setMapped($this->mapped);
|
2015-07-05 06:18:02 +02:00
|
|
|
$converter->setValue($value);
|
|
|
|
$converter->setRole($role);
|
|
|
|
$data[$field] = $converter->convert();
|
|
|
|
|
|
|
|
}
|
2015-07-05 18:18:44 +02:00
|
|
|
// post processing and validating.
|
|
|
|
$data = $this->postProcess($data);
|
2015-07-05 06:59:05 +02:00
|
|
|
$result = $this->validateData($data);
|
|
|
|
if ($result === true) {
|
|
|
|
$result = $this->createTransactionJournal($data);
|
|
|
|
} else {
|
|
|
|
Log::error('Validator: ' . $result);
|
|
|
|
}
|
|
|
|
if ($result instanceof TransactionJournal) {
|
|
|
|
return true;
|
|
|
|
}
|
2015-07-05 06:18:02 +02:00
|
|
|
|
2015-07-05 06:59:05 +02:00
|
|
|
return 'Not a journal.';
|
2015-07-05 06:18:02 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
protected function getFiller()
|
|
|
|
{
|
2015-07-05 15:16:44 +02:00
|
|
|
$filler = [];
|
|
|
|
foreach (Config::get('csv.roles') as $role) {
|
2015-07-05 16:39:25 +02:00
|
|
|
if (isset($role['field'])) {
|
|
|
|
$fieldName = $role['field'];
|
|
|
|
$filler[$fieldName] = null;
|
|
|
|
}
|
2015-07-05 15:16:44 +02:00
|
|
|
}
|
|
|
|
// some extra's:
|
|
|
|
$filler['bill-id'] = null;
|
|
|
|
$filler['opposing-account-object'] = null;
|
2015-07-05 16:39:25 +02:00
|
|
|
$filler['amount-modifier'] = '1';
|
2015-07-05 15:16:44 +02:00
|
|
|
|
|
|
|
return $filler;
|
2015-07-05 06:18:02 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-07-05 07:18:48 +02:00
|
|
|
* Row denotes the original data.
|
|
|
|
*
|
2015-07-05 06:18:02 +02:00
|
|
|
* @param array $data
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
2015-07-05 18:18:44 +02:00
|
|
|
protected function postProcess(array $data)
|
2015-07-05 06:18:02 +02:00
|
|
|
{
|
2015-07-05 19:31:58 +02:00
|
|
|
$set = Config::get('csv.post_processors');
|
|
|
|
foreach ($set as $className) {
|
|
|
|
/** @var PostProcessorInterface $postProcessor */
|
|
|
|
$postProcessor = App::make('FireflyIII\Helpers\Csv\PostProcessing\\' . $className);
|
|
|
|
$postProcessor->setData($data);
|
|
|
|
$data = $postProcessor->process();
|
2015-07-05 14:37:36 +02:00
|
|
|
}
|
2015-07-05 18:18:44 +02:00
|
|
|
|
2015-07-05 19:31:58 +02:00
|
|
|
// do bank specific fixes: TODO
|
2015-07-05 07:18:48 +02:00
|
|
|
|
2015-07-05 18:18:44 +02:00
|
|
|
// $specifix = new Specifix();
|
|
|
|
// $specifix->setData($data);
|
|
|
|
// $specifix->setRow($row);
|
2015-07-05 14:37:36 +02:00
|
|
|
//$specifix->fix($data, $row); // TODO
|
2015-07-05 07:18:48 +02:00
|
|
|
// get data back:
|
2015-07-05 14:37:36 +02:00
|
|
|
//$data = $specifix->getData(); // TODO
|
2015-07-05 07:18:48 +02:00
|
|
|
|
2015-07-05 06:18:02 +02:00
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
2015-07-05 06:59:05 +02:00
|
|
|
/**
|
|
|
|
* @param $data
|
|
|
|
*
|
|
|
|
* @return bool|string
|
|
|
|
*/
|
|
|
|
protected function validateData($data)
|
|
|
|
{
|
|
|
|
if (is_null($data['date']) && is_null($data['date-rent'])) {
|
|
|
|
return 'No date value for this row.';
|
|
|
|
}
|
|
|
|
if (is_null($data['opposing-account-object'])) {
|
|
|
|
return 'Opposing account is null';
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param array $data
|
|
|
|
*
|
|
|
|
* @return static
|
|
|
|
*/
|
|
|
|
protected function createTransactionJournal(array $data)
|
|
|
|
{
|
|
|
|
bcscale(2);
|
|
|
|
$date = $data['date'];
|
|
|
|
if (is_null($data['date'])) {
|
|
|
|
$date = $data['date-rent'];
|
|
|
|
}
|
2015-07-05 18:18:44 +02:00
|
|
|
|
|
|
|
// defaults to deposit
|
|
|
|
$transactionType = TransactionType::where('type', 'Deposit')->first();
|
2015-07-05 06:59:05 +02:00
|
|
|
if ($data['amount'] < 0) {
|
|
|
|
$transactionType = TransactionType::where('type', 'Withdrawal')->first();
|
|
|
|
}
|
2015-07-05 18:18:44 +02:00
|
|
|
|
|
|
|
if ($data['opposing-account-object']->accountType->type == 'Asset account') {
|
|
|
|
$transactionType = TransactionType::where('type', 'Transfer')->first();
|
|
|
|
}
|
|
|
|
|
2015-07-05 07:18:48 +02:00
|
|
|
$errors = new MessageBag;
|
2015-07-05 06:59:05 +02:00
|
|
|
$journal = TransactionJournal::create(
|
|
|
|
[
|
|
|
|
'user_id' => Auth::user()->id,
|
|
|
|
'transaction_type_id' => $transactionType->id,
|
|
|
|
'transaction_currency_id' => $data['currency']->id,
|
|
|
|
'description' => $data['description'],
|
|
|
|
'completed' => 0,
|
|
|
|
'date' => $date,
|
2015-07-05 14:37:36 +02:00
|
|
|
'bill_id' => $data['bill-id'],
|
2015-07-05 06:59:05 +02:00
|
|
|
]
|
|
|
|
);
|
2015-07-05 07:18:48 +02:00
|
|
|
$errors = $journal->getErrors()->merge($errors);
|
2015-07-05 06:59:05 +02:00
|
|
|
if ($journal->getErrors()->count() == 0) {
|
|
|
|
// create both transactions:
|
|
|
|
$transaction = Transaction::create(
|
|
|
|
[
|
|
|
|
'transaction_journal_id' => $journal->id,
|
|
|
|
'account_id' => $data['asset-account']->id,
|
|
|
|
'amount' => $data['amount']
|
|
|
|
]
|
|
|
|
);
|
2015-07-05 07:18:48 +02:00
|
|
|
$errors = $transaction->getErrors()->merge($errors);
|
2015-07-05 06:59:05 +02:00
|
|
|
|
|
|
|
$transaction = Transaction::create(
|
|
|
|
[
|
|
|
|
'transaction_journal_id' => $journal->id,
|
|
|
|
'account_id' => $data['opposing-account-object']->id,
|
|
|
|
'amount' => bcmul($data['amount'], -1)
|
|
|
|
]
|
|
|
|
);
|
2015-07-05 07:18:48 +02:00
|
|
|
$errors = $transaction->getErrors()->merge($errors);
|
2015-07-05 06:59:05 +02:00
|
|
|
}
|
2015-07-05 07:18:48 +02:00
|
|
|
if ($errors->count() == 0) {
|
2015-07-05 06:59:05 +02:00
|
|
|
$journal->completed = 1;
|
|
|
|
$journal->save();
|
|
|
|
}
|
|
|
|
|
2015-07-05 15:16:44 +02:00
|
|
|
// add budget:
|
|
|
|
if (!is_null($data['budget'])) {
|
|
|
|
$journal->budgets()->save($data['budget']);
|
|
|
|
}
|
|
|
|
|
|
|
|
// add category:
|
|
|
|
if (!is_null($data['category'])) {
|
|
|
|
$journal->categories()->save($data['category']);
|
|
|
|
}
|
2015-07-05 18:18:44 +02:00
|
|
|
if (!is_null($data['tags'])) {
|
|
|
|
foreach ($data['tags'] as $tag) {
|
|
|
|
$journal->tags()->save($tag);
|
|
|
|
}
|
|
|
|
}
|
2015-07-05 15:16:44 +02:00
|
|
|
|
2015-07-05 06:59:05 +02:00
|
|
|
return $journal;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-07-05 06:18:02 +02:00
|
|
|
/**
|
|
|
|
* @param Data $data
|
|
|
|
*/
|
|
|
|
public function setData($data)
|
|
|
|
{
|
|
|
|
$this->data = $data;
|
|
|
|
}
|
|
|
|
}
|