First working version of a working Spectre import.

This commit is contained in:
James Cole 2018-05-19 21:13:00 +02:00
parent 04953b5645
commit 2c206bba64
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
17 changed files with 552 additions and 172 deletions

View File

@ -33,6 +33,7 @@ use FireflyIII\Support\Import\JobConfiguration\Spectre\ChooseLoginHandler;
use FireflyIII\Support\Import\JobConfiguration\Spectre\NewConfig;
use FireflyIII\Support\Import\JobConfiguration\Spectre\SpectreJobConfig;
use Illuminate\Support\MessageBag;
use Log;
/**
* Class SpectreJobConfiguration
@ -117,6 +118,7 @@ class SpectreJobConfiguration implements JobConfigurationInterface
*/
private function getHandler(): SpectreJobConfig
{
Log::debug(sprintf('Now in SpectreJobConfiguration::getHandler() with stage "%s"', $this->importJob->stage));
$handler = null;
switch ($this->importJob->stage) {
case 'new':

View File

@ -29,10 +29,10 @@ use FireflyIII\Support\Import\Routine\Spectre\ImportDataHandler;
use FireflyIII\Support\Import\Routine\Spectre\ManageLoginsHandler;
use FireflyIII\Support\Import\Routine\Spectre\StageAuthenticatedHandler;
use FireflyIII\Support\Import\Routine\Spectre\StageNewHandler;
use Log;
/**
* @codeCoverageIgnore
* Class FileRoutine
* Class SpectreRoutine
*/
class SpectreRoutine implements RoutineInterface
{
@ -57,28 +57,19 @@ class SpectreRoutine implements RoutineInterface
*/
public function run(): void
{
Log::debug(sprintf('Now in SpectreRoutine::run() with status "%s" and stage "%s".', $this->importJob->status, $this->importJob->stage));
$valid = ['ready_to_run']; // should be only ready_to_run
if (in_array($this->importJob->status, $valid)) {
if (\in_array($this->importJob->status, $valid, true)) {
switch ($this->importJob->stage) {
default:
throw new FireflyException(sprintf('SpectreRoutine cannot handle stage "%s".', $this->importJob->stage));
case 'new':
// list all of the users logins.
$this->repository->setStatus($this->importJob, 'running');
/** @var StageNewHandler $handler */
$handler = app(StageNewHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
$this->repository->setStage($this->importJob, 'manage-logins');
break;
case 'authenticate':
// set job to require config.
$this->repository->setStatus($this->importJob, 'need_job_config');
return;
case 'manage-logins':
// list all of the users logins.
$handler = new ManageLoginsHandler;
$handler->setImportJob($this->importJob);
$handler->run();
// if count logins is zero, go to authenticate stage
if ($handler->countLogins === 0) {
@ -91,9 +82,16 @@ class SpectreRoutine implements RoutineInterface
$this->repository->setStage($this->importJob, 'choose-login');
$this->repository->setStatus($this->importJob, 'need_job_config');
break;
case 'authenticate':
// set job to require config.
$this->repository->setStatus($this->importJob, 'need_job_config');
return;
case 'authenticated':
$this->repository->setStatus($this->importJob, 'running');
// get accounts from login, store in job.
$handler = new StageAuthenticatedHandler;
/** @var StageAuthenticatedHandler $handler */
$handler = app(StageAuthenticatedHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
@ -103,9 +101,10 @@ class SpectreRoutine implements RoutineInterface
break;
case 'go-for-import':
// user has chosen account mapping. Should now be ready to import data.
//$this->repository->setStatus($this->importJob, 'running');
//$this->repository->setStage($this->importJob, 'do_import');
$handler = new ImportDataHandler;
$this->repository->setStatus($this->importJob, 'running');
$this->repository->setStage($this->importJob, 'do_import');
/** @var ImportDataHandler $handler */
$handler = app(ImportDataHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
$this->repository->setStatus($this->importJob, 'provider_finished');

View File

@ -382,7 +382,9 @@ class ImportArrayStorage
$store['date'] = Carbon::createFromFormat('Y-m-d', $store['date']);
$store['description'] = $store['description'] === '' ? '(empty description)' : $store['description'];
// store the journal.
$collection->push($this->journalRepos->store($store));
$journal = $this->journalRepos->store($store);
Log::debug(sprintf('Stored as journal #%d', $journal->id));
$collection->push($journal);
}
Log::debug('DONE storing!');

View File

@ -38,6 +38,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class Account.
*
* @property int $id
* @property string $name
* @property string $iban
*/

View File

@ -22,7 +22,6 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@ -30,8 +29,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class ImportJob.
*
* @property array $transactions
* @property array $configuration
* @property User $user
* @property int $user_id
* @property string $status
* @property string $stage
*/
class ImportJob extends Model
{
@ -53,22 +56,12 @@ class ImportJob extends Model
/** @var array */
protected $fillable = ['key', 'user_id', 'file_type', 'provider', 'status', 'stage', 'configuration', 'extended_status', 'transactions', 'errors'];
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function attachments()
{
return $this->morphMany(Attachment::class, 'attachable');
}
/**
* @param $value
*
* @return mixed
*
* @throws NotFoundHttpException
* @throws FireflyException
*/
public static function routeBinder(string $value): ImportJob
{
@ -84,11 +77,11 @@ class ImportJob extends Model
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function user()
public function attachments()
{
return $this->belongsTo(User::class);
return $this->morphMany(Attachment::class, 'attachable');
}
/**
@ -99,4 +92,13 @@ class ImportJob extends Model
{
return $this->belongsTo(Tag::class);
}
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo(User::class);
}
}

View File

@ -112,9 +112,9 @@ class Transaction extends SpectreObject
}
/**
* @return TransactionExtra
* @return TransactionExtra|null
*/
public function getExtra(): TransactionExtra
public function getExtra(): ?TransactionExtra
{
return $this->extra;
}
@ -167,6 +167,38 @@ class Transaction extends SpectreObject
return $this->mode;
}
/**
* @return array
*/
public function getOpposingAccountData(): array
{
$data = [
'name' => null,
'iban' => null,
'number' => null,
'bic' => null,
];
$extra = $this->getExtra();
if (null !== $extra) {
$arr = $extra->toArray();
foreach ($arr as $key => $value) {
switch ($key) {
case 'account_number':
$data['number'] = $value;
$data['name'] = $data['name'] ?? trans('import.spectre_account_with_number', ['number' => $value]);
break;
case 'payee':
$data['name'] = $value;
break;
default:
break;
}
}
}
return $data;
}
/**
* @return string
*/

View File

@ -26,8 +26,13 @@ namespace FireflyIII\Support\Import\JobConfiguration\Spectre;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Services\Spectre\Object\Customer;
use FireflyIII\Services\Spectre\Object\Token;
use FireflyIII\Services\Spectre\Request\CreateTokenRequest;
use FireflyIII\Services\Spectre\Request\ListCustomersRequest;
use FireflyIII\Services\Spectre\Request\NewCustomerRequest;
use Illuminate\Support\MessageBag;
use Log;
/**
* Class AuthenticateConfig
@ -50,6 +55,8 @@ class AuthenticateConfig implements SpectreJobConfig
*/
public function configurationComplete(): bool
{
Log::debug('AuthenticateConfig::configurationComplete() will always return false');
return false;
}
@ -62,7 +69,8 @@ class AuthenticateConfig implements SpectreJobConfig
*/
public function configureJob(array $data): MessageBag
{
// does nothing
Log::debug('AuthenticateConfig::configureJob() will do nothing.');
return new MessageBag;
}
@ -74,15 +82,22 @@ class AuthenticateConfig implements SpectreJobConfig
*/
public function getNextData(): array
{
Log::debug('Now in AuthenticateConfig::getNextData()');
// next data only makes sure the job is ready for the next stage.
$this->repository->setStatus($this->importJob, 'ready_to_run');
$this->repository->setStage($this->importJob, 'authenticated');
$config = $this->importJob->configuration;
$token = isset($config['token']) ? new Token($config['token']) : null;
if (null !== $token) {
Log::debug(sprintf('Return "%s" from token in config.', $token->getConnectUrl()));
return ['token-url' => $token->getConnectUrl()];
}
throw new FireflyException('The import routine cannot continue without a Spectre token. Apologies.');
Log::debug('No existing token, get a new one.');
// get a new token from Spectre.
$customer = $this->getCustomer();
$token = $this->getToken($customer);
return ['token-url' => $token->getConnectUrl()];
}
/**
@ -106,4 +121,75 @@ class AuthenticateConfig implements SpectreJobConfig
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
}
/**
* @return Customer
* @throws FireflyException
*/
private function getCustomer(): Customer
{
Log::debug('Now in AuthenticateConfig::getCustomer()');
$customer = $this->getExistingCustomer();
if (null === $customer) {
Log::debug('The customer is NULL, will fire a newCustomerRequest.');
$newCustomerRequest = new NewCustomerRequest($this->importJob->user);
$customer = $newCustomerRequest->getCustomer();
}
Log::debug('The customer is not null.');
return $customer;
}
/**
* @return Customer|null
* @throws FireflyException
*/
private function getExistingCustomer(): ?Customer
{
Log::debug('Now in AuthenticateConfig::getExistingCustomer()');
$preference = app('preferences')->getForUser($this->importJob->user, 'spectre_customer');
if (null !== $preference) {
Log::debug('Customer is in user configuration');
$customer = new Customer($preference->data);
return $customer;
}
Log::debug('Customer is not in user config');
$customer = null;
$getCustomerRequest = new ListCustomersRequest($this->importJob->user);
$getCustomerRequest->call();
$customers = $getCustomerRequest->getCustomers();
Log::debug(sprintf('Found %d customer(s)', \count($customers)));
/** @var Customer $current */
foreach ($customers as $current) {
if ('default_ff3_customer' === $current->getIdentifier()) {
$customer = $current;
Log::debug('Found the correct customer.');
app('preferences')->setForUser($this->importJob->user, 'spectre_customer', $customer->toArray());
break;
}
}
return $customer;
}
/**
* @param Customer $customer
*
* @throws FireflyException
* @return Token
*/
private function getToken(Customer $customer): Token
{
Log::debug('Now in AuthenticateConfig::getToken()');
$request = new CreateTokenRequest($this->importJob->user);
$request->setUri(route('import.job.status.index', [$this->importJob->key]));
$request->setCustomer($customer);
$request->call();
Log::debug('Call to get token is finished');
return $request->getToken();
}
}

View File

@ -23,10 +23,10 @@ declare(strict_types=1);
namespace FireflyIII\Support\Import\JobConfiguration\Spectre;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use Illuminate\Support\MessageBag;
use Log;
class AuthenticatedConfigHandler implements SpectreJobConfig
{
@ -42,6 +42,8 @@ class AuthenticatedConfigHandler implements SpectreJobConfig
*/
public function configurationComplete(): bool
{
Log::debug('AuthenticatedConfigHandler::configurationComplete() always returns true');
return true;
}
@ -54,6 +56,8 @@ class AuthenticatedConfigHandler implements SpectreJobConfig
*/
public function configureJob(array $data): MessageBag
{
Log::debug('AuthenticatedConfigHandler::configurationComplete() always returns empty message bag');
return new MessageBag();
}
@ -64,6 +68,8 @@ class AuthenticatedConfigHandler implements SpectreJobConfig
*/
public function getNextData(): array
{
Log::debug('AuthenticatedConfigHandler::getNextData() always returns []');
return [];
}
@ -74,6 +80,8 @@ class AuthenticatedConfigHandler implements SpectreJobConfig
*/
public function getNextView(): string
{
Log::debug('AuthenticatedConfigHandler::getNextView() always returns ""');
return '';
}

View File

@ -35,6 +35,7 @@ use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Services\Spectre\Object\Account as SpectreAccount;
use FireflyIII\Services\Spectre\Object\Login;
use Illuminate\Support\MessageBag;
use Log;
/**
* Class ChooseAccount
@ -60,10 +61,12 @@ class ChooseAccount implements SpectreJobConfig
*/
public function configurationComplete(): bool
{
Log::debug('Now in ChooseAccount::configurationComplete()');
$config = $this->importJob->configuration;
$importAccounts = $config['account_mapping'] ?? [];
$complete = \count($importAccounts) > 0 && $importAccounts !== [0 => 0];
if ($complete) {
Log::debug('Looks like user has mapped import accounts to Firefly III accounts', $importAccounts);
$this->repository->setStage($this->importJob, 'go-for-import');
}
@ -79,6 +82,7 @@ class ChooseAccount implements SpectreJobConfig
*/
public function configureJob(array $data): MessageBag
{
Log::debug('Now in ChooseAccount::configureJob()', $data);
$config = $this->importJob->configuration;
$mapping = $data['account_mapping'] ?? [];
$final = [];
@ -89,11 +93,12 @@ class ChooseAccount implements SpectreJobConfig
$final[$spectreId] = $accountId;
}
Log::debug('Final mapping is:', $final);
$messages = new MessageBag;
$config['account_mapping'] = $final;
$this->repository->setConfiguration($this->importJob, $config);
if (\count($final) === 0 || $final === [0 => 0]) {
if ($final === [0 => 0] || \count($final) === 0) {
$messages->add('count', trans('import.spectre_no_mapping'));
}
@ -108,6 +113,7 @@ class ChooseAccount implements SpectreJobConfig
*/
public function getNextData(): array
{
Log::debug('Now in ChooseAccount::getnextData()');
$config = $this->importJob->configuration;
$accounts = $config['accounts'] ?? [];
if (\count($accounts) === 0) {
@ -125,14 +131,17 @@ class ChooseAccount implements SpectreJobConfig
if (\count($logins) === 0) {
throw new FireflyException('It seems you have no configured logins in this import job. The import cannot continue.');
}
Log::debug(sprintf('Selected login to use is %d', $selected));
if ($selected === 0) {
$login = new Login($logins[0]);
Log::debug(sprintf('Will use login %d (%s %s)', $login->getId(), $login->getProviderName(), $login->getCountryCode()));
}
if ($selected !== 0) {
foreach ($logins as $loginArray) {
$loginId = $loginArray['id'] ?? -1;
if ($loginId === $selected) {
$login = new Login($loginArray);
Log::debug(sprintf('Will use login %d (%s %s)', $login->getId(), $login->getProviderName(), $login->getCountryCode()));
}
}
}

View File

@ -55,10 +55,14 @@ class ChooseLoginHandler implements SpectreJobConfig
*/
public function configurationComplete(): bool
{
Log::debug('Now in ChooseLoginHandler::configurationComplete()');
$config = $this->importJob->configuration;
if(isset($config['selected-login'])) {
if (isset($config['selected-login'])) {
Log::debug('config[selected-login] is set, return true.');
return true;
}
Log::debug('config[selected-login] is not set, return false.');
return false;
}
@ -73,24 +77,30 @@ class ChooseLoginHandler implements SpectreJobConfig
*/
public function configureJob(array $data): MessageBag
{
Log::debug('Now in ChooseLoginHandler::configureJob()');
$selectedLogin = (int)$data['spectre_login_id'];
$config = $this->importJob->configuration;
$config['selected-login'] = $selectedLogin;
$this->repository->setConfiguration($this->importJob, $config);
Log::debug(sprintf('The selected login by the user is #%d', $selectedLogin));
// if selected login is zero, create a new one.
if ($selectedLogin === 0) {
Log::debug('Login is zero, get a new customer + token and store it in config.');
$customer = $this->getCustomer();
// get a token for the user and redirect to next stage
$token = $this->getToken($customer);
$config['customer'] = $customer->toArray();
$config['token'] = $token->toArray();
$this->repository->setConfiguration($this->importJob, $config);
// move job to correct stage to redirect to Spectre:
$this->repository->setStage($this->importJob, 'authenticate');
return new MessageBag;
}
$this->repository->setStage($this->importJob, 'authenticated');
return new MessageBag;
}
@ -101,9 +111,11 @@ class ChooseLoginHandler implements SpectreJobConfig
*/
public function getNextData(): array
{
Log::debug('Now in ChooseLoginHandler::getNextData()');
$config = $this->importJob->configuration;
$data = ['logins' => []];
$logins = $config['all-logins'] ?? [];
Log::debug(sprintf('Count of logins in configuration is %d.', \count($logins)));
foreach ($logins as $login) {
$data['logins'][] = new Login($login);
}
@ -158,7 +170,7 @@ class ChooseLoginHandler implements SpectreJobConfig
*/
private function getExistingCustomer(): ?Customer
{
Log::debug('Now in getExistingCustomer()');
Log::debug('Now in ChooseLoginHandler::getExistingCustomer()');
$preference = app('preferences')->getForUser($this->importJob->user, 'spectre_customer');
if (null !== $preference) {
Log::debug('Customer is in user configuration');
@ -178,6 +190,7 @@ class ChooseLoginHandler implements SpectreJobConfig
if ('default_ff3_customer' === $current->getIdentifier()) {
$customer = $current;
Log::debug('Found the correct customer.');
app('preferences')->setForUser($this->importJob->user, 'spectre_customer', $customer->toArray());
break;
}
}
@ -193,7 +206,7 @@ class ChooseLoginHandler implements SpectreJobConfig
*/
private function getToken(Customer $customer): Token
{
Log::debug('Now in ChooseLoginsHandler::getToken()');
Log::debug('Now in ChooseLoginHandler::ChooseLoginsHandler::getToken()');
$request = new CreateTokenRequest($this->importJob->user);
$request->setUri(route('import.job.status.index', [$this->importJob->key]));
$request->setCustomer($customer);

View File

@ -84,6 +84,5 @@ class NewConfig implements SpectreJobConfig
*/
public function setImportJob(ImportJob $importJob): void
{
return;
}
}

View File

@ -27,6 +27,11 @@ namespace FireflyIII\Support\Import\JobConfiguration\Spectre;
use FireflyIII\Models\ImportJob;
use Illuminate\Support\MessageBag;
/**
* Interface SpectreJobConfig
*
* @package FireflyIII\Support\Import\JobConfiguration\Spectre
*/
interface SpectreJobConfig
{
/**

View File

@ -24,8 +24,17 @@ declare(strict_types=1);
namespace FireflyIII\Support\Import\Routine\Spectre;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account as LocalAccount;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Services\Spectre\Object\Account as SpectreAccount;
use FireflyIII\Services\Spectre\Object\Transaction as SpectreTransaction;
use FireflyIII\Services\Spectre\Request\ListTransactionsRequest;
use FireflyIII\Support\Import\Routine\File\OpposingAccountMapper;
use Log;
/**
* Class ImportDataHandler
@ -34,18 +43,37 @@ use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
*/
class ImportDataHandler
{
/** @var AccountRepositoryInterface */
private $accountRepository;
/** @var ImportJob */
private $importJob;
/** @var OpposingAccountMapper */
private $mapper;
/** @var ImportJobRepositoryInterface */
private $repository;
/**
*
* @throws FireflyException
*/
public function run()
public function run(): void
{
die('here we are');
Log::debug('Now in ImportDataHandler::run()');
$config = $this->importJob->configuration;
$accounts = $config['accounts'] ?? [];
Log::debug(sprintf('Count of accounts in array is %d', \count($accounts)));
if (\count($accounts) === 0) {
throw new FireflyException('There are no accounts in this import job. Cannot continue.');
}
$toImport = $config['account_mapping'] ?? [];
foreach ($toImport as $spectreId => $localId) {
if ((int)$localId > 0) {
Log::debug(sprintf('Will get transactions from Spectre account #%d and save them in Firefly III account #%d', $spectreId, $localId));
$spectreAccount = $this->getSpectreAccount((int)$spectreId);
$localAccount = $this->getLocalAccount((int)$localId);
$set = $this->getTransactions($spectreAccount, $localAccount);
$this->repository->setTransactions($this->importJob, $set);
}
}
}
/**
@ -57,6 +85,186 @@ class ImportDataHandler
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->mapper = app(OpposingAccountMapper::class);
$this->accountRepository->setUser($importJob->user);
$this->repository->setUser($importJob->user);
$this->mapper->setUser($importJob->user);
}
/**
* @param array $transactions
* @param SpectreAccount $spectreAccount
* @param LocalAccount $originalSource
*
* @return array
*/
private function convertToArray(array $transactions, SpectreAccount $spectreAccount, LocalAccount $originalSource): array
{
$array = [];
$total = \count($transactions);
Log::debug(sprintf('Now in ImportDataHandler::convertToArray() with count %d', \count($transactions)));
/** @var SpectreTransaction $transaction */
foreach ($transactions as $index => $transaction) {
Log::debug(sprintf('Now creating array for transaction %d of %d', $index + 1, $total));
$extra = [];
if (null !== $transaction->getExtra()) {
$extra = $transaction->getExtra()->toArray();
}
$destinationData = $transaction->getOpposingAccountData();
$amount = $transaction->getAmount();
$source = $originalSource;
$destination = $this->mapper->map(null, $amount, $destinationData);
$notes = (string)trans('import.imported_from_account', ['account' => $spectreAccount->getName()]) . ' ' . "\n";
$foreignAmount = null;
$foreignCurrencyCode = null;
$currencyCode = $transaction->getCurrencyCode();
$type = 'withdrawal';
// switch source and destination if amount is greater than zero.
if (bccomp($amount, '0') === 1) {
[$source, $destination] = [$destination, $source];
$type = 'deposit';
}
Log::debug(sprintf('Mapped destination to #%d ("%s")', $destination->id, $destination->name));
Log::debug(sprintf('Set source to #%d ("%s")', $source->id, $source->name));
// put some data in tags:
$tags = [];
$tags[] = $transaction->getMode();
$tags[] = $transaction->getStatus();
if ($transaction->isDuplicated()) {
$tags[] = 'possibly-duplicated';
}
// get extra fields:
foreach ($extra as $key => $value) {
if ('' === (string)$value) {
continue;
}
switch ($key) {
case 'original_category':
case 'original_subcategory':
case 'customer_category_code':
case 'customer_category_name':
$tags[] = $value;
break;
case 'original_amount':
$foreignAmount = $value;
break;
case 'original_currency_code':
$foreignCurrencyCode = $value;
break;
default:
$notes .= $key . ': ' . $value . ' ' . "\n"; // for newline in Markdown.
}
}
$entry = [
'type' => $type,
'date' => $transaction->getMadeOn()->format('Y-m-d'),
'tags' => $tags,
'user' => $this->importJob->user_id,
'notes' => $notes,
// all custom fields:
'external_id' => (string)$transaction->getId(),
// journal data:
'description' => $transaction->getDescription(),
'piggy_bank_id' => null,
'piggy_bank_name' => null,
'bill_id' => null,
'bill_name' => null,
// transaction data:
'transactions' => [
[
'currency_id' => null,
'currency_code' => $currencyCode,
'description' => null,
'amount' => $amount,
'budget_id' => null,
'budget_name' => null,
'category_id' => null,
'category_name' => $transaction->getCategory(),
'source_id' => $source->id,
'source_name' => null,
'destination_id' => $destination->id,
'destination_name' => null,
'foreign_currency_id' => null,
'foreign_currency_code' => $foreignCurrencyCode,
'foreign_amount' => $foreignAmount,
'reconciled' => false,
'identifier' => 0,
],
],
];
$array[] = $entry;
}
Log::debug(sprintf('Return %d entries', \count($array)));
return $array;
}
/**
* @param int $accountId
*
* @return LocalAccount
* @throws FireflyException
*/
private function getLocalAccount(int $accountId): LocalAccount
{
$account = $this->accountRepository->findNull($accountId);
if (null === $account) {
throw new FireflyException(sprintf('Cannot find Firefly III asset account with ID #%d. Job must stop now.', $accountId));
}
if ($account->accountType->type !== AccountType::ASSET) {
throw new FireflyException(sprintf('Account with ID #%d is not an asset account. Job must stop now.', $accountId));
}
return $account;
}
/**
* @param int $accountId
*
* @return SpectreAccount
* @throws FireflyException
*/
private function getSpectreAccount(int $accountId): SpectreAccount
{
$config = $this->importJob->configuration;
$accounts = $config['accounts'] ?? [];
foreach ($accounts as $account) {
$spectreId = (int)($account['id'] ?? 0.0);
if ($spectreId === $accountId) {
return new SpectreAccount($account);
}
}
throw new FireflyException(sprintf('Cannot find Spectre account with ID #%d in configuration. Job will exit.', $accountId));
}
/**
* @param SpectreAccount $spectreAccount
* @param LocalAccount $localAccount
*
* @return array
* @throws FireflyException
*/
private function getTransactions(SpectreAccount $spectreAccount, LocalAccount $localAccount): array
{
// grab all transactions
$request = new ListTransactionsRequest($this->importJob->user);
$request->setAccount($spectreAccount);
$request->call();
$transactions = $request->getTransactions();
return $this->convertToArray($transactions, $spectreAccount, $localAccount);
}
}

View File

@ -33,101 +33,11 @@ use FireflyIII\Services\Spectre\Request\ListLoginsRequest;
use FireflyIII\Services\Spectre\Request\NewCustomerRequest;
use Log;
/**
* Class ManageLoginsHandler
*/
class ManageLoginsHandler
{
public $countLogins = 0;
/** @var ImportJob */
private $importJob;
/** @var ImportJobRepositoryInterface */
private $repository;
/**
* Tasks for this stage:
*
* - List all of the users logins.
* - If zero, return to "get-token" stage and make user make a login. That stage redirects here.
* - If one or more, list and let user select.
*
* @throws FireflyException
*/
public function run(): void
{
$customer = $this->getCustomer();
$request = new ListLoginsRequest($this->importJob->user);
$request->setCustomer($customer);
$request->call();
$list = $request->getLogins();
// count is zero?
$this->countLogins = \count($list);
if ($this->countLogins > 0) {
$store = [];
/** @var Login $login */
foreach ($list as $login) {
$store[] = $login->toArray();
}
$config = $this->repository->getConfiguration($this->importJob);
$config['all-logins'] = $store;
$this->repository->setConfiguration($this->importJob, $config);
}
}
/**
* @param ImportJob $importJob
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
}
/**
* @return Customer
* @throws FireflyException
*/
private function getCustomer(): Customer
{
Log::debug('Now in manageLoginsHandler::getCustomer()');
$customer = $this->getExistingCustomer();
if (null === $customer) {
Log::debug('The customer is NULL, will fire a newCustomerRequest.');
$newCustomerRequest = new NewCustomerRequest($this->importJob->user);
$customer = $newCustomerRequest->getCustomer();
}
Log::debug('The customer is not null.');
return $customer;
}
/**
* @return Customer|null
* @throws FireflyException
*/
private function getExistingCustomer(): ?Customer
{
Log::debug('Now in getExistingCustomer()');
$customer = null;
$getCustomerRequest = new ListCustomersRequest($this->importJob->user);
$getCustomerRequest->call();
$customers = $getCustomerRequest->getCustomers();
Log::debug(sprintf('Found %d customer(s)', \count($customers)));
/** @var Customer $current */
foreach ($customers as $current) {
if ('default_ff3_customer' === $current->getIdentifier()) {
$customer = $current;
Log::debug('Found the correct customer.');
break;
}
}
return $customer;
}
}

View File

@ -27,9 +27,17 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Services\Spectre\Object\Account;
use FireflyIII\Services\Spectre\Object\Customer;
use FireflyIII\Services\Spectre\Object\Login;
use FireflyIII\Services\Spectre\Request\ListAccountsRequest;
use FireflyIII\Services\Spectre\Request\ListCustomersRequest;
use FireflyIII\Services\Spectre\Request\ListLoginsRequest;
use FireflyIII\Services\Spectre\Request\NewCustomerRequest;
use Log;
/**
* Class StageAuthenticatedHandler
*/
class StageAuthenticatedHandler
{
/** @var ImportJob */
@ -43,24 +51,31 @@ class StageAuthenticatedHandler
*
* @throws FireflyException
*/
public function run()
public function run(): void
{
Log::debug('Now in StageAuthenticatedHandler::run()');
// grab a list of logins.
$config = $this->importJob->configuration;
$logins = $config['all-logins'] ?? [];
Log::debug(sprintf('%d logins in config', \count($logins)));
if (\count($logins) === 0) {
throw new FireflyException('StageAuthenticatedHandler expects more than 0 logins. Apologies, the import has stopped.');
// get logins from Spectre.
$logins = $this->getLogins();
$config['all-logins'] = $logins;
}
$selectedLogin = $config['selected-login'];
$selectedLogin = $config['selected-login'] ?? 0;
$login = null;
Log::debug(sprintf('$selectedLogin is %d', $selectedLogin));
foreach ($logins as $loginArray) {
$loginId = $loginArray['id'] ?? -1;
if ($loginId === $selectedLogin) {
Log::debug('Selected login is in the array with logins.');
$login = new Login($loginArray);
}
}
if (null === $login) {
Log::debug('Login is null, simply use the first one from the array.');
$login = new Login($logins[0]);
}
@ -93,13 +108,88 @@ class StageAuthenticatedHandler
*/
private function getAccounts(Login $login): array
{
Log::debug(sprintf('Now in StageAuthenticatedHandler::getAccounts() for login #%d', $login->getId()));
$request = new ListAccountsRequest($this->importJob->user);
$request->setLogin($login);
$request->call();
$accounts = $request->getAccounts();
Log::debug(sprintf('Found %d accounts using login', \count($accounts)));
return $accounts;
}
/**
* @return Customer
* @throws FireflyException
*/
private function getCustomer(): Customer
{
Log::debug('Now in stageNewHandler::getCustomer()');
$customer = $this->getExistingCustomer();
if (null === $customer) {
Log::debug('The customer is NULL, will fire a newCustomerRequest.');
$newCustomerRequest = new NewCustomerRequest($this->importJob->user);
$customer = $newCustomerRequest->getCustomer();
}
Log::debug('The customer is not null.');
return $customer;
}
/**
* @return Customer|null
* @throws FireflyException
*/
private function getExistingCustomer(): ?Customer
{
Log::debug('Now in ChooseLoginHandler::getExistingCustomer()');
$preference = app('preferences')->getForUser($this->importJob->user, 'spectre_customer');
if (null !== $preference) {
Log::debug('Customer is in user configuration');
$customer = new Customer($preference->data);
return $customer;
}
Log::debug('Customer is not in user config');
$customer = null;
$getCustomerRequest = new ListCustomersRequest($this->importJob->user);
$getCustomerRequest->call();
$customers = $getCustomerRequest->getCustomers();
Log::debug(sprintf('Found %d customer(s)', \count($customers)));
/** @var Customer $current */
foreach ($customers as $current) {
if ('default_ff3_customer' === $current->getIdentifier()) {
$customer = $current;
Log::debug('Found the correct customer.');
app('preferences')->setForUser($this->importJob->user, 'spectre_customer', $customer->toArray());
break;
}
}
return $customer;
}
/**
* @return array
* @throws FireflyException
*/
private function getLogins(): array
{
$customer = $this->getCustomer();
$request = new ListLoginsRequest($this->importJob->user);
$request->setCustomer($customer);
$request->call();
$logins = $request->getLogins();
$return = [];
/** @var Login $login */
foreach ($logins as $login) {
$return[] = $login->toArray();
}
return $return;
}
}

View File

@ -27,9 +27,9 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Services\Spectre\Object\Customer;
use FireflyIII\Services\Spectre\Object\Token;
use FireflyIII\Services\Spectre\Request\CreateTokenRequest;
use FireflyIII\Services\Spectre\Object\Login;
use FireflyIII\Services\Spectre\Request\ListCustomersRequest;
use FireflyIII\Services\Spectre\Request\ListLoginsRequest;
use FireflyIII\Services\Spectre\Request\NewCustomerRequest;
use Log;
@ -40,35 +40,49 @@ use Log;
*/
class StageNewHandler
{
/** @var int */
public $countLogins = 0;
/** @var ImportJob */
private $importJob;
/** @var ImportJobRepositoryInterface */
private $repository;
/**
* Tasks for this stage:
*
* - Get the user's customer from Spectre.
* - Create a new customer if it does not exist.
* - Store it in the job either way.
* - Use it to grab a token.
* - Store the token in the job.
* - List all of the users logins.
* - If zero, return to "get-token" stage and make user make a login. That stage redirects here.
* - If one or more, list and let user select.
*
* @throws FireflyException
*/
public function run(): void
{
Log::debug('Now in stageNewHandler::run()');
Log::debug('Now in ManageLoginsHandler::run()');
$customer = $this->getCustomer();
// get token using customer.
app('preferences')->setForUser($this->importJob->user, 'spectre_customer', $customer->toArray());
// store token in the job.
$config = $this->repository->getConfiguration($this->importJob);
Log::debug('Going to get a list of logins.');
$request = new ListLoginsRequest($this->importJob->user);
$request->setCustomer($customer);
$request->call();
$list = $request->getLogins();
// count is zero?
$this->countLogins = \count($list);
Log::debug(sprintf('Number of logins is %d', $this->countLogins));
if ($this->countLogins > 0) {
$store = [];
/** @var Login $login */
foreach ($list as $login) {
$store[] = $login->toArray();
}
$config['all-logins'] = $store;
$this->repository->setConfiguration($this->importJob, $config);
Log::debug('Stored all logins in configuration.');
}
}
/**
@ -87,7 +101,7 @@ class StageNewHandler
*/
private function getCustomer(): Customer
{
Log::debug('Now in stageNewHandler::getCustomer()');
Log::debug('Now in manageLoginsHandler::getCustomer()');
$customer = $this->getExistingCustomer();
if (null === $customer) {
Log::debug('The customer is NULL, will fire a newCustomerRequest.');
@ -106,7 +120,7 @@ class StageNewHandler
*/
private function getExistingCustomer(): ?Customer
{
Log::debug('Now in getExistingCustomer()');
Log::debug('Now in manageLoginsHandler::getExistingCustomer()');
$customer = null;
$getCustomerRequest = new ListCustomersRequest($this->importJob->user);
$getCustomerRequest->call();
@ -120,11 +134,9 @@ class StageNewHandler
Log::debug('Found the correct customer.');
break;
}
Log::debug(sprintf('Skip customer with name "%s"', $current->getIdentifier()));
}
return $customer;
}
}

View File

@ -120,6 +120,8 @@ return [
'spectre_no_supported_accounts' => 'You cannot import from this account due to a currency mismatch.',
'spectre_do_not_import' => '(do not import)',
'spectre_no_mapping' => 'It seems you have not selected any accounts to import from.',
'imported_from_account' => 'Imported from ":account"',
'spectre_account_with_number' => 'Account :number',
// keys from "extra" array:
'spectre_extra_key_iban' => 'IBAN',
@ -460,5 +462,5 @@ return [
// 'spectre_extra_key_transactions_count' => 'Transaction count',
//
// // various other strings:
// 'imported_from_account' => 'Imported from ":account"',
//
];