diff --git a/app/Import/Configuration/FileConfigurator.php b/app/Import/Configuration/FileConfigurator.php index 2b16f268f8..3876c802e3 100644 --- a/app/Import/Configuration/FileConfigurator.php +++ b/app/Import/Configuration/FileConfigurator.php @@ -172,6 +172,7 @@ class FileConfigurator implements ConfiguratorInterface 'column-mapping-complete' => false, // so mapping is not complete. 'apply-rules' => true, 'match-bills' => false, + 'auto-start' => false, ]; $config = $this->job->configuration ?? []; $finalConfig = array_merge($defaultConfig, $config); diff --git a/app/Import/Configuration/SpectreConfigurator.php b/app/Import/Configuration/SpectreConfigurator.php index 69fb4b429c..126e964601 100644 --- a/app/Import/Configuration/SpectreConfigurator.php +++ b/app/Import/Configuration/SpectreConfigurator.php @@ -22,7 +22,9 @@ declare(strict_types=1); namespace FireflyIII\Import\Configuration; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\ImportJob; +use FireflyIII\Support\Import\Configuration\Spectre\HaveAccounts; use Log; /** @@ -52,7 +54,29 @@ class SpectreConfigurator implements ConfiguratorInterface */ public function configureJob(array $data): bool { - die('cannot store config'); + $config = $this->job->configuration; + $stage = $config['stage']; + $status = $this->job->status; + Log::debug(sprintf('in getNextData(), for stage "%s".', $stage)); + switch ($stage) { + case 'have-accounts': + /** @var HaveAccounts $class */ + $class = app(HaveAccounts::class); + $class->setJob($this->job); + $class->storeConfiguration($data); + + // update job for next step and set to "configured". + $config = $this->job->configuration; + $config['stage'] = 'have-account-mapping'; + $this->job->configuration = $config; + $this->job->status = 'configured'; + $this->job->save(); + return true; + break; + default: + throw new FireflyException(sprintf('Cannot store configuration when job is in state "%s"', $stage)); + break; + } } /** @@ -62,13 +86,34 @@ class SpectreConfigurator implements ConfiguratorInterface */ public function getNextData(): array { - Log::debug('in getNextData(), user will be redirected next.'); - // update config to tell Firefly the user is redirected. - $config = $this->job->configuration; - $config['is-redirected'] = true; - $config['stage'] = 'redirected'; + $config = $this->job->configuration; + $stage = $config['stage']; + $status = $this->job->status; + Log::debug(sprintf('in getNextData(), for stage "%s".', $stage)); + switch ($stage) { + case 'has-token': + // simply redirect to Spectre. + $config['is-redirected'] = true; + $config['stage'] = 'user-logged-in'; + $status = 'configured'; + break; + case 'have-accounts': + // use special class: + /** @var HaveAccounts $class */ + $class = app(HaveAccounts::class); + $class->setJob($this->job); + $data = $class->getData(); + + return $data; + default: + return []; + break; + + } + + // update config and status: $this->job->configuration = $config; - $this->job->status = 'configured'; + $this->job->status = $status; $this->job->save(); return $this->job->configuration; @@ -79,10 +124,22 @@ class SpectreConfigurator implements ConfiguratorInterface */ public function getNextView(): string { - Log::debug('Send user redirect view'); + $config = $this->job->configuration; + $stage = $config['stage']; + Log::debug(sprintf('in getNextView(), for stage "%s".', $stage)); + switch ($stage) { + case 'has-token': + // redirect to Spectre. + return 'import.spectre.redirect'; + break; + case 'have-accounts': + return 'import.spectre.accounts'; + break; + default: + return ''; + break; - // sends the user to spectre. - return 'import.spectre.redirect'; + } } /** @@ -100,17 +157,20 @@ class SpectreConfigurator implements ConfiguratorInterface */ public function isJobConfigured(): bool { - Log::debug('in isJobConfigured'); - // job is configured (and can start) when token is empty: $config = $this->job->configuration; - if ($config['has-token'] === false && $config['is-redirected'] === true) { - Log::debug('has-token is false, is-redirected is true, return true'); + $stage = $config['stage']; + Log::debug(sprintf('in isJobConfigured(), for stage "%s".', $stage)); + switch ($stage) { + case 'has-token': + case 'have-accounts': + Log::debug('isJobConfigured returns false'); - return true; + return false; + default: + Log::debug('isJobConfigured returns true'); + + return true; } - Log::debug('return false'); - - return false; } /** @@ -119,15 +179,17 @@ class SpectreConfigurator implements ConfiguratorInterface public function setJob(ImportJob $job) { $defaultConfig = [ - 'has-token' => false, - 'token' => '', - 'token-expires' => 0, - 'token-url' => '', - 'is-redirected' => false, - 'customer' => null, - 'login' => null, - 'stage' => 'initial', - 'accounts' => [], + 'has-token' => false, + 'token' => '', + 'token-expires' => 0, + 'token-url' => '', + 'is-redirected' => false, + 'customer' => null, + 'login' => null, + 'stage' => 'initial', + 'accounts' => '', + 'accounts-mapped' => '', + 'auto-start' => true, ]; $extendedStatus = $job->extended_status; $extendedStatus['steps'] = 100; diff --git a/app/Import/Routine/SpectreRoutine.php b/app/Import/Routine/SpectreRoutine.php index 7b9ba5425a..993983e062 100644 --- a/app/Import/Routine/SpectreRoutine.php +++ b/app/Import/Routine/SpectreRoutine.php @@ -26,12 +26,16 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\ImportJob; use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; use FireflyIII\Services\Spectre\Exception\DuplicatedCustomerException; +use FireflyIII\Services\Spectre\Exception\SpectreException; +use FireflyIII\Services\Spectre\Object\Account; use FireflyIII\Services\Spectre\Object\Customer; use FireflyIII\Services\Spectre\Object\Login; use FireflyIII\Services\Spectre\Object\Token; use FireflyIII\Services\Spectre\Request\CreateTokenRequest; +use FireflyIII\Services\Spectre\Request\ListAccountsRequest; use FireflyIII\Services\Spectre\Request\ListCustomersRequest; use FireflyIII\Services\Spectre\Request\ListLoginsRequest; +use FireflyIII\Services\Spectre\Request\ListTransactionsRequest; use FireflyIII\Services\Spectre\Request\NewCustomerRequest; use Illuminate\Support\Collection; use Log; @@ -99,6 +103,8 @@ class SpectreRoutine implements RoutineInterface * if attempt failed: job status is error, save a warning somewhere? * if success, try to get accounts. Save in config key 'accounts'. set status: have-accounts and "configuring" * + * have-accounts: make user link accounts and select accounts to import from. + * * If job is "configuring" and stage "have-accounts" then present the accounts and make user link them to * own asset accounts. Store this mapping, set config to "have-account-mapping" and job status configured". * @@ -111,90 +117,35 @@ class SpectreRoutine implements RoutineInterface public function run(): bool { if ('configured' === $this->job->status) { - $this->repository->updateStatus($this->job,'running'); + $this->repository->updateStatus($this->job, 'running'); } - - Log::info(sprintf('Start with import job %s using Spectre.', $this->job->key)); set_time_limit(0); // check if job has token first! - $config = $this->job->configuration; - $hasToken = $config['has-token'] ?? false; - if ($hasToken === false) { - Log::debug('Job has no token'); - // create customer if user does not have one: - $customer = $this->getCustomer(); - Log::debug(sprintf('Customer ID is %s', $customer->getId())); - // use customer to request a token: - $uri = route('import.status', [$this->job->key]); - $token = $this->getToken($customer, $uri); - Log::debug(sprintf('Token is %s', $token->getToken())); + $config = $this->job->configuration; + $stage = $config['stage']; - // update job, give it the token: - $config = $this->job->configuration; - $config['has-token'] = true; - $config['token'] = $token->getToken(); - $config['token-expires'] = $token->getExpiresAt()->format('U'); - $config['token-url'] = $token->getConnectUrl(); - $this->job->configuration = $config; - - Log::debug('Job config is now', $config); - - // update job, set status to "configuring". - $this->job->status = 'configuring'; - $this->job->save(); - Log::debug(sprintf('Job status is now %s', $this->job->status)); - - return true; + switch ($stage) { + case 'initial': + // get customer and token: + $this->runStageInitial(); + break; + case 'has-token': + // import routine does nothing at this point: + break; + case 'user-logged-in': + $this->runStageLoggedIn(); + break; + case 'have-account-mapping': + $this->runStageHaveMapping(); + break; + default: + throw new FireflyException(sprintf('Cannot handle stage %s', $stage)); } - $isRedirected = $config['is-redirected'] ?? false; - if ($isRedirected === true) { - // update job to say it's running - $extended = $this->job->extended_status; - $this->job->status = 'running'; - $extended['steps'] = 100; - $extended['done'] = 1; - $this->job->extended_status = $extended; - $this->job->save(); - } - // is job running? - if ($this->job->status === 'running') { - // list all logins: - $customer = $this->getCustomer(); - $request = new ListLoginsRequest($this->job->user); - $request->setCustomer($customer); - $request->call(); - $logins = $request->getLogins(); - /** @var Login $final */ - $final = null; - // loop logins, find the latest with no error in it: - $time = 0; - /** @var Login $login */ - foreach($logins as $login) { - $attempt = $login->getLastAttempt(); - $attemptTime = intval($attempt->getCreatedAt()->format('U')); - if($attemptTime > $time && is_null($attempt->getFailErrorClass())) { - $time = $attemptTime; - $final = $login; - } - } - if(is_null($final)) { - throw new FireflyException('No valid login attempt found.'); - } - var_dump($final); - - //var_dump($logins); - exit; - - // assume user has "used" the token. - // ... - // now what? - Log::debug('Token has been used. User was redirected. Now check status with Spectre and respond?'); - - throw new FireflyException('Application cannot handle this.'); - } + var_dump($config); + exit; throw new FireflyException('Application cannot handle this.'); } @@ -204,7 +155,7 @@ class SpectreRoutine implements RoutineInterface */ public function setJob(ImportJob $job) { - $this->job = $job; + $this->job = $job; $this->repository = app(ImportJobRepositoryInterface::class); $this->repository->setUser($job->user); } @@ -289,4 +240,124 @@ class SpectreRoutine implements RoutineInterface return $request->getToken(); } + + /** + * @throws FireflyException + * @throws SpectreException + */ + protected function runStageInitial(): void + { + Log::debug('In runStageInitial()'); + + // create customer if user does not have one: + $customer = $this->getCustomer(); + Log::debug(sprintf('Customer ID is %s', $customer->getId())); + + // use customer to request a token: + $uri = route('import.status', [$this->job->key]); + $token = $this->getToken($customer, $uri); + Log::debug(sprintf('Token is %s', $token->getToken())); + + // update job, give it the token: + $config = $this->job->configuration; + $config['has-token'] = true; + $config['token'] = $token->getToken(); + $config['token-expires'] = $token->getExpiresAt()->format('U'); + $config['token-url'] = $token->getConnectUrl(); + $config['stage'] = 'has-token'; + $this->job->configuration = $config; + + Log::debug('Job config is now', $config); + + // update job, set status to "configuring". + $this->job->status = 'configuring'; + $this->job->save(); + Log::debug(sprintf('Job status is now %s', $this->job->status)); + } + + /** + * @throws FireflyException + * @throws SpectreException + */ + protected function runStageLoggedIn(): void + { + Log::debug('In runStageLoggedIn'); + // list all logins: + $customer = $this->getCustomer(); + $request = new ListLoginsRequest($this->job->user); + $request->setCustomer($customer); + $request->call(); + $logins = $request->getLogins(); + /** @var Login $final */ + $final = null; + // loop logins, find the latest with no error in it: + $time = 0; + /** @var Login $login */ + foreach ($logins as $login) { + $attempt = $login->getLastAttempt(); + $attemptTime = intval($attempt->getCreatedAt()->format('U')); + if ($attemptTime > $time && is_null($attempt->getFailErrorClass())) { + $time = $attemptTime; + $final = $login; + } + } + if (is_null($final)) { + throw new FireflyException('No valid login attempt found.'); + } + + // list the users accounts using this login. + $accountRequest = new ListAccountsRequest($this->job->user); + $accountRequest->setLogin($login); + $accountRequest->call(); + $accounts = $accountRequest->getAccounts(); + + // store accounts in job: + $all = []; + /** @var Account $account */ + foreach ($accounts as $account) { + $all[] = $account->toArray(); + } + + // update job: + $config = $this->job->configuration; + $config['accounts'] = $all; + $config['login'] = $login->toArray(); + $config['stage'] = 'have-accounts'; + $this->job->configuration = $config; + $this->job->status = 'configuring'; + $this->job->save(); + + return; + } + + /** + * + */ + private function runStageHaveMapping() + { + // for each spectre account id in 'account-mappings'. + // find FF account + // get transactions. + // import?! + $config = $this->job->configuration; + $accounts = $config['accounts'] ?? []; + /** @var array $accountArray */ + foreach ($accounts as $accountArray) { + $account = new Account($accountArray); + $importId = intval($config['accounts-mapped'][$account->getid()] ?? 0); + $doImport = $importId !== 0 ? true : false; + if (!$doImport) { + continue; + } + // import into account + $listTransactionsRequest = new ListTransactionsRequest($this->job->user); + $listTransactionsRequest->setAccount($account); + $listTransactionsRequest->call(); + $transactions = $listTransactionsRequest->getTransactions(); + var_dump($transactions);exit; + + } + var_dump($config); + exit; + } } diff --git a/app/Services/Spectre/Object/Account.php b/app/Services/Spectre/Object/Account.php new file mode 100644 index 0000000000..92f01ed6c3 --- /dev/null +++ b/app/Services/Spectre/Object/Account.php @@ -0,0 +1,101 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Spectre\Object; + +use Carbon\Carbon; + +/** + * Class Account + */ +class Account extends SpectreObject +{ + /** @var float */ + private $balance; + /** @var Carbon */ + private $createdAt; + /** @var string */ + private $currencyCode; + /** @var array */ + private $extra = []; + /** @var int */ + private $id; + /** @var int */ + private $loginId; + /** @var string */ + private $name; + /** @var string */ + private $nature; + /** @var Carbon */ + private $updatedAt; + + /** + * Account constructor. + * + * @param array $data + */ + public function __construct(array $data) + { + $this->id = $data['id']; + $this->loginId = $data['login_id']; + $this->currencyCode = $data['currency_code']; + $this->balance = $data['balance']; + $this->name = $data['name']; + $this->nature = $data['nature']; + $this->createdAt = new Carbon($data['created_at']); + $this->updatedAt = new Carbon($data['updated_at']); + + foreach ($data['extra'] as $key => $value) { + $this->extra[$key] = $value; + } + } + + /** + * @return int + */ + public function getId(): int + { + return $this->id; + } + + /** + * @return array + */ + public function toArray(): array + { + $array = [ + 'balance' => $this->balance, + 'created_at' => $this->createdAt->toIso8601String(), + 'currency_code' => $this->currencyCode, + 'extra' => $this->extra, + 'id' => $this->id, + 'login_id' => $this->loginId, + 'name' => $this->name, + 'nature' => $this->nature, + 'updated_at' => $this->updatedAt->toIso8601String(), + ]; + + return $array; + } + +} \ No newline at end of file diff --git a/app/Services/Spectre/Object/Attempt.php b/app/Services/Spectre/Object/Attempt.php index 71b77bbbbe..c6151be494 100644 --- a/app/Services/Spectre/Object/Attempt.php +++ b/app/Services/Spectre/Object/Attempt.php @@ -163,6 +163,46 @@ class Attempt extends SpectreObject return $this->failMessage; } + /** + * @return array + */ + public function toArray(): array + { + $array = [ + 'api_mode' => $this->apiMode, + 'api_version' => $this->apiVersion, + 'automatic_fetch' => $this->automaticFetch, + 'categorize' => $this->categorize, + 'created_at' => $this->createdAt->toIso8601String(), + 'consent_given_at' => $this->consentGivenAt->toIso8601String(), + 'consent_types' => $this->consentTypes, + 'custom_fields' => $this->customFields, + 'daily_refresh' => $this->dailyRefresh, + 'device_type' => $this->deviceType, + 'user_agent' => $this->userAgent, + 'remote_ip' => $this->remoteIp, + 'exclude_accounts' => $this->excludeAccounts, + 'fail_at' => $this->failAt->toIso8601String(), + 'fail_error_class' => $this->failErrorClass, + 'fail_message' => $this->failMessage, + 'fetch_type' => $this->fetchType, + 'finished' => $this->finished, + 'finished_recent' => $this->finishedRecent, + 'from_date' => $this->fromDate->toIso8601String(), + 'id' => $this->id, + 'interactive' => $this->interactive, + 'locale' => $this->locale, + 'partial' => $this->partial, + 'show_consent_confirmation' => $this->showConsentInformation, + 'stages' => $this->stages, + 'store_credentials' => $this->storeCredentials, + 'success_at' => $this->successAt->toIso8601String(), + 'to_date' => $this->toDate->toIso8601String(), + 'updated_at' => $this->updatedAt->toIso8601String(), + ]; + + return $array; + } } \ No newline at end of file diff --git a/app/Services/Spectre/Object/Holder.php b/app/Services/Spectre/Object/Holder.php index d1e2922f7b..b6416f925b 100644 --- a/app/Services/Spectre/Object/Holder.php +++ b/app/Services/Spectre/Object/Holder.php @@ -37,4 +37,12 @@ class Holder extends SpectreObject { } + + /** + * @return array + */ + public function toArray(): array + { + return []; + } } \ No newline at end of file diff --git a/app/Services/Spectre/Object/Login.php b/app/Services/Spectre/Object/Login.php index 73fa3e2c6b..fb2624c5ad 100644 --- a/app/Services/Spectre/Object/Login.php +++ b/app/Services/Spectre/Object/Login.php @@ -96,6 +96,14 @@ class Login extends SpectreObject } + /** + * @return int + */ + public function getId(): int + { + return $this->id; + } + /** * @return Attempt */ @@ -104,5 +112,35 @@ class Login extends SpectreObject return $this->lastAttempt; } + /** + * @return array + */ + public function toArray(): array + { + $array = [ + 'consent_given_at' => $this->consentGivenAt->toIso8601String(), + 'consent_types' => $this->consentTypes, + 'country_code' => $this->countryCode, + 'created_at' => $this->createdAt->toIso8601String(), + 'updated_at' => $this->updatedAt->toIso8601String(), + 'customer_id' => $this->customerId, + 'daily_refresh' => $this->dailyRefresh, + 'holder_info' => $this->holderInfo->toArray(), + 'id' => $this->id, + 'last_attempt' => $this->lastAttempt->toArray(), + 'last_success_at' => $this->lastSuccessAt->toIso8601String(), + 'next_refresh_possible_at' => $this->nextRefreshPossibleAt, + 'provider_code' => $this->providerCode, + 'provider_id' => $this->providerId, + 'provider_name' => $this->providerName, + 'show_consent_confirmation' => $this->showConsentConfirmation, + 'status' => $this->status, + 'store_credentials' => $this->storeCredentials, + + ]; + + return $array; + } + } \ No newline at end of file diff --git a/app/Services/Spectre/Object/Transaction.php b/app/Services/Spectre/Object/Transaction.php new file mode 100644 index 0000000000..23c8633a91 --- /dev/null +++ b/app/Services/Spectre/Object/Transaction.php @@ -0,0 +1,41 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Spectre\Object; + +/** + * Class Transaction + */ +class Transaction extends SpectreObject +{ + /** + * Transaction constructor. + * + * @param array $data + */ + public function __construct(array $data) { + var_dump($data); + exit; + } + +} \ No newline at end of file diff --git a/app/Services/Spectre/Request/ListAccountsRequest.php b/app/Services/Spectre/Request/ListAccountsRequest.php new file mode 100644 index 0000000000..2912137d62 --- /dev/null +++ b/app/Services/Spectre/Request/ListAccountsRequest.php @@ -0,0 +1,93 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Spectre\Request; + +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Services\Spectre\Exception\SpectreException; +use FireflyIII\Services\Spectre\Object\Account; +use FireflyIII\Services\Spectre\Object\Login; +use Log; + +/** + * Class ListAccountsRequest + */ +class ListAccountsRequest extends SpectreRequest +{ + /** @var array */ + private $accounts = []; + /** @var Login */ + private $login; + + /** + * @throws SpectreException + * @throws FireflyException + */ + public function call(): void + { + $hasNextPage = true; + $nextId = 0; + while ($hasNextPage) { + Log::debug(sprintf('Now calling ListAccountsRequest for next_id %d', $nextId)); + $parameters = ['from_id' => $nextId, 'login_id' => $this->login->getId()]; + $uri = '/api/v3/accounts?' . http_build_query($parameters); + $response = $this->sendSignedSpectreGet($uri, []); + + // count entries: + Log::debug(sprintf('Found %d entries in data-array', count($response['data']))); + + // extract next ID + $hasNextPage = false; + if (isset($response['meta']['next_id']) && intval($response['meta']['next_id']) > $nextId) { + $hasNextPage = true; + $nextId = $response['meta']['next_id']; + Log::debug(sprintf('Next ID is now %d.', $nextId)); + } else { + Log::debug('No next page.'); + } + + // store customers: + foreach ($response['data'] as $accountArray) { + $this->accounts[] = new Account($accountArray); + } + } + } + + /** + * @return array + */ + public function getAccounts(): array + { + return $this->accounts; + } + + /** + * @param Login $login + */ + public function setLogin(Login $login): void + { + $this->login = $login; + } + + +} \ No newline at end of file diff --git a/app/Services/Spectre/Request/ListTransactionsRequest.php b/app/Services/Spectre/Request/ListTransactionsRequest.php new file mode 100644 index 0000000000..57f45f199a --- /dev/null +++ b/app/Services/Spectre/Request/ListTransactionsRequest.php @@ -0,0 +1,90 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Spectre\Request; + +use FireflyIII\Services\Spectre\Object\Account; +use FireflyIII\Services\Spectre\Object\Transaction; +use Log; +/** + * Class ListTransactionsRequest + */ +class ListTransactionsRequest extends SpectreRequest +{ + /** @var Account */ + private $account; + /** @var array */ + private $transactions = []; + + /** + * + */ + public function call(): void + { + $hasNextPage = true; + $nextId = 0; + while ($hasNextPage) { + Log::debug(sprintf('Now calling ListTransactionsRequest for next_id %d', $nextId)); + $parameters = ['from_id' => $nextId,'account_id' => $this->account->getId()]; + $uri = '/api/v3/transactions?' . http_build_query($parameters); + $response = $this->sendSignedSpectreGet($uri, []); + + // count entries: + Log::debug(sprintf('Found %d entries in data-array', count($response['data']))); + + // extract next ID + $hasNextPage = false; + if (isset($response['meta']['next_id']) && intval($response['meta']['next_id']) > $nextId) { + $hasNextPage = true; + $nextId = $response['meta']['next_id']; + Log::debug(sprintf('Next ID is now %d.', $nextId)); + } else { + Log::debug('No next page.'); + } + + // store customers: + foreach ($response['data'] as $transactionArray) { + $this->transactions[] = new Transaction($transactionArray); + } + } + } + + /** + * @return array + */ + public function getTransactions(): array + { + return $this->transactions; + } + + + /** + * @param Account $account + */ + public function setAccount(Account $account): void + { + $this->account = $account; + } + + +} \ No newline at end of file diff --git a/app/Support/Import/Configuration/Spectre/HaveAccounts.php b/app/Support/Import/Configuration/Spectre/HaveAccounts.php new file mode 100644 index 0000000000..796d05afd9 --- /dev/null +++ b/app/Support/Import/Configuration/Spectre/HaveAccounts.php @@ -0,0 +1,157 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Support\Import\Configuration\Spectre; + + +use FireflyIII\Models\Account; +use FireflyIII\Models\AccountType; +use FireflyIII\Models\ImportJob; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use FireflyIII\Support\Import\Configuration\ConfigurationInterface; +use Illuminate\Support\Collection; + +/** + * Class HaveAccounts + */ +class HaveAccounts implements ConfigurationInterface +{ + /** @var ImportJob */ + private $job; + + /** + * Get the data necessary to show the configuration screen. + * + * @return array + */ + public function getData(): array + { + /** @var AccountRepositoryInterface $accountRepository */ + $accountRepository = app(AccountRepositoryInterface::class); + /** @var CurrencyRepositoryInterface $currencyRepository */ + $currencyRepository = app(CurrencyRepositoryInterface::class); + $data = []; + $config = $this->job->configuration; + $collection = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]); + $defaultCurrency = app('amount')->getDefaultCurrency(); + $dbAccounts = []; + /** @var Account $dbAccount */ + foreach ($collection as $dbAccount) { + $id = $dbAccount->id; + $currencyId = intval($dbAccount->getMeta('currency_id')); + $currency = $currencyRepository->find($currencyId); + $dbAccounts[$id] = [ + 'account' => $dbAccount, + 'currency' => is_null($currency->id) ? $defaultCurrency : $currency, + ]; + } + + // loop Spectre accounts: + /** + * @var int $index + * @var array $spectreAccount + */ + foreach ($config['accounts'] as $index => $spectreAccount) { + // find accounts with currency code + $code = $spectreAccount['currency_code']; + $selection = $this->filterAccounts($dbAccounts, $code); + $config['accounts'][$index]['options'] = app('expandedform')->makeSelectList($selection); + } + + + $data = [ + 'config' => $config, + ]; + + + return $data; + } + + /** + * Return possible warning to user. + * + * @return string + */ + public function getWarningMessage(): string + { + return ''; + } + + /** + * @param ImportJob $job + * + * @return ConfigurationInterface + */ + public function setJob(ImportJob $job) + { + $this->job = $job; + + return $this; + } + + /** + * Store the result. + * + * @param array $data + * + * @return bool + */ + public function storeConfiguration(array $data): bool + { + $accounts = $data['spectre_account_id'] ?? []; + $mapping = []; + foreach ($accounts as $spectreId) { + $spectreId = intval($spectreId); + $doImport = intval($data['do_import'][$spectreId] ?? 0) === 1; + $account = intval($data['import'][$spectreId] ?? 0); + if ($doImport) { + $mapping[$spectreId] = $account; + } + } + $config = $this->job->configuration; + $config['accounts-mapped'] = $mapping; + $this->job->configuration = $config; + $this->job->save(); + + return true; + } + + /** + * @param array $dbAccounts + * @param string $code + * + * @return Collection + */ + private function filterAccounts(array $dbAccounts, string $code): Collection + { + $collection = new Collection; + foreach ($dbAccounts as $accountId => $data) { + if ($data['currency']->code === $code) { + $collection->push($data['account']); + } + } + + return $collection; + } +} \ No newline at end of file diff --git a/public/js/ff/import/status.js b/public/js/ff/import/status.js index c05560cafd..fc65d88ace 100644 --- a/public/js/ff/import/status.js +++ b/public/js/ff/import/status.js @@ -174,14 +174,20 @@ function jobIsStalled(data) { /** * This function tells Firefly start the job. It will also initialize a re-check in 500ms time. + * Only when job is in "configured" state. */ function startJob() { - // disable the button, add loading thing. - $('.start-job').prop('disabled', true).text('...'); - $.post(jobStartUri, {_token: token}).fail(reportOnSubmitError); + if (job.status === "configured") { + console.log("Job auto started!"); + // disable the button, add loading thing. + $('.start-job').prop('disabled', true).text('...'); + $.post(jobStartUri, {_token: token}).fail(reportOnSubmitError); - // check status, every 500 ms. - timeOutId = setTimeout(checkJobStatus, startInterval); + // check status, every 500 ms. + timeOutId = setTimeout(checkJobStatus, startInterval); + return; + } + console.log("Job not auto started because state is " + job.status); } /** diff --git a/resources/views/accounts/index.twig b/resources/views/accounts/index.twig index 1783050235..e64c115625 100644 --- a/resources/views/accounts/index.twig +++ b/resources/views/accounts/index.twig @@ -33,7 +33,7 @@ {% endif %} - {% if accounts.count == 0 and page == 0 %} + {% if accounts.count == 0 and page == 1 %} {% include 'partials.empty' with {what: what, type: 'accounts',route: route('accounts.create', [what])} %} {% endif %} {% endblock %} diff --git a/resources/views/form/options.twig b/resources/views/form/options.twig index 936ec85601..b32a53f7a1 100644 --- a/resources/views/form/options.twig +++ b/resources/views/form/options.twig @@ -5,7 +5,7 @@
-
+
-