diff --git a/app/Http/Controllers/Import/JobStatusController.php b/app/Http/Controllers/Import/JobStatusController.php index c9b53a4eb9..3e7e7258ff 100644 --- a/app/Http/Controllers/Import/JobStatusController.php +++ b/app/Http/Controllers/Import/JobStatusController.php @@ -94,7 +94,7 @@ class JobStatusController extends Controller if ($count === 0) { $json['report_txt'] = trans('import.result_no_transactions'); } - if ($count === 1) { + if ($count === 1 && null !== $importJob->tag_id) { $json['report_txt'] = trans('import.result_one_transaction', ['route' => route('tags.show', [$importJob->tag_id]), 'tag' => $importJob->tag->tag]); } if ($count > 1 && null !== $importJob->tag_id) { diff --git a/app/Http/Controllers/Import/PrerequisitesController.php b/app/Http/Controllers/Import/PrerequisitesController.php index 7a6668d708..d0e4d5bbd6 100644 --- a/app/Http/Controllers/Import/PrerequisitesController.php +++ b/app/Http/Controllers/Import/PrerequisitesController.php @@ -151,8 +151,8 @@ class PrerequisitesController extends Controller if ($result->count() > 0) { $request->session()->flash('error', $result->first()); - // redirect back: - return redirect(route('import.prerequisites.index', [$importProvider, $importJob->key]))->withInput(); + // redirect back to job, if has job: + return redirect(route('import.prerequisites.index', [$importProvider, $importJob->key ?? '']))->withInput(); } // session flash! diff --git a/app/Import/JobConfiguration/BunqJobConfiguration.php b/app/Import/JobConfiguration/BunqJobConfiguration.php new file mode 100644 index 0000000000..e2f29cea69 --- /dev/null +++ b/app/Import/JobConfiguration/BunqJobConfiguration.php @@ -0,0 +1,128 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Import\JobConfiguration; + +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\ImportJob; +use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use FireflyIII\Support\Import\JobConfiguration\Bunq\BunqJobConfigurationInterface; +use FireflyIII\Support\Import\JobConfiguration\Bunq\ChooseAccountsHandler; +use FireflyIII\Support\Import\JobConfiguration\Bunq\NewBunqJobHandler; +use Illuminate\Support\MessageBag; +use Log; + +/** + * Class BunqJobConfiguration + */ +class BunqJobConfiguration implements JobConfigurationInterface +{ + /** @var BunqJobConfigurationInterface */ + private $handler; + /** @var ImportJob */ + private $importJob; + /** @var ImportJobRepositoryInterface */ + private $repository; + + /** + * Returns true when the initial configuration for this job is complete. + * + * @return bool + */ + public function configurationComplete(): bool + { + return $this->handler->configurationComplete(); + } + + /** + * Store any data from the $data array into the job. Anything in the message bag will be flashed + * as an error to the user, regardless of its content. + * + * @param array $data + * + * @return MessageBag + */ + public function configureJob(array $data): MessageBag + { + return $this->handler->configureJob($data); + } + + /** + * Return the data required for the next step in the job configuration. + * + * @return array + */ + public function getNextData(): array + { + return $this->handler->getNextData(); + } + + /** + * Returns the view of the next step in the job configuration. + * + * @return string + */ + public function getNextView(): string + { + return $this->handler->getNextView(); + } + + /** + * @param ImportJob $importJob + * + * @throws FireflyException + */ + public function setImportJob(ImportJob $importJob): void + { + $this->importJob = $importJob; + $this->repository = app(ImportJobRepositoryInterface::class); + $this->repository->setUser($importJob->user); + $this->handler = $this->getHandler(); + } + + /** + * @return BunqJobConfigurationInterface + * @throws FireflyException + */ + private function getHandler(): BunqJobConfigurationInterface + { + Log::debug(sprintf('Now in BunqJobConfiguration::getHandler() with stage "%s"', $this->importJob->stage)); + $handler = null; + switch ($this->importJob->stage) { + case 'new'; + $handler = app(NewBunqJobHandler::class); + break; + case 'choose-accounts': + /** @var ChooseAccountsHandler $handler */ + $handler = app(ChooseAccountsHandler::class); + $handler->setImportJob($this->importJob); + break; + default: + // @codeCoverageIgnoreStart + throw new FireflyException(sprintf('Firefly III cannot create a configuration handler for stage "%s"', $this->importJob->stage)); + // @codeCoverageIgnoreEnd + } + + return $handler; + } +} \ No newline at end of file diff --git a/app/Import/JobConfiguration/SpectreJobConfiguration.php b/app/Import/JobConfiguration/SpectreJobConfiguration.php index 6d7c0f0c87..1251ebf6f4 100644 --- a/app/Import/JobConfiguration/SpectreJobConfiguration.php +++ b/app/Import/JobConfiguration/SpectreJobConfiguration.php @@ -35,7 +35,7 @@ use FireflyIII\Support\Import\JobConfiguration\Spectre\ChooseLoginHandler; use FireflyIII\Support\Import\JobConfiguration\Spectre\DoAuthenticateHandler; use FireflyIII\Support\Import\JobConfiguration\Spectre\NewConfig; use FireflyIII\Support\Import\JobConfiguration\Spectre\NewSpectreJobHandler; -use FireflyIII\Support\Import\JobConfiguration\Spectre\SpectreConfigurationInterface; +use FireflyIII\Support\Import\JobConfiguration\Spectre\SpectreJobConfigurationInterface; use Illuminate\Support\MessageBag; use Log; @@ -44,7 +44,7 @@ use Log; */ class SpectreJobConfiguration implements JobConfigurationInterface { - /** @var SpectreConfigurationInterface */ + /** @var SpectreJobConfigurationInterface */ private $handler; /** @var ImportJob */ private $importJob; @@ -108,10 +108,10 @@ class SpectreJobConfiguration implements JobConfigurationInterface } /** - * @return SpectreConfigurationInterface + * @return SpectreJobConfigurationInterface * @throws FireflyException */ - private function getHandler(): SpectreConfigurationInterface + private function getHandler(): SpectreJobConfigurationInterface { Log::debug(sprintf('Now in SpectreJobConfiguration::getHandler() with stage "%s"', $this->importJob->stage)); $handler = null; diff --git a/app/Import/Prerequisites/BunqPrerequisites.php b/app/Import/Prerequisites/BunqPrerequisites.php index ac4056fe7c..80b8bba85a 100644 --- a/app/Import/Prerequisites/BunqPrerequisites.php +++ b/app/Import/Prerequisites/BunqPrerequisites.php @@ -22,160 +22,23 @@ declare(strict_types=1); namespace FireflyIII\Import\Prerequisites; +use bunq\Context\ApiContext; +use bunq\Exception\BadRequestException; +use bunq\Exception\BunqException; +use bunq\Util\BunqEnumApiEnvironmentType; use FireflyIII\Services\IP\IPRetrievalInterface; use FireflyIII\User; -use Illuminate\Http\Request; use Illuminate\Support\MessageBag; use Log; -use Preferences; /** - * @deprecated - * @codeCoverageIgnore * This class contains all the routines necessary to connect to Bunq. */ class BunqPrerequisites implements PrerequisitesInterface { /** @var User */ private $user; - // - // /** - // * Returns view name that allows user to fill in prerequisites. Currently asks for the API key. - // * - // * @return string - // */ - // public function getView(): string - // { - // Log::debug('Now in BunqPrerequisites::getView()'); - // - // return 'import.bunq.prerequisites'; - // } - // - // /** - // * Returns any values required for the prerequisites-view. - // * - // * @return array - // */ - // public function getViewParameters(): array - // { - // Log::debug('Now in BunqPrerequisites::getViewParameters()'); - // $key = ''; - // $serverIP = ''; - // if ($this->hasApiKey()) { - // $key = Preferences::getForUser($this->user, 'bunq_api_key', null)->data; - // } - // if ($this->hasServerIP()) { - // $serverIP = Preferences::getForUser($this->user, 'external_ip', null)->data; - // } - // if (!$this->hasServerIP()) { - // /** @var IPRetrievalInterface $service */ - // $service = app(IPRetrievalInterface::class); - // $serverIP = (string)$service->getIP(); - // } - // - // - // // get IP address - // return ['key' => $key, 'ip' => $serverIP]; - // } - // - // /** - // * Returns if this import method has any special prerequisites such as config - // * variables or other things. The only thing we verify is the presence of the API key. Everything else - // * tumbles into place: no installation token? Will be requested. No device server? Will be created. Etc. - // * - // * @return bool - // */ - // public function hasPrerequisites(): bool - // { - // $hasApiKey = $this->hasApiKey(); - // $hasServerIP = $this->hasServerIP(); - // - // return !$hasApiKey || !$hasServerIP; - // } - // - // /** - // * Indicate if all prerequisites have been met. - // * - // * @return bool - // */ - // public function isComplete(): bool - // { - // // is complete when user has entered both the API key - // // and his IP address. - // - // $hasApiKey = $this->hasApiKey(); - // $hasServerIP = $this->hasServerIP(); - // - // return $hasApiKey && $hasServerIP; - // } - // - // /** - // * Set the user for this Prerequisites-routine. Class is expected to implement and save this. - // * - // * @param User $user - // */ - // public function setUser(User $user): void - // { - // Log::debug(sprintf('Now in setUser(#%d)', $user->id)); - // $this->user = $user; - // } - // - // /** - // * This method responds to the user's submission of an API key. It tries to register this instance as a new Firefly III device. - // * If this fails, the error is returned in a message bag and the user is notified (this is fairly friendly). - // * - // * @param Request $request - // * - // * @return MessageBag - // */ - // public function storePrerequisites(Request $request): MessageBag - // { - // $apiKey = $request->get('api_key'); - // $serverIP = $request->get('external_ip'); - // Log::debug('Storing bunq API key'); - // Preferences::setForUser($this->user, 'bunq_api_key', $apiKey); - // Preferences::setForUser($this->user, 'external_ip', $serverIP); - // - // return new MessageBag; - // } - // - // /** - // * @return bool - // */ - // private function hasApiKey(): bool - // { - // $apiKey = Preferences::getForUser($this->user, 'bunq_api_key', false); - // if (null === $apiKey) { - // return false; - // } - // if (null === $apiKey->data) { - // return false; - // } - // if (\strlen((string)$apiKey->data) === 64) { - // return true; - // } - // - // return false; - // } - // - // /** - // * @return bool - // */ - // private function hasServerIP(): bool - // { - // $serverIP = Preferences::getForUser($this->user, 'external_ip', false); - // if (null === $serverIP) { - // return false; - // } - // if (null === $serverIP->data) { - // return false; - // } - // if (\strlen((string)$serverIP->data) > 6) { - // return true; - // } - // - // return false; - // } + /** * Returns view name that allows user to fill in prerequisites. * @@ -183,7 +46,7 @@ class BunqPrerequisites implements PrerequisitesInterface */ public function getView(): string { - return 'todo'; + return 'import.bunq.prerequisites'; } /** @@ -193,7 +56,22 @@ class BunqPrerequisites implements PrerequisitesInterface */ public function getViewParameters(): array { - return []; + Log::debug('Now in BunqPrerequisites::getViewParameters()'); + $key = ''; + $externalIP = ''; + if ($this->hasApiKey()) { + $key = app('preferences')->getForUser($this->user, 'bunq_api_key', null)->data; + } + if ($this->hasExternalIP()) { + $externalIP = app('preferences')->getForUser($this->user, 'bunq_external_ip', null)->data; + } + if (!$this->hasExternalIP()) { + /** @var IPRetrievalInterface $service */ + $service = app(IPRetrievalInterface::class); + $externalIP = (string)$service->getIP(); + } + + return ['api_key' => $key, 'external_ip' => $externalIP]; } /** @@ -203,7 +81,7 @@ class BunqPrerequisites implements PrerequisitesInterface */ public function isComplete(): bool { - return false; + return $this->hasApiKey() && $this->hasExternalIP() && $this->hasApiContext(); } /** @@ -227,6 +105,105 @@ class BunqPrerequisites implements PrerequisitesInterface */ public function storePrerequisites(array $data): MessageBag { + $apiKey = $data['api_key'] ?? ''; + $externalIP = $data['external_ip'] ?? ''; + Log::debug('Storing bunq API key'); + app('preferences')->setForUser($this->user, 'bunq_api_key', $apiKey); + app('preferences')->setForUser($this->user, 'bunq_external_ip', $externalIP); + + $environment = $this->getBunqEnvironment(); + $deviceDescription = 'Firefly III v' . config('firefly.version'); + $permittedIps = [$externalIP]; + + try { + $apiContext = ApiContext::create( + $environment, + $apiKey, + $deviceDescription, + $permittedIps + ); + } catch (BadRequestException $e) { + $messages = new MessageBag(); + $messages->add('bunq_error', $e->getMessage()); + + return $messages; + } + // store context in JSON: + try { + $json = $apiContext->toJson(); + } catch (BunqException $e) { + $messages = new MessageBag(); + $messages->add('bunq_error', $e->getMessage()); + + return $messages; + } + // and store for user: + app('preferences')->setForUser($this->user, 'bunq_api_context', $json); + return new MessageBag; } + + /** + * @return BunqEnumApiEnvironmentType + */ + private function getBunqEnvironment(): BunqEnumApiEnvironmentType + { + $env = env('BUNQ_USE_SANDBOX'); + if (null === $env) { + return BunqEnumApiEnvironmentType::PRODUCTION(); + } + if (false === $env) { + return BunqEnumApiEnvironmentType::PRODUCTION(); + } + + return BunqEnumApiEnvironmentType::SANDBOX(); + } + + /** + * @return bool + */ + private function hasApiContext(): bool + { + $apiContext = app('preferences')->getForUser($this->user, 'bunq_api_context', null); + if (null === $apiContext) { + return false; + } + if ('' === (string)$apiContext->data) { + return false; + } + + return true; + } + + /** + * @return bool + */ + private function hasApiKey(): bool + { + $apiKey = app('preferences')->getForUser($this->user, 'bunq_api_key', null); + if (null === $apiKey) { + return false; + } + if ('' === (string)$apiKey->data) { + return false; + } + + return true; + } + + /** + * @return bool + */ + private function hasExternalIP(): bool + { + $externalIP = app('preferences')->getForUser($this->user, 'bunq_external_ip', null); + if (null === $externalIP) { + return false; + } + if ('' === (string)$externalIP->data) { + return false; + } + + return true; + } } diff --git a/app/Import/Routine/BunqRoutine.php b/app/Import/Routine/BunqRoutine.php index a369bcefe6..3f3994afc0 100644 --- a/app/Import/Routine/BunqRoutine.php +++ b/app/Import/Routine/BunqRoutine.php @@ -23,896 +23,24 @@ declare(strict_types=1); namespace FireflyIII\Import\Routine; -use Carbon\Carbon; -use DB; use FireflyIII\Exceptions\FireflyException; -use FireflyIII\Factory\AccountFactory; -use FireflyIII\Factory\TransactionJournalFactory; -use FireflyIII\Models\Account; -use FireflyIII\Models\AccountType; use FireflyIII\Models\ImportJob; -use FireflyIII\Models\TransactionJournalMeta; -use FireflyIII\Models\TransactionType; -use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; -use FireflyIII\Repositories\Tag\TagRepositoryInterface; -use FireflyIII\Services\Bunq\Id\DeviceServerId; -use FireflyIII\Services\Bunq\Object\DeviceServer; -use FireflyIII\Services\Bunq\Object\LabelMonetaryAccount; -use FireflyIII\Services\Bunq\Object\MonetaryAccountBank; -use FireflyIII\Services\Bunq\Object\Payment; -use FireflyIII\Services\Bunq\Object\ServerPublicKey; -use FireflyIII\Services\Bunq\Object\UserCompany; -use FireflyIII\Services\Bunq\Object\UserPerson; -use FireflyIII\Services\Bunq\Request\DeviceServerRequest; -use FireflyIII\Services\Bunq\Request\DeviceSessionRequest; -use FireflyIII\Services\Bunq\Request\InstallationTokenRequest; -use FireflyIII\Services\Bunq\Request\ListDeviceServerRequest; -use FireflyIII\Services\Bunq\Request\ListMonetaryAccountRequest; -use FireflyIII\Services\Bunq\Request\ListPaymentRequest; -use FireflyIII\Services\Bunq\Token\InstallationToken; -use FireflyIII\Services\Bunq\Token\SessionToken; -use FireflyIII\Services\IP\IPRetrievalInterface; -use Illuminate\Support\Collection; +use FireflyIII\Support\Import\Routine\Bunq\StageImportDataHandler; +use FireflyIII\Support\Import\Routine\Bunq\StageNewHandler; use Log; -use Preferences; /** - * @deprecated - * @codeCoverageIgnore * Class BunqRoutine - * - * Steps before import: - * 1) register device complete. - * - * Stage: 'initial'. - * - * 1) Get an installation token (if not present) - * 2) Register device (if not found) - * - * Stage 'registered' - * - * 1) Get a session token. (new session) - * 2) store user person / user company - * - * Stage 'logged-in' - * - * Get list of bank accounts - * - * Stage 'have-accounts' - * - * Map accounts to existing accounts - * - * Stage 'do-import'? */ class BunqRoutine implements RoutineInterface { -// /** @var Collection */ -// public $errors; -// /** @var Collection */ -// public $journals; -// /** @var int */ -// public $lines = 0; -// /** @var AccountFactory */ -// private $accountFactory; -// /** @var AccountRepositoryInterface */ -// private $accountRepository; -// /** @var ImportJob */ -// private $job; -// /** @var TransactionJournalFactory */ -// private $journalFactory; -// /** @var ImportJobRepositoryInterface */ -// private $repository; -// -// /** -// * ImportRoutine constructor. -// */ -// public function __construct() -// { -// $this->journals = new Collection; -// $this->errors = new Collection; -// } -// -// /** -// * @return Collection -// */ -// public function getErrors(): Collection -// { -// return $this->errors; -// } -// -// /** -// * @return Collection -// */ -// public function getJournals(): Collection -// { -// return $this->journals; -// } -// -// /** -// * @return int -// */ -// public function getLines(): int -// { -// return $this->lines; -// } -// -// /** -// * @return bool -// * -// * @throws FireflyException -// */ -// public function run(): bool -// { -// Log::info(sprintf('Start with import job %s using Bunq.', $this->job->key)); -// set_time_limit(0); -// // this method continues with the job and is called by whenever a stage is -// // finished -// $this->continueJob(); -// -// return true; -// } -// -// /** -// * @param ImportJob $job -// */ -// public function setJob(ImportJob $job) -// { -// $this->job = $job; -// $this->repository = app(ImportJobRepositoryInterface::class); -// $this->accountRepository = app(AccountRepositoryInterface::class); -// $this->accountFactory = app(AccountFactory::class); -// $this->journalFactory = app(TransactionJournalFactory::class); -// $this->repository->setUser($job->user); -// $this->accountRepository->setUser($job->user); -// $this->accountFactory->setUser($job->user); -// $this->journalFactory->setUser($job->user); -// } -// -// /** -// * @throws FireflyException -// */ -// protected function continueJob() -// { -// // if in "configuring" -// if ('configuring' === $this->getStatus()) { -// Log::debug('Job is in configuring stage, will do nothing.'); -// -// return; -// } -// $stage = $this->getConfig()['stage'] ?? 'unknown'; -// Log::debug(sprintf('Now in continueJob() for stage %s', $stage)); -// switch ($stage) { -// case 'initial': -// // register device and get tokens. -// $this->runStageInitial(); -// $this->continueJob(); -// break; -// case 'registered': -// // get all bank accounts of user. -// $this->runStageRegistered(); -// $this->continueJob(); -// break; -// case 'logged-in': -// $this->runStageLoggedIn(); -// break; -// case 'have-accounts': -// // do nothing in this stage. Job should revert to config routine. -// break; -// case 'have-account-mapping': -// $this->setStatus('running'); -// $this->runStageHaveAccountMapping(); -// -// break; -// default: -// throw new FireflyException(sprintf('No action for stage %s!', $stage)); -// break; -// } -// } -// -// /** -// * @throws FireflyException -// */ -// protected function runStageInitial(): void -// { -// $this->addStep(); -// Log::debug('In runStageInitial()'); -// $this->setStatus('running'); -// -// // register the device at Bunq: -// $serverId = $this->registerDevice(); -// Log::debug(sprintf('Found device server with id %d', $serverId->getId())); -// -// $config = $this->getConfig(); -// $config['stage'] = 'registered'; -// $this->setConfig($config); -// $this->addStep(); -// } -// -// /** -// * Get a session token + userperson + usercompany. Store it in the job. -// * -// * @throws FireflyException -// */ -// protected function runStageRegistered(): void -// { -// $this->addStep(); -// Log::debug('Now in runStageRegistered()'); -// $apiKey = (string)Preferences::getForUser($this->job->user, 'bunq_api_key')->data; -// $serverPublicKey = new ServerPublicKey(Preferences::getForUser($this->job->user, 'bunq_server_public_key', [])->data); -// $installationToken = $this->getInstallationToken(); -// $request = new DeviceSessionRequest; -// $request->setInstallationToken($installationToken); -// $request->setPrivateKey($this->getPrivateKey()); -// $request->setServerPublicKey($serverPublicKey); -// $request->setSecret($apiKey); -// $request->call(); -// $this->addStep(); -// -// Log::debug('Requested new session.'); -// -// $deviceSession = $request->getDeviceSessionId(); -// $userPerson = $request->getUserPerson(); -// $userCompany = $request->getUserCompany(); -// $sessionToken = $request->getSessionToken(); -// -// $config = $this->getConfig(); -// $config['device_session_id'] = $deviceSession->toArray(); -// $config['user_person'] = $userPerson->toArray(); -// $config['user_company'] = $userCompany->toArray(); -// $config['session_token'] = $sessionToken->toArray(); -// $config['stage'] = 'logged-in'; -// $this->setConfig($config); -// $this->addStep(); -// -// Log::debug('Session stored in job.'); -// } -// -// /** -// * Shorthand method. -// */ -// private function addStep(): void -// { -// $this->addSteps(1); -// } -// -// /** -// * Shorthand method. -// * -// * @param int $count -// */ -// private function addSteps(int $count): void -// { -// $this->repository->addStepsDone($this->job, $count); -// } -// -// /** -// * Shorthand method -// * -// * @param int $steps -// */ -// private function addTotalSteps(int $steps): void -// { -// $this->repository->addTotalSteps($this->job, $steps); -// } -// -// /** -// * @param int $paymentId -// * -// * @return bool -// */ -// private function alreadyImported(int $paymentId): bool -// { -// $count = TransactionJournalMeta::where('name', 'bunq_payment_id') -// ->where('data', json_encode($paymentId))->count(); -// -// Log::debug(sprintf('Transaction #%d is %d time(s) in the database.', $paymentId, $count)); -// -// return $count > 0; -// } -// -// /** -// * @param LabelMonetaryAccount $party -// * @param string $expectedType -// * -// * @return Account -// */ -// private function convertToAccount(LabelMonetaryAccount $party, string $expectedType): Account -// { -// Log::debug('in convertToAccount()'); -// -// if ($party->getIban() !== null) { -// // find opposing party by IBAN first. -// $result = $this->accountRepository->findByIbanNull($party->getIban(), [$expectedType]); -// if (null !== $result) { -// Log::debug(sprintf('Search for %s resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id)); -// -// return $result; -// } -// -// // try to find asset account just in case: -// if ($expectedType !== AccountType::ASSET) { -// $result = $this->accountRepository->findByIbanNull($party->getIban(), [AccountType::ASSET]); -// if (null !== $result) { -// Log::debug(sprintf('Search for Asset "%s" resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id)); -// -// return $result; -// } -// } -// } -// -// // create new account: -// $data = [ -// 'user_id' => $this->job->user_id, -// 'iban' => $party->getIban(), -// 'name' => $party->getLabelUser()->getDisplayName(), -// 'account_type_id' => null, -// 'accountType' => $expectedType, -// 'virtualBalance' => null, -// 'active' => true, -// -// ]; -// $account = $this->accountFactory->create($data); -// Log::debug( -// sprintf( -// 'Converted label monetary account %s to %s account %s (#%d)', -// $party->getLabelUser()->getDisplayName(), -// $expectedType, -// $account->name, $account->id -// ) -// ); -// -// return $account; -// } -// -// /** -// * This method creates a new public/private keypair for the user. This isn't really secure, since the key is generated on the fly with -// * no regards for HSM's, smart cards or other things. It would require some low level programming to get this right. But the private key -// * is stored encrypted in the database so it's something. -// */ -// private function createKeyPair(): void -// { -// Log::debug('Now in createKeyPair()'); -// $private = Preferences::getForUser($this->job->user, 'bunq_private_key', null); -// $public = Preferences::getForUser($this->job->user, 'bunq_public_key', null); -// -// if (!(null === $private && null === $public)) { -// Log::info('Already have public and private key, return NULL.'); -// -// return; -// } -// -// Log::debug('Generate new key pair for user.'); -// $keyConfig = [ -// 'digest_alg' => 'sha512', -// 'private_key_bits' => 2048, -// 'private_key_type' => OPENSSL_KEYTYPE_RSA, -// ]; -// // Create the private and public key -// $res = openssl_pkey_new($keyConfig); -// -// // Extract the private key from $res to $privKey -// $privKey = ''; -// openssl_pkey_export($res, $privKey); -// -// // Extract the public key from $res to $pubKey -// $pubKey = openssl_pkey_get_details($res); -// -// Preferences::setForUser($this->job->user, 'bunq_private_key', $privKey); -// Preferences::setForUser($this->job->user, 'bunq_public_key', $pubKey['key']); -// Log::debug('Created and stored key pair'); -// } -// -// /** -// * Shorthand method. -// * -// * @return array -// */ -// private function getConfig(): array -// { -// return $this->repository->getConfiguration($this->job); -// } -// -// /** -// * Try to detect the current device ID (in case this instance has been registered already. -// * -// * @return DeviceServerId -// * -// * @throws FireflyException -// */ -// private function getExistingDevice(): ?DeviceServerId -// { -// Log::debug('Now in getExistingDevice()'); -// $installationToken = $this->getInstallationToken(); -// $serverPublicKey = $this->getServerPublicKey(); -// $request = new ListDeviceServerRequest; -// $remoteIp = $this->getRemoteIp(); -// $request->setInstallationToken($installationToken); -// $request->setServerPublicKey($serverPublicKey); -// $request->setPrivateKey($this->getPrivateKey()); -// $request->call(); -// $devices = $request->getDevices(); -// /** @var DeviceServer $device */ -// foreach ($devices as $device) { -// if ($device->getIp() === $remoteIp) { -// Log::debug(sprintf('This instance is registered as device #%s', $device->getId()->getId())); -// -// return $device->getId(); -// } -// } -// Log::info('This instance is not yet registered.'); -// -// return null; -// } -// -// /** -// * Shorthand method. -// * -// * @return array -// */ -// private function getExtendedStatus(): array -// { -// return $this->repository->getExtendedStatus($this->job); -// } -// -// /** -// * Get the installation token, either from the users preferences or from Bunq. -// * -// * @return InstallationToken -// * -// * @throws FireflyException -// */ -// private function getInstallationToken(): InstallationToken -// { -// Log::debug('Now in getInstallationToken().'); -// $token = Preferences::getForUser($this->job->user, 'bunq_installation_token', null); -// if (null !== $token) { -// Log::debug('Have installation token, return it.'); -// -// return new InstallationToken($token->data); -// } -// Log::debug('Have no installation token, request one.'); -// -// // verify bunq api code: -// $publicKey = $this->getPublicKey(); -// $request = new InstallationTokenRequest; -// $request->setPublicKey($publicKey); -// $request->call(); -// Log::debug('Sent request for installation token.'); -// -// $installationToken = $request->getInstallationToken(); -// $installationId = $request->getInstallationId(); -// $serverPublicKey = $request->getServerPublicKey(); -// -// Log::debug('Have all values from InstallationTokenRequest'); -// -// -// Preferences::setForUser($this->job->user, 'bunq_installation_token', $installationToken->toArray()); -// Preferences::setForUser($this->job->user, 'bunq_installation_id', $installationId->toArray()); -// Preferences::setForUser($this->job->user, 'bunq_server_public_key', $serverPublicKey->toArray()); -// -// Log::debug('Stored token, ID and pub key.'); -// -// return $installationToken; -// } -// -// /** -// * Get the private key from the users preferences. -// * -// * @return string -// */ -// private function getPrivateKey(): string -// { -// Log::debug('In getPrivateKey()'); -// $preference = Preferences::getForUser($this->job->user, 'bunq_private_key', null); -// if (null === $preference) { -// Log::debug('private key is null'); -// // create key pair -// $this->createKeyPair(); -// } -// $preference = Preferences::getForUser($this->job->user, 'bunq_private_key', null); -// Log::debug('Return private key for user'); -// -// return (string)$preference->data; -// } -// -// /** -// * Get a public key from the users preferences. -// * -// * @return string -// */ -// private function getPublicKey(): string -// { -// Log::debug('Now in getPublicKey()'); -// $preference = Preferences::getForUser($this->job->user, 'bunq_public_key', null); -// if (null === $preference) { -// Log::debug('public key is NULL.'); -// // create key pair -// $this->createKeyPair(); -// } -// $preference = Preferences::getForUser($this->job->user, 'bunq_public_key', null); -// Log::debug('Return public key for user'); -// -// return (string)$preference->data; -// } -// -// /** -// * Request users server remote IP. Let's assume this value will not change any time soon. -// * -// * @return string -// * -// */ -// private function getRemoteIp(): ?string -// { -// -// $preference = Preferences::getForUser($this->job->user, 'external_ip', null); -// if (null === $preference) { -// -// /** @var IPRetrievalInterface $service */ -// $service = app(IPRetrievalInterface::class); -// $serverIp = $service->getIP(); -// if (null !== $serverIp) { -// Preferences::setForUser($this->job->user, 'external_ip', $serverIp); -// } -// -// return $serverIp; -// } -// -// return $preference->data; -// } -// -// /** -// * Get the public key of the server, necessary to verify server signature. -// * -// * @return ServerPublicKey -// * -// * @throws FireflyException -// */ -// private function getServerPublicKey(): ServerPublicKey -// { -// $pref = Preferences::getForUser($this->job->user, 'bunq_server_public_key', null)->data; -// if (null === $pref) { -// throw new FireflyException('Cannot determine bunq server public key, but should have it at this point.'); -// } -// -// return new ServerPublicKey($pref); -// } -// -// /** -// * Shorthand method. -// * -// * @return string -// */ -// private function getStatus(): string -// { -// return $this->repository->getStatus($this->job); -// } -// -// /** -// * Import the transactions that were found. -// * -// * @param array $payments -// * -// * @throws FireflyException -// */ -// private function importPayments(array $payments): void -// { -// Log::debug('Going to run importPayments()'); -// $journals = new Collection; -// $config = $this->getConfig(); -// foreach ($payments as $accountId => $data) { -// Log::debug(sprintf('Now running for bunq account #%d with %d payment(s).', $accountId, \count($data['payments']))); -// /** @var Payment $payment */ -// foreach ($data['payments'] as $index => $payment) { -// Log::debug(sprintf('Now at payment #%d with ID #%d', $index, $payment->getId())); -// // store or find counter party: -// $counterParty = $payment->getCounterParty(); -// $amount = $payment->getAmount(); -// $paymentId = $payment->getId(); -// if ($this->alreadyImported($paymentId)) { -// Log::error(sprintf('Already imported bunq payment with id #%d', $paymentId)); -// -// // add three steps to keep up -// $this->addSteps(3); -// continue; -// } -// Log::debug(sprintf('Amount is %s %s', $amount->getCurrency(), $amount->getValue())); -// $expected = AccountType::EXPENSE; -// if (bccomp($amount->getValue(), '0') === 1) { -// // amount + means that its a deposit. -// $expected = AccountType::REVENUE; -// Log::debug('Will make opposing account revenue.'); -// } -// $opposing = $this->convertToAccount($counterParty, $expected); -// $account = $this->accountRepository->findNull($config['accounts-mapped'][$accountId]); -// $type = TransactionType::WITHDRAWAL; -// -// $this->addStep(); -// -// Log::debug(sprintf('Will store withdrawal between "%s" (%d) and "%s" (%d)', $account->name, $account->id, $opposing->name, $opposing->id)); -// -// // start storing stuff: -// $source = $account; -// $destination = $opposing; -// if (bccomp($amount->getValue(), '0') === 1) { -// // its a deposit: -// $source = $opposing; -// $destination = $account; -// $type = TransactionType::DEPOSIT; -// Log::debug('Will make it a deposit.'); -// } -// if ($account->accountType->type === AccountType::ASSET && $opposing->accountType->type === AccountType::ASSET) { -// $type = TransactionType::TRANSFER; -// Log::debug('Both are assets, will make transfer.'); -// } -// -// $storeData = [ -// 'user' => $this->job->user_id, -// 'type' => $type, -// 'date' => $payment->getCreated(), -// 'description' => $payment->getDescription(), -// 'piggy_bank_id' => null, -// 'piggy_bank_name' => null, -// 'bill_id' => null, -// 'bill_name' => null, -// 'tags' => [$payment->getType(), $payment->getSubType()], -// 'internal_reference' => $payment->getId(), -// 'notes' => null, -// 'bunq_payment_id' => $payment->getId(), -// 'transactions' => [ -// // single transaction: -// [ -// 'description' => null, -// 'amount' => $amount->getValue(), -// 'currency_id' => null, -// 'currency_code' => $amount->getCurrency(), -// 'foreign_amount' => null, -// 'foreign_currency_id' => null, -// 'foreign_currency_code' => null, -// 'budget_id' => null, -// 'budget_name' => null, -// 'category_id' => null, -// 'category_name' => null, -// 'source_id' => $source->id, -// 'source_name' => null, -// 'destination_id' => $destination->id, -// 'destination_name' => null, -// 'reconciled' => false, -// 'identifier' => 0, -// ], -// ], -// ]; -// $journal = $this->journalFactory->create($storeData); -// Log::debug(sprintf('Stored journal with ID #%d', $journal->id)); -// $this->addStep(); -// $journals->push($journal); -// -// } -// } -// if ($journals->count() > 0) { -// // link to tag -// /** @var TagRepositoryInterface $repository */ -// $repository = app(TagRepositoryInterface::class); -// $repository->setUser($this->job->user); -// $data = [ -// 'tag' => trans('import.import_with_key', ['key' => $this->job->key]), -// 'date' => new Carbon, -// 'description' => null, -// 'latitude' => null, -// 'longitude' => null, -// 'zoomLevel' => null, -// 'tagMode' => 'nothing', -// ]; -// $tag = $repository->store($data); -// $extended = $this->getExtendedStatus(); -// $extended['tag'] = $tag->id; -// $this->setExtendedStatus($extended); -// -// Log::debug(sprintf('Created tag #%d ("%s")', $tag->id, $tag->tag)); -// Log::debug('Looping journals...'); -// $tagId = $tag->id; -// -// foreach ($journals as $journal) { -// Log::debug(sprintf('Linking journal #%d to tag #%d...', $journal->id, $tagId)); -// DB::table('tag_transaction_journal')->insert(['transaction_journal_id' => $journal->id, 'tag_id' => $tagId]); -// $this->addStep(); -// } -// Log::info(sprintf('Linked %d journals to tag #%d ("%s")', $journals->count(), $tag->id, $tag->tag)); -// } -// -// // set status to "finished"? -// // update job: -// $this->setStatus('finished'); -// } -// -// /** -// * To install Firefly III as a new device: -// * - Send an installation token request. -// * - Use this token to send a device server request -// * - Store the installation token -// * - Use the installation token each time we need a session. -// * -// * @throws FireflyException -// */ -// private function registerDevice(): DeviceServerId -// { -// Log::debug('Now in registerDevice()'); -// $deviceServerId = Preferences::getForUser($this->job->user, 'bunq_device_server_id', null); -// $serverIp = $this->getRemoteIp(); -// if (null !== $deviceServerId) { -// Log::debug('Already have device server ID.'); -// -// return new DeviceServerId($deviceServerId->data); -// } -// -// Log::debug('Device server ID is null, we have to find an existing one or register a new one.'); -// $installationToken = $this->getInstallationToken(); -// $serverPublicKey = $this->getServerPublicKey(); -// $apiKey = Preferences::getForUser($this->job->user, 'bunq_api_key', ''); -// $this->addStep(); -// -// // try get the current from a list: -// $deviceServerId = $this->getExistingDevice(); -// $this->addStep(); -// if (null !== $deviceServerId) { -// Log::debug('Found device server ID in existing devices list.'); -// -// return $deviceServerId; -// } -// -// Log::debug('Going to create new DeviceServerRequest() because nothing found in existing list.'); -// $request = new DeviceServerRequest; -// $request->setPrivateKey($this->getPrivateKey()); -// $request->setDescription('Firefly III v' . config('firefly.version') . ' for ' . $this->job->user->email); -// $request->setSecret($apiKey->data); -// $request->setPermittedIps([$serverIp]); -// $request->setInstallationToken($installationToken); -// $request->setServerPublicKey($serverPublicKey); -// $deviceServerId = null; -// // try to register device: -// try { -// $request->call(); -// $deviceServerId = $request->getDeviceServerId(); -// } catch (FireflyException $e) { -// Log::error($e->getMessage()); -// // we really have to quit at this point :( -// throw new FireflyException($e->getMessage()); -// } -// if (null === $deviceServerId) { -// throw new FireflyException('Was not able to register server with bunq. Please see the log files.'); -// } -// -// Preferences::setForUser($this->job->user, 'bunq_device_server_id', $deviceServerId->toArray()); -// Log::debug(sprintf('Server ID: %s', json_encode($deviceServerId))); -// -// return $deviceServerId; -// } -// -// /** -// * Will download the transactions for each account that is selected to be imported from. -// * Will of course also update the number of steps and what-not. -// * -// * @throws FireflyException -// */ -// private function runStageHaveAccountMapping(): void -// { -// $config = $this->getConfig(); -// $user = new UserPerson($config['user_person']); -// $mapping = $config['accounts-mapped']; -// $token = new SessionToken($config['session_token']); -// $count = 0; -// $all = []; -// if (0 === $user->getId()) { -// $user = new UserCompany($config['user_company']); -// Log::debug(sprintf('Will try to get transactions for company #%d', $user->getId())); -// } -// -// $this->addTotalSteps(\count($config['accounts']) * 2); -// -// foreach ($config['accounts'] as $accountData) { -// $this->addStep(); -// $account = new MonetaryAccountBank($accountData); -// $importId = $account->getId(); -// if (isset($mapping[$importId])) { -// Log::debug(sprintf('Will grab payments for account %s', $account->getDescription())); -// $request = new ListPaymentRequest(); -// $request->setPrivateKey($this->getPrivateKey()); -// $request->setServerPublicKey($this->getServerPublicKey()); -// $request->setSessionToken($token); -// $request->setUserId($user->getId()); -// $request->setAccount($account); -// $request->call(); -// $payments = $request->getPayments(); -// -// // store in array -// $all[$account->getId()] = [ -// 'account' => $account, -// 'import_id' => $importId, -// 'payments' => $payments, -// ]; -// $count += \count($payments); -// } -// Log::debug(sprintf('Total number of payments: %d', $count)); -// $this->addStep(); -// // add steps for import: -// $this->addTotalSteps($count * 3); -// $this->importPayments($all); -// } -// -// // update job to be complete, I think? -// } -// -// /** -// * @throws FireflyException -// */ -// private function runStageLoggedIn(): void -// { -// $this->addStep(); -// // grab new session token: -// $config = $this->getConfig(); -// $token = new SessionToken($config['session_token']); -// $user = new UserPerson($config['user_person']); -// if (0 === $user->getId()) { -// $user = new UserCompany($config['user_company']); -// } -// -// // list accounts request -// $request = new ListMonetaryAccountRequest(); -// $request->setServerPublicKey($this->getServerPublicKey()); -// $request->setPrivateKey($this->getPrivateKey()); -// $request->setUserId($user->getId()); -// $request->setSessionToken($token); -// $request->call(); -// $accounts = $request->getMonetaryAccounts(); -// $arr = []; -// Log::debug(sprintf('Get monetary accounts, found %d accounts.', $accounts->count())); -// $this->addStep(); -// -// /** @var MonetaryAccountBank $account */ -// foreach ($accounts as $account) { -// $arr[] = $account->toArray(); -// } -// -// $config = $this->getConfig(); -// $config['accounts'] = $arr; -// $config['stage'] = 'have-accounts'; -// $this->setConfig($config); -// -// // once the accounts are stored, go to configuring stage: -// // update job, set status to "configuring". -// $this->setStatus('configuring'); -// $this->addStep(); -// } -// -// /** -// * Shorthand. -// * -// * @param array $config -// */ -// private function setConfig(array $config): void -// { -// $this->repository->setConfiguration($this->job, $config); -// } -// -// /** -// * Shorthand method. -// * -// * @param array $extended -// */ -// private function setExtendedStatus(array $extended): void -// { -// $this->repository->setExtendedStatus($this->job, $extended); -// } -// -// /** -// * Shorthand. -// * -// * @param string $status -// */ -// private function setStatus(string $status): void -// { -// $this->repository->setStatus($this->job, $status); -// } + /** @var ImportJob */ + private $importJob; + + /** @var ImportJobRepositoryInterface */ + private $repository; + /** * At the end of each run(), the import routine must set the job to the expected status. * @@ -923,8 +51,41 @@ class BunqRoutine implements RoutineInterface */ public function run(): void { - // TODO: Implement run() method. - throw new NotImplementedException; + 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, true)) { + switch ($this->importJob->stage) { + default: + throw new FireflyException(sprintf('SpectreRoutine cannot handle stage "%s".', $this->importJob->stage)); // @codeCoverageIgnore + case 'new': + // list all of the users accounts. + $this->repository->setStatus($this->importJob, 'running'); + /** @var StageNewHandler $handler */ + $handler = app(StageNewHandler::class); + $handler->setImportJob($this->importJob); + $handler->run(); + + // make user choose accounts to import from. + $this->repository->setStage($this->importJob, 'choose-accounts'); + $this->repository->setStatus($this->importJob, 'need_job_config'); + break; + case 'go-for-import': + // list all of the users accounts. + $this->repository->setStatus($this->importJob, 'running'); + + /** @var StageImportDataHandler $handler */ + $handler = app(StageImportDataHandler::class); + $handler->setImportJob($this->importJob); + $handler->run(); + $transactions = $handler->getTransactions(); + + $this->repository->setTransactions($this->importJob, $transactions); + $this->repository->setStatus($this->importJob, 'provider_finished'); + $this->repository->setStage($this->importJob, 'final'); + + break; + } + } } @@ -935,7 +96,9 @@ class BunqRoutine implements RoutineInterface */ public function setImportJob(ImportJob $importJob): void { - // TODO: Implement setImportJob() method. - throw new NotImplementedException; + $this->importJob = $importJob; + $this->repository = app(ImportJobRepositoryInterface::class); + $this->repository->setUser($importJob->user); } + } diff --git a/app/Models/ImportJob.php b/app/Models/ImportJob.php index 508168c16d..7a9759f263 100644 --- a/app/Models/ImportJob.php +++ b/app/Models/ImportJob.php @@ -38,6 +38,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; * @property string $key * @property string $provider * @property string $file_type + * @property int $tag_id + * @property Tag $tag */ class ImportJob extends Model { diff --git a/app/Models/Tag.php b/app/Models/Tag.php index 11a9d8fadd..4a5f176e73 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -25,12 +25,14 @@ namespace FireflyIII\Models; use Crypt; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Support\Collection; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use FireflyIII\User; use FireflyIII\Models\TransactionJournal; /** * Class Tag. + * @property Collection $transactionJournals */ class Tag extends Model { diff --git a/app/Services/Bunq/Id/BunqId.php b/app/Services/Bunq/Id/BunqId.php deleted file mode 100644 index e2d7338c54..0000000000 --- a/app/Services/Bunq/Id/BunqId.php +++ /dev/null @@ -1,73 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Id; - -/** - * @codeCoverageIgnore - * @deprecated - * Class BunqId. - */ -class BunqId -{ - /** @var int */ - private $id = 0; - - /** - * BunqId constructor. - * - * @param null $data - */ - public function __construct($data = null) - { - if (null !== $data) { - $this->id = $data['id']; - } - } - - /** - * @return int - */ - public function getId(): int - { - return $this->id; - } - - /** - * @param int $id - */ - public function setId(int $id): void - { - $this->id = $id; - } - - /** - * @return array - */ - public function toArray(): array - { - return [ - 'id' => $this->id, - ]; - } -} diff --git a/app/Services/Bunq/Id/DeviceServerId.php b/app/Services/Bunq/Id/DeviceServerId.php deleted file mode 100644 index fec499bb85..0000000000 --- a/app/Services/Bunq/Id/DeviceServerId.php +++ /dev/null @@ -1,33 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Id; - -/** - * @codeCoverageIgnore - * @deprecated - * Class DeviceServerId. - */ -class DeviceServerId extends BunqId -{ -} diff --git a/app/Services/Bunq/Id/DeviceSessionId.php b/app/Services/Bunq/Id/DeviceSessionId.php deleted file mode 100644 index 54870850c5..0000000000 --- a/app/Services/Bunq/Id/DeviceSessionId.php +++ /dev/null @@ -1,32 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Id; - -/** - * @codeCoverageIgnore - * @deprecated - * Class DeviceSessionId. - */ -class DeviceSessionId extends BunqId -{ -} diff --git a/app/Services/Bunq/Id/InstallationId.php b/app/Services/Bunq/Id/InstallationId.php deleted file mode 100644 index 26a7b209f3..0000000000 --- a/app/Services/Bunq/Id/InstallationId.php +++ /dev/null @@ -1,32 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Id; - -/** - * @codeCoverageIgnore - * @deprecated - * Class InstallationId. - */ -class InstallationId extends BunqId -{ -} diff --git a/app/Services/Bunq/Object/Alias.php b/app/Services/Bunq/Object/Alias.php deleted file mode 100644 index 4dcfd5a0c6..0000000000 --- a/app/Services/Bunq/Object/Alias.php +++ /dev/null @@ -1,86 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -/** - * @codeCoverageIgnore - * @deprecated - * Class Alias. - */ -class Alias extends BunqObject -{ - /** @var string */ - private $name; - /** @var string */ - private $type; - /** @var string */ - private $value; - - /** - * Alias constructor. - * - * @param array $data - */ - public function __construct(array $data) - { - $this->type = $data['type']; - $this->name = $data['name']; - $this->value = $data['value']; - } - - /** - * @return string - */ - public function getName(): string - { - return $this->name; - } - - /** - * @return string - */ - public function getType(): string - { - return $this->type; - } - - /** - * @return string - */ - public function getValue(): string - { - return $this->value; - } - - /** - * @return array - */ - public function toArray(): array - { - return [ - 'type' => $this->type, - 'name' => $this->name, - 'value' => $this->value, - ]; - } -} diff --git a/app/Services/Bunq/Object/Avatar.php b/app/Services/Bunq/Object/Avatar.php deleted file mode 100644 index 96e4cf50e5..0000000000 --- a/app/Services/Bunq/Object/Avatar.php +++ /dev/null @@ -1,62 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -/** - * @deprecated - * @codeCoverageIgnore - * Class Avatar. - */ -class Avatar extends BunqObject -{ - /** @var string */ - private $anchorUuid; - /** @var Image */ - private $image; - /** @var string */ - private $uuid; - - /** - * Avatar constructor. - * - * @param array $data - */ - public function __construct(array $data) - { - $this->uuid = $data['uuid']; - $this->anchorUuid = $data['anchor_uuid']; - $this->image = new Image($data['image']); - } - - /** - * @return array - */ - public function toArray(): array - { - return [ - 'uuid' => $this->uuid, - 'anchor_uuid' => $this->anchorUuid, - 'image' => $this->image->toArray(), - ]; - } -} diff --git a/app/Services/Bunq/Object/BunqObject.php b/app/Services/Bunq/Object/BunqObject.php deleted file mode 100644 index 364fed89cd..0000000000 --- a/app/Services/Bunq/Object/BunqObject.php +++ /dev/null @@ -1,38 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -/** - * @deprecated - * @codeCoverageIgnore - * Class BunqObject. - */ -abstract class BunqObject -{ - /** - * Convert this object to array. - * - * @return array - */ - abstract public function toArray(): array; -} diff --git a/app/Services/Bunq/Object/DeviceServer.php b/app/Services/Bunq/Object/DeviceServer.php deleted file mode 100644 index 064e38dcaf..0000000000 --- a/app/Services/Bunq/Object/DeviceServer.php +++ /dev/null @@ -1,92 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -use Carbon\Carbon; -use FireflyIII\Services\Bunq\Id\DeviceServerId; - -use FireflyIII\Exceptions\FireflyException; - -/** - * @deprecated - * @codeCoverageIgnore - * Class DeviceServer - */ -class DeviceServer extends BunqObject -{ - /** @var Carbon */ - private $created; - /** @var string */ - private $description; - /** @var DeviceServerId */ - private $id; - /** @var string */ - private $ip; - /** @var string */ - private $status; - /** @var Carbon */ - private $updated; - - /** - * DeviceServer constructor. - * - * @param array $data - * - */ - public function __construct(array $data) - { - $id = new DeviceServerId(); - $id->setId($data['id']); - $this->id = $id; - $this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['created']); - $this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['updated']); - $this->ip = $data['ip']; - $this->description = $data['description']; - $this->status = $data['status']; - } - - /** - * @return DeviceServerId - */ - public function getId(): DeviceServerId - { - return $this->id; - } - - /** - * @return string - */ - public function getIp(): string - { - return $this->ip; - } - - /** - * @return array - * @throws FireflyException - */ - public function toArray(): array - { - throw new FireflyException(sprintf('Cannot convert %s to array.', \get_class($this))); - } -} diff --git a/app/Services/Bunq/Object/Image.php b/app/Services/Bunq/Object/Image.php deleted file mode 100644 index 79a73bdbe0..0000000000 --- a/app/Services/Bunq/Object/Image.php +++ /dev/null @@ -1,68 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -/** - * @deprecated - * @codeCoverageIgnore - * Class Image - */ -class Image extends BunqObject -{ - /** @var string */ - private $attachmentPublicUuid; - /** @var string */ - private $contentType; - /** @var int */ - private $height; - /** @var int */ - private $width; - - /** - * Image constructor. - * - * @param array $data - */ - public function __construct(array $data) - { - $this->attachmentPublicUuid = $data['attachment_public_uuid'] ?? null; - $this->height = $data['height'] ?? null; - $this->width = $data['width'] ?? null; - $this->contentType = $data['content_type'] ?? null; - } - - /** - * @return array - */ - public function toArray(): array - { - return [ - 'attachment_public_uuid' => $this->attachmentPublicUuid, - 'height' => $this->height, - 'width' => $this->width, - 'content_type' => $this->contentType, - ]; - } - -} diff --git a/app/Services/Bunq/Object/LabelMonetaryAccount.php b/app/Services/Bunq/Object/LabelMonetaryAccount.php deleted file mode 100644 index 62fddca392..0000000000 --- a/app/Services/Bunq/Object/LabelMonetaryAccount.php +++ /dev/null @@ -1,85 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -use FireflyIII\Exceptions\FireflyException; - -/** - * @deprecated - * @codeCoverageIgnore - * Class LabelMonetaryAccount - */ -class LabelMonetaryAccount extends BunqObject -{ - /** @var Avatar */ - private $avatar; - /** @var string */ - private $country; - /** @var string */ - private $iban; - /** @var bool */ - private $isLight; - /** @var LabelUser */ - private $labelUser; - - /** - * LabelMonetaryAccount constructor. - * - * @param array $data - */ - public function __construct(array $data) - { - $this->iban = $data['iban']; - $this->isLight = $data['is_light']; - $this->avatar = isset($data['avatar']) ? new Avatar($data['avatar']) : null; - $this->labelUser = new LabelUser($data['label_user']); - $this->country = $data['country']; - } - - /** - * @return string|null - */ - public function getIban(): ?string - { - return $this->iban; - } - - /** - * @return LabelUser - */ - public function getLabelUser(): LabelUser - { - return $this->labelUser; - } - - /** - * @return array - * @throws FireflyException - */ - public function toArray(): array - { - throw new FireflyException(sprintf('Cannot convert %s to array.', \get_class($this))); - } - -} diff --git a/app/Services/Bunq/Object/LabelUser.php b/app/Services/Bunq/Object/LabelUser.php deleted file mode 100644 index f01a142ac4..0000000000 --- a/app/Services/Bunq/Object/LabelUser.php +++ /dev/null @@ -1,91 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -use FireflyIII\Exceptions\FireflyException; -/** - * @deprecated - * @codeCoverageIgnore - * Class LabelUser - */ -class LabelUser extends BunqObject -{ - /** @var Avatar */ - private $avatar; - /** @var string */ - private $country; - /** @var string */ - private $displayName; - /** @var string */ - private $publicNickName; - /** @var string */ - private $uuid; - - /** - * LabelUser constructor. - * - * @param array $data - */ - public function __construct(array $data) - { - $this->uuid = $data['uuid']; - $this->displayName = $data['display_name']; - $this->country = $data['country']; - $this->publicNickName = $data['public_nick_name']; - $this->avatar = isset($data['avatar']) ? new Avatar($data['avatar']) : null; - } - - /** - * @return Avatar - */ - public function getAvatar(): Avatar - { - return $this->avatar; - } - - /** - * @return string - */ - public function getDisplayName(): string - { - return $this->displayName; - } - - /** - * @return string - */ - public function getPublicNickName(): string - { - return $this->publicNickName; - } - - /** - * @return array - * @throws FireflyException - */ - public function toArray(): array - { - throw new FireflyException(sprintf('Cannot convert %s to array.', \get_class($this))); - } -} diff --git a/app/Services/Bunq/Object/MonetaryAccountBank.php b/app/Services/Bunq/Object/MonetaryAccountBank.php deleted file mode 100644 index 0bd7e50f7d..0000000000 --- a/app/Services/Bunq/Object/MonetaryAccountBank.php +++ /dev/null @@ -1,200 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -use Carbon\Carbon; - -/** - * @deprecated - * @codeCoverageIgnore - * Class MonetaryAccountBank. - */ -class MonetaryAccountBank extends BunqObject -{ - /** @var array */ - private $aliases = []; - /** @var Avatar */ - private $avatar; - /** @var Amount */ - private $balance; - /** @var Carbon */ - private $created; - /** @var string */ - private $currency; - /** @var Amount */ - private $dailyLimit; - /** @var Amount */ - private $dailySpent; - /** @var string */ - private $description; - /** @var int */ - private $id; - /** @var MonetaryAccountProfile */ - private $monetaryAccountProfile; - /** @var array */ - private $notificationFilters = []; - /** @var Amount */ - private $overdraftLimit; - /** @var string */ - private $publicUuid; - /** @var string */ - private $reason; - /** @var string */ - private $reasonDescription; - /** @var MonetaryAccountSetting */ - private $setting; - /** @var string */ - private $status; - /** @var string */ - private $subStatus; - /** @var Carbon */ - private $updated; - /** @var int */ - private $userId; - - /** - * MonetaryAccountBank constructor. - * - * @param array $data - * - */ - public function __construct(array $data) - { - $this->id = $data['id']; - $this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['created']); - $this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['updated']); - $this->balance = new Amount($data['balance']); - $this->currency = $data['currency']; - $this->dailyLimit = new Amount($data['daily_limit']); - $this->dailySpent = new Amount($data['daily_spent']); - $this->description = $data['description']; - $this->publicUuid = $data['public_uuid']; - $this->status = $data['status']; - $this->subStatus = $data['sub_status']; - $this->userId = $data['user_id']; - $this->monetaryAccountProfile = new MonetaryAccountProfile($data['monetary_account_profile']); - $this->setting = new MonetaryAccountSetting($data['setting']); - $this->overdraftLimit = new Amount($data['overdraft_limit']); - $this->avatar = isset($data['avatar']) ? new Avatar($data['avatar']) : null; - $this->reason = $data['reason'] ?? ''; - $this->reasonDescription = $data['reason_description'] ?? ''; - - // create aliases: - foreach ($data['alias'] as $alias) { - $this->aliases[] = new Alias($alias); - } - /** @var array $filter */ - foreach ($data['notification_filters'] as $filter) { - $this->notificationFilters[] = new NotificationFilter($filter); - } - } - - /** - * @return array - */ - public function getAliases(): array - { - return $this->aliases; - } - - /** - * @return Amount - */ - public function getBalance(): Amount - { - return $this->balance; - } - - /** - * @return string - */ - public function getCurrency(): string - { - return $this->currency; - } - - /** - * @return string - */ - public function getDescription(): string - { - return $this->description; - } - - /** - * @return int - */ - public function getId(): int - { - return $this->id; - } - - /** - * @return MonetaryAccountSetting - */ - public function getSetting(): MonetaryAccountSetting - { - return $this->setting; - } - - /** - * @return array - */ - public function toArray(): array - { - $data = [ - 'id' => $this->id, - 'created' => $this->created->format('Y-m-d H:i:s.u'), - 'updated' => $this->updated->format('Y-m-d H:i:s.u'), - 'balance' => $this->balance->toArray(), - 'currency' => $this->currency, - 'daily_limit' => $this->dailyLimit->toArray(), - 'daily_spent' => $this->dailySpent->toArray(), - 'description' => $this->description, - 'public_uuid' => $this->publicUuid, - 'status' => $this->status, - 'sub_status' => $this->subStatus, - 'user_id' => $this->userId, - 'monetary_account_profile' => $this->monetaryAccountProfile->toArray(), - 'setting' => $this->setting->toArray(), - 'overdraft_limit' => $this->overdraftLimit->toArray(), - 'avatar' => null === $this->avatar ? null : $this->avatar->toArray(), - 'reason' => $this->reason, - 'reason_description' => $this->reasonDescription, - 'alias' => [], - 'notification_filters' => [], - ]; - - /** @var Alias $alias */ - foreach ($this->aliases as $alias) { - $data['alias'][] = $alias->toArray(); - } - - /** @var NotificationFilter $filter */ - foreach ($this->notificationFilters as $filter) { - $data['notification_filters'][] = $filter->toArray(); - } - - return $data; - } -} diff --git a/app/Services/Bunq/Object/MonetaryAccountProfile.php b/app/Services/Bunq/Object/MonetaryAccountProfile.php deleted file mode 100644 index 294742623c..0000000000 --- a/app/Services/Bunq/Object/MonetaryAccountProfile.php +++ /dev/null @@ -1,69 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -/** - * @deprecated - * @codeCoverageIgnore - * Class MonetaryAccountProfile. - */ -class MonetaryAccountProfile extends BunqObject -{ - /** @var string */ - private $profileActionRequired; - /** @var Amount */ - private $profileAmountRequired; - /** - * @var null - */ - private $profileDrain; - /** - * @var null - */ - private $profileFill; - - /** - * MonetaryAccountProfile constructor. - * - * @param array $data - */ - public function __construct(array $data) - { - $this->profileDrain = null; - $this->profileFill = null; - $this->profileActionRequired = $data['profile_action_required']; - $this->profileAmountRequired = new Amount($data['profile_amount_required']); - - } - - /** - * @return array - */ - public function toArray(): array - { - return [ - 'profile_action_required' => $this->profileActionRequired, - 'profile_amount_required' => $this->profileAmountRequired->toArray(), - ]; - } -} diff --git a/app/Services/Bunq/Object/MonetaryAccountSetting.php b/app/Services/Bunq/Object/MonetaryAccountSetting.php deleted file mode 100644 index 38cb95fbd9..0000000000 --- a/app/Services/Bunq/Object/MonetaryAccountSetting.php +++ /dev/null @@ -1,87 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -/** - * @deprecated - * @codeCoverageIgnore - * Class MonetaryAccountSetting. - */ -class MonetaryAccountSetting extends BunqObject -{ - /** @var string */ - private $color; - /** @var string */ - private $defaultAvatarStatus; - /** @var string */ - private $restrictionChat; - - /** - * MonetaryAccountSetting constructor. - * - * @param array $data - */ - public function __construct(array $data) - { - $this->color = $data['color']; - $this->defaultAvatarStatus = $data['default_avatar_status']; - $this->restrictionChat = $data['restriction_chat']; - - } - - /** - * @return string - */ - public function getColor(): string - { - return $this->color; - } - - /** - * @return string - */ - public function getDefaultAvatarStatus(): string - { - return $this->defaultAvatarStatus; - } - - /** - * @return string - */ - public function getRestrictionChat(): string - { - return $this->restrictionChat; - } - - /** - * @return array - */ - public function toArray(): array - { - return [ - 'color' => $this->color, - 'default_avatar_status' => $this->defaultAvatarStatus, - 'restriction_chat' => $this->restrictionChat, - ]; - } -} diff --git a/app/Services/Bunq/Object/NotificationFilter.php b/app/Services/Bunq/Object/NotificationFilter.php deleted file mode 100644 index 360de185fd..0000000000 --- a/app/Services/Bunq/Object/NotificationFilter.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -/** - * @deprecated - * @codeCoverageIgnore - * Class NotificationFilter. - */ -class NotificationFilter extends BunqObject -{ - /** - * NotificationFilter constructor. - * - * @param array $data - */ - public function __construct(array $data) - { - - } - - /** - * @return array - */ - public function toArray(): array - { - return []; - } -} diff --git a/app/Services/Bunq/Object/Payment.php b/app/Services/Bunq/Object/Payment.php deleted file mode 100644 index 01df0eb991..0000000000 --- a/app/Services/Bunq/Object/Payment.php +++ /dev/null @@ -1,147 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -use Carbon\Carbon; -use FireflyIII\Exceptions\FireflyException; - -/** - * @deprecated - * @codeCoverageIgnore - * Class Payment - */ -class Payment extends BunqObject -{ - /** @var LabelMonetaryAccount */ - private $alias; - /** @var Amount */ - private $amount; - /** @var array */ - private $attachments = []; - /** @var LabelMonetaryAccount */ - private $counterParty; - /** @var Carbon */ - private $created; - /** @var string */ - private $description; - /** @var int */ - private $id; - /** @var string */ - private $merchantReference; - /** @var int */ - private $monetaryAccountId; - /** @var string */ - private $subType; - /** @var string */ - private $type; - /** @var Carbon */ - private $updated; - - /** - * Payment constructor. - * - * @param array $data - * - */ - public function __construct(array $data) - { - $this->id = $data['id']; - $this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['created']); - $this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['updated']); - $this->monetaryAccountId = (int)$data['monetary_account_id']; - $this->amount = new Amount($data['amount']); - $this->description = $data['description']; - $this->type = $data['type']; - $this->merchantReference = $data['merchant_reference']; - $this->alias = new LabelMonetaryAccount($data['alias']); - $this->counterParty = new LabelMonetaryAccount($data['counterparty_alias']); - $this->subType = $data['sub_type']; - } - - /** - * @return Amount - */ - public function getAmount(): Amount - { - return $this->amount; - } - - /** - * @return LabelMonetaryAccount|null - */ - public function getCounterParty(): ?LabelMonetaryAccount - { - return $this->counterParty; - } - - /** - * @return Carbon - */ - public function getCreated(): Carbon - { - return $this->created; - } - - /** - * @return string - */ - public function getDescription(): string - { - return $this->description; - } - - /** - * @return int - */ - public function getId(): int - { - return $this->id; - } - - /** - * @return string - */ - public function getSubType(): string - { - return $this->subType; - } - - /** - * @return string - */ - public function getType(): string - { - return $this->type; - } - - /** - * @return array - * @throws FireflyException - */ - public function toArray(): array - { - throw new FireflyException(sprintf('Cannot convert %s to array.', \get_class($this))); - } - -} diff --git a/app/Services/Bunq/Object/ServerPublicKey.php b/app/Services/Bunq/Object/ServerPublicKey.php deleted file mode 100644 index c1665400a3..0000000000 --- a/app/Services/Bunq/Object/ServerPublicKey.php +++ /dev/null @@ -1,70 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -/** - * @deprecated - * @codeCoverageIgnore - * Class ServerPublicKey. - */ -class ServerPublicKey extends BunqObject -{ - /** @var string */ - private $publicKey; - - /** - * ServerPublicKey constructor. - * - * @param array $response - */ - public function __construct(array $response) - { - $this->publicKey = $response['server_public_key']; - } - - /** - * @return string - */ - public function getPublicKey(): string - { - return $this->publicKey; - } - - /** - * @param string $publicKey - */ - public function setPublicKey(string $publicKey) - { - $this->publicKey = $publicKey; - } - - /** - * @return array - */ - public function toArray(): array - { - return [ - 'server_public_key' => $this->publicKey, - ]; - } -} diff --git a/app/Services/Bunq/Object/UserCompany.php b/app/Services/Bunq/Object/UserCompany.php deleted file mode 100644 index 25dcb6c9ab..0000000000 --- a/app/Services/Bunq/Object/UserCompany.php +++ /dev/null @@ -1,190 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -use Carbon\Carbon; - -/** - * @deprecated - * @codeCoverageIgnore - * Class UserCompany. - */ -class UserCompany extends BunqObject -{ - /** - * @var - */ - private $addressMain; - /** - * @var - */ - private $addressPostal; - /** @var array */ - private $aliases = []; - /** - * @var - */ - private $avatar; - /** @var string */ - private $cocNumber; - /** @var string */ - private $counterBankIban; - /** @var Carbon */ - private $created; - /** - * @var - */ - private $dailyLimit; - /** - * @var - */ - private $directorAlias; - /** @var string */ - private $displayName; - /** @var int */ - private $id; - /** @var string */ - private $language; - /** @var string */ - private $name; - /** @var array */ - private $notificationFilters = []; - /** @var string */ - private $publicNickName; - /** @var string */ - private $publicUuid; - /** @var string */ - private $region; - /** @var string */ - private $sectorOfIndustry; - /** @var int */ - private $sessionTimeout; - /** @var string */ - private $status; - /** @var string */ - private $subStatus; - /** @var string */ - private $typeOfBusinessEntity; - /** @var array */ - private $ubos = []; - /** @var Carbon */ - private $updated; - /** @var int */ - private $versionTos; - - /** - * UserCompany constructor. - * - * @param array $data - * - */ - public function __construct(array $data) - { - if (\count($data) === 0 || (isset($data['id']) && (int)$data['id'] === 0)) { - $this->id = 0; - $this->created = new Carbon; - $this->updated = new Carbon; - - return; - } - $this->id = (int)$data['id']; - $this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['created']); - $this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['updated']); - $this->status = $data['status']; - $this->subStatus = $data['sub_status']; - $this->publicUuid = $data['public_uuid']; - $this->displayName = $data['display_name']; - $this->publicNickName = $data['public_nick_name']; - $this->language = $data['language']; - $this->region = $data['region']; - $this->sessionTimeout = (int)$data['session_timeout']; - $this->versionTos = (int)$data['version_terms_of_service']; - $this->cocNumber = $data['chamber_of_commerce_number']; - $this->typeOfBusinessEntity = $data['type_of_business_entity'] ?? ''; - $this->sectorOfIndustry = $data['sector_of_industry'] ?? ''; - $this->counterBankIban = $data['counter_bank_iban']; - $this->name = $data['name']; - - // TODO alias - // TODO avatar - // TODO daily_limit_without_confirmation_login - // TODO notification_filters - // TODO address_main - // TODO address_postal - // TODO director_alias - // TODO ubo - // TODO customer - // TODO customer_limit - // TODO billing_contract - // TODO pack_membership - } - - /** - * @return int - */ - public function getId(): int - { - return $this->id; - } - - /** - * @return array - */ - public function toArray(): array - { - $data = [ - 'id' => $this->id, - 'created' => $this->created->format('Y-m-d H:i:s.u'), - 'updated' => $this->updated->format('Y-m-d H:i:s.u'), - 'status' => $this->status, - 'sub_status' => $this->subStatus, - 'public_uuid' => $this->publicUuid, - 'display_name' => $this->displayName, - 'public_nick_name' => $this->publicNickName, - 'language' => $this->language, - 'region' => $this->region, - 'session_timeout' => $this->sessionTimeout, - 'version_terms_of_service' => $this->versionTos, - 'chamber_of_commerce_number' => $this->cocNumber, - 'type_of_business_entity' => $this->typeOfBusinessEntity, - 'sector_of_industry' => $this->sectorOfIndustry, - 'counter_bank_iban' => $this->counterBankIban, - 'name' => $this->name, - ]; - - // TODO alias - // TODO avatar - // TODO daily_limit_without_confirmation_login - // TODO notification_filters - // TODO address_main - // TODO address_postal - // TODO director_alias - // TODO ubo - // TODO customer - // TODO customer_limit - // TODO billing_contract - // TODO pack_membership - - return $data; - } -} diff --git a/app/Services/Bunq/Object/UserLight.php b/app/Services/Bunq/Object/UserLight.php deleted file mode 100644 index 521fc69a66..0000000000 --- a/app/Services/Bunq/Object/UserLight.php +++ /dev/null @@ -1,89 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -use Carbon\Carbon; -use FireflyIII\Exceptions\FireflyException; -/** - * @deprecated - * @codeCoverageIgnore - * Class UserLight. - */ -class UserLight extends BunqObject -{ - /** @var array */ - private $aliases = []; - /** @var Carbon */ - private $created; - /** @var string */ - private $displayName; - /** @var string */ - private $firstName; - /** @var int */ - private $id; - /** @var string */ - private $lastName; - /** @var string */ - private $legalName; - /** @var string */ - private $middleName; - /** @var string */ - private $publicNickName; - /** @var string */ - private $publicUuid; - /** @var Carbon */ - private $updated; - - /** - * UserLight constructor. - * - * @param array $data - * - */ - public function __construct(array $data) - { - if (0 === \count($data)) { - return; - } - $this->id = (int)$data['id']; - $this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['created']); - $this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['updated']); - $this->publicUuid = $data['public_uuid']; - $this->displayName = $data['display_name']; - $this->publicNickName = $data['public_nick_name']; - $this->firstName = $data['first_name']; - $this->middleName = $data['middle_name']; - $this->lastName = $data['last_name']; - $this->legalName = $data['legal_name']; - // aliases - } - - /** - * @return array - * @throws FireflyException - */ - public function toArray(): array - { - throw new FireflyException(sprintf('Cannot convert %s to array.', \get_class($this))); - } -} diff --git a/app/Services/Bunq/Object/UserPerson.php b/app/Services/Bunq/Object/UserPerson.php deleted file mode 100644 index ec2bf6c61c..0000000000 --- a/app/Services/Bunq/Object/UserPerson.php +++ /dev/null @@ -1,212 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Object; - -use Carbon\Carbon; - -/** - * @deprecated - * @codeCoverageIgnore - * Class UserPerson. - */ -class UserPerson extends BunqObject -{ - /** - * @var - */ - private $addressMain; - /** - * @var - */ - private $addressPostal; - /** @var array */ - private $aliases = []; - /** - * @var - */ - private $avatar; - /** @var array */ - private $billingContracts = []; - /** @var string */ - private $countryOfBirth; - /** @var Carbon */ - private $created; - /** - * @var - */ - private $customer; - /** - * @var - */ - private $customerLimit; - /** - * @var - */ - private $dailyLimit; - /** @var Carbon */ - private $dateOfBirth; - /** @var string */ - private $displayName; - /** @var string */ - private $documentCountry; - /** @var string */ - private $documentNumber; - /** @var string */ - private $documentType; - /** @var string */ - private $firstName; - /** @var string */ - private $gender; - /** @var int */ - private $id; - /** @var string */ - private $language; - /** @var string */ - private $lastName; - /** @var string */ - private $legalName; - /** @var string */ - private $middleName; - /** @var string */ - private $nationality; - /** @var array */ - private $notificationFilters = []; - /** @var string */ - private $placeOfBirth; - /** @var string */ - private $publicNickName; - /** @var string */ - private $publicUuid; - /** - * @var mixed - */ - private $region; - /** @var int */ - private $sessionTimeout; - /** @var string */ - private $status; - /** @var string */ - private $subStatus; - /** @var string */ - private $taxResident; - /** @var Carbon */ - private $updated; - /** @var int */ - private $versionTos; - - /** - * UserPerson constructor. - * - * @param array $data - * - */ - public function __construct(array $data) - { - if (0 === \count($data)) { - $this->created = new Carbon; - $this->updated = new Carbon; - $this->dateOfBirth = new Carbon; - - return; - } - - $this->id = (int)$data['id']; - $this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['created']); - $this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['updated']); - $this->status = $data['status']; - $this->subStatus = $data['sub_status']; - $this->publicUuid = $data['public_uuid']; - $this->displayName = $data['display_name']; - $this->publicNickName = $data['public_nick_name']; - $this->language = $data['language']; - $this->region = $data['region']; - $this->sessionTimeout = (int)$data['session_timeout']; - $this->firstName = $data['first_name']; - $this->middleName = $data['middle_name']; - $this->lastName = $data['last_name']; - $this->legalName = $data['legal_name']; - $this->taxResident = $data['tax_resident']; - $this->dateOfBirth = Carbon::createFromFormat('Y-m-d', $data['date_of_birth']); - $this->placeOfBirth = $data['place_of_birth']; - $this->countryOfBirth = $data['country_of_birth']; - $this->nationality = $data['nationality']; - $this->gender = $data['gender']; - $this->versionTos = (int)$data['version_terms_of_service']; - $this->documentNumber = $data['document_number']; - $this->documentType = $data['document_type']; - $this->documentCountry = $data['document_country_of_issuance']; - - // TODO create aliases - // TODO create avatar - // TODO create daily limit - // TODO create notification filters - // TODO create address main, postal - // TODO document front, back attachment - // TODO customer, customer_limit - // TODO billing contracts - } - - /** - * @return int - */ - public function getId(): int - { - return $this->id; - } - - /** - * @return array - */ - public function toArray(): array - { - $data = [ - 'id' => $this->id, - 'created' => $this->created->format('Y-m-d H:i:s.u'), - 'updated' => $this->updated->format('Y-m-d H:i:s.u'), - 'status' => $this->status, - 'sub_status' => $this->subStatus, - 'public_uuid' => $this->publicUuid, - 'display_name' => $this->displayName, - 'public_nick_name' => $this->publicNickName, - 'language' => $this->language, - 'region' => $this->region, - 'session_timeout' => $this->sessionTimeout, - 'first_name' => $this->firstName, - 'middle_name' => $this->middleName, - 'last_name' => $this->lastName, - 'legal_name' => $this->legalName, - 'tax_resident' => $this->taxResident, - 'date_of_birth' => $this->dateOfBirth->format('Y-m-d'), - 'place_of_birth' => $this->placeOfBirth, - 'country_of_birth' => $this->countryOfBirth, - 'nationality' => $this->nationality, - 'gender' => $this->gender, - 'version_terms_of_service' => $this->versionTos, - 'document_number' => $this->documentNumber, - 'document_type' => $this->documentType, - 'document_country_of_issuance' => $this->documentCountry, - ]; - - return $data; - } -} diff --git a/app/Services/Bunq/Request/BunqRequest.php b/app/Services/Bunq/Request/BunqRequest.php deleted file mode 100644 index 5c02da3960..0000000000 --- a/app/Services/Bunq/Request/BunqRequest.php +++ /dev/null @@ -1,527 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Request; - -use Exception; -use FireflyIII\Exceptions\FireflyException; -use FireflyIII\Services\Bunq\Object\ServerPublicKey; -use Log; -use Requests; - -/** - * @deprecated - * @codeCoverageIgnore - * Class BunqRequest. - */ -abstract class BunqRequest -{ - /** @var string */ - protected $secret = ''; - /** @var ServerPublicKey */ - protected $serverPublicKey; - /** @var string */ - private $privateKey = ''; - /** @var string */ - private $server; - /** - * @var array - */ - private $upperCaseHeaders - = [ - 'x-bunq-client-response-id' => 'X-Bunq-Client-Response-Id', - 'x-bunq-client-request-id' => 'X-Bunq-Client-Request-Id', - ]; - /** @var string */ - private $version = 'v1'; - - /** - * BunqRequest constructor. - */ - public function __construct() - { - $this->server = (string)config('import.options.bunq.server'); - $this->version = (string)config('import.options.bunq.version'); - Log::debug(sprintf('Created new BunqRequest with server "%s" and version "%s"', $this->server, $this->version)); - } - - /** - * - */ - abstract public function call(): void; - - /** - * @return string - */ - public function getServer(): string - { - return $this->server; - } - - /** - * @return ServerPublicKey - */ - public function getServerPublicKey(): ServerPublicKey - { - return $this->serverPublicKey; - } - - /** - * @param ServerPublicKey $serverPublicKey - */ - public function setServerPublicKey(ServerPublicKey $serverPublicKey) - { - $this->serverPublicKey = $serverPublicKey; - } - - /** - * @param string $privateKey - */ - public function setPrivateKey(string $privateKey) - { - $this->privateKey = $privateKey; - } - - /** - * @param string $secret - */ - public function setSecret(string $secret) - { - $this->secret = $secret; - } - - /** - * @param string $method - * @param string $uri - * @param array $headers - * @param string $data - * - * @return string - * - * @throws FireflyException - */ - protected function generateSignature(string $method, string $uri, array $headers, string $data): string - { - if (0 === \strlen($this->privateKey)) { - throw new FireflyException('No private key present.'); - } - if ('get' === strtolower($method) || 'delete' === strtolower($method)) { - $data = ''; - } - $uri = sprintf('/%s/%s', $this->version, $uri); - $toSign = sprintf("%s %s\n", strtoupper($method), $uri); - - Log::debug(sprintf('Message to sign (without data): %s', $toSign)); - - $headersToSign = ['Cache-Control', 'User-Agent']; - ksort($headers); - foreach ($headers as $name => $value) { - if (\in_array($name, $headersToSign) || 'X-Bunq-' === substr($name, 0, 7)) { - $toSign .= sprintf("%s: %s\n", $name, $value); - } - } - $toSign .= "\n" . $data; - $signature = ''; - - - openssl_sign($toSign, $signature, $this->privateKey, OPENSSL_ALGO_SHA256); - $signature = base64_encode($signature); - - return $signature; - } - - /** - * @param string $key - * @param array $response - * - * @return array - */ - protected function getArrayFromResponse(string $key, array $response): array - { - $result = []; - if (isset($response['Response'])) { - foreach ($response['Response'] as $entry) { - $currentKey = key($entry); - $data = current($entry); - if ($currentKey === $key) { - $result[] = $data; - } - } - } - - return $result; - } - - /** - * @return array - */ - protected function getDefaultHeaders(): array - { - $userAgent = sprintf('FireflyIII v%s', config('firefly.version')); - - return [ - 'X-Bunq-Client-Request-Id' => uniqid('FFIII', true), - 'Cache-Control' => 'no-cache', - 'User-Agent' => $userAgent, - 'X-Bunq-Language' => 'en_US', - 'X-Bunq-Region' => 'nl_NL', - 'X-Bunq-Geolocation' => '0 0 0 0 NL', - ]; - } - - /** - * @param string $key - * @param array $response - * - * @return array - */ - protected function getKeyFromResponse(string $key, array $response): array - { - if (isset($response['Response'])) { - foreach ($response['Response'] as $entry) { - $currentKey = key($entry); - $data = current($entry); - if ($currentKey === $key) { - return $data; - } - } - } - - return []; - } - - /** - * @param string $uri - * @param array $headers - * - * @return array - * - * @throws FireflyException - */ - protected function sendSignedBunqDelete(string $uri, array $headers): array - { - if (0 === \strlen($this->server)) { - throw new FireflyException('No bunq server defined'); - } - - $fullUri = $this->makeUri($uri); - $signature = $this->generateSignature('delete', $uri, $headers, ''); - $headers['X-Bunq-Client-Signature'] = $signature; - - Log::debug(sprintf('Going to send a signed bunq DELETE to %s', $fullUri)); - - try { - $response = Requests::delete($fullUri, $headers); - } catch (Exception $e) { - return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()]]]; - } - - $body = $response->body; - $array = json_decode($body, true); - $responseHeaders = $response->headers->getAll(); - $statusCode = (int)$response->status_code; - $array['ResponseHeaders'] = $responseHeaders; - $array['ResponseStatusCode'] = $statusCode; - - Log::debug(sprintf('Response to DELETE %s is %s', $fullUri, $body)); - if ($this->isErrorResponse($array)) { - $this->throwResponseError($array); - } - - if (!$this->verifyServerSignature($body, $responseHeaders, $statusCode)) { - throw new FireflyException(sprintf('Could not verify signature for request to "%s"', $uri)); - } - - return $array; - } - - /** - * @param string $uri - * @param array $data - * @param array $headers - * - * @return array - * - * @throws FireflyException - */ - protected function sendSignedBunqGet(string $uri, array $data, array $headers): array - { - if (0 === \strlen($this->server)) { - throw new FireflyException('No bunq server defined'); - } - - $body = json_encode($data); - $fullUri = $this->makeUri($uri); - $signature = $this->generateSignature('get', $uri, $headers, $body); - $headers['X-Bunq-Client-Signature'] = $signature; - - Log::debug(sprintf('Going to send a signed bunq GET to %s', $fullUri)); - - try { - $response = Requests::get($fullUri, $headers); - } catch (Exception $e) { - return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()]]]; - } - - $body = $response->body; - $array = json_decode($body, true); - $responseHeaders = $response->headers->getAll(); - $statusCode = (int)$response->status_code; - $array['ResponseHeaders'] = $responseHeaders; - $array['ResponseStatusCode'] = $statusCode; - - if ($this->isErrorResponse($array)) { - $this->throwResponseError($array); - } - - if (!$this->verifyServerSignature($body, $responseHeaders, $statusCode)) { - throw new FireflyException(sprintf('Could not verify signature for request to "%s"', $uri)); - } - - return $array; - } - - /** - * @param string $uri - * @param array $data - * @param array $headers - * - * @return array - * @throws FireflyException - */ - protected function sendSignedBunqPost(string $uri, array $data, array $headers): array - { - $body = json_encode($data); - $fullUri = $this->makeUri($uri); - $signature = $this->generateSignature('post', $uri, $headers, $body); - $headers['X-Bunq-Client-Signature'] = $signature; - - Log::debug(sprintf('Going to send a signed bunq POST request to: %s', $fullUri), $headers); - - try { - $response = Requests::post($fullUri, $headers, $body); - } catch (Exception $e) { - return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()]]]; - } - Log::debug('Seems to have NO exceptions in Response'); - $body = $response->body; - $array = json_decode($body, true); - $responseHeaders = $response->headers->getAll(); - $statusCode = (int)$response->status_code; - $array['ResponseHeaders'] = $responseHeaders; - $array['ResponseStatusCode'] = $statusCode; - - if ($this->isErrorResponse($array)) { - $this->throwResponseError($array); - } - - if (!$this->verifyServerSignature($body, $responseHeaders, $statusCode)) { - throw new FireflyException(sprintf('Could not verify signature for request to "%s"', $uri)); - } - - return $array; - } - - /** - * @param string $uri - * @param array $headers - * - * @return array - * @throws FireflyException - */ - protected function sendUnsignedBunqDelete(string $uri, array $headers): array - { - $fullUri = $this->makeUri($uri); - - Log::debug(sprintf('Going to send a UNsigned bunq DELETE to %s', $fullUri)); - - try { - $response = Requests::delete($fullUri, $headers); - } catch (Exception $e) { - return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()]]]; - } - $body = $response->body; - $array = json_decode($body, true); - $responseHeaders = $response->headers->getAll(); - $statusCode = $response->status_code; - $array['ResponseHeaders'] = $responseHeaders; - $array['ResponseStatusCode'] = $statusCode; - - if ($this->isErrorResponse($array)) { - $this->throwResponseError($array); - } - - return $array; - } - - /** - * @param string $uri - * @param array $data - * @param array $headers - * - * @return array - * @throws FireflyException - */ - protected function sendUnsignedBunqPost(string $uri, array $data, array $headers): array - { - $body = json_encode($data); - $fullUri = $this->makeUri($uri); - - Log::debug(sprintf('Going to send an UNsigned bunq POST to: %s', $fullUri)); - - try { - $response = Requests::post($fullUri, $headers, $body); - } catch (Exception $e) { - return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()]]]; - } - $body = $response->body; - $array = json_decode($body, true); - $responseHeaders = $response->headers->getAll(); - $statusCode = $response->status_code; - $array['ResponseHeaders'] = $responseHeaders; - $array['ResponseStatusCode'] = $statusCode; - - if ($this->isErrorResponse($array)) { - $this->throwResponseError($array); - } - - return $array; - } - - /** - * @param array $response - * - * @return bool - */ - private function isErrorResponse(array $response): bool - { - - $key = key($response); - if ('Error' === $key) { - Log::error('Response IS an error response!'); - - return true; - } - Log::debug('Response is not an error response'); - - return false; - } - - /** - * @param array $headers - * - * @return string - */ - private function joinHeaders(array $headers): string - { - $string = ''; - foreach ($headers as $header => $value) { - $string .= $header . ': ' . trim($value) . "\n"; - } - - return $string; - } - - /** - * Make full API URI - * - * @param string $uri - * - * @return string - */ - private function makeUri(string $uri): string - { - return 'https://' . $this->server . '/' . $this->version . '/' . $uri; - } - - /** - * @param array $response - * - * @throws FireflyException - */ - private function throwResponseError(array $response) - { - $message = []; - if (isset($response['Error'])) { - foreach ($response['Error'] as $error) { - $message[] = $error['error_description']; - } - } - throw new FireflyException('Bunq ERROR ' . $response['ResponseStatusCode'] . ': ' . implode(', ', $message)); - } - - /** - * @param string $body - * @param array $headers - * @param int $statusCode - * - * @return bool - * @throws FireflyException - */ - private function verifyServerSignature(string $body, array $headers, int $statusCode): bool - { - Log::debug('Going to verify signature for body+headers+status'); - $dataToVerify = $statusCode . "\n"; - $verifyHeaders = []; - - // false when no public key is present - if (null === $this->serverPublicKey) { - Log::error('No public key present in class, so return FALSE.'); - - return false; - } - foreach ($headers as $header => $value) { - // skip non-bunq headers or signature - if ('x-bunq-' !== substr($header, 0, 7) || 'x-bunq-server-signature' === $header) { - continue; - } - // need to have upper case variant of header: - if (!isset($this->upperCaseHeaders[$header])) { - throw new FireflyException(sprintf('No upper case variant for header "%s"', $header)); - } - $header = $this->upperCaseHeaders[$header]; - $verifyHeaders[$header] = $value[0]; - } - // sort verification headers: - ksort($verifyHeaders); - - // add them to data to sign: - $dataToVerify .= $this->joinHeaders($verifyHeaders); - $signature = $headers['x-bunq-server-signature'][0]; - $dataToVerify .= "\n" . $body; - $result = openssl_verify($dataToVerify, base64_decode($signature), $this->serverPublicKey->getPublicKey(), OPENSSL_ALGO_SHA256); - - if (\is_int($result) && $result < 1) { - Log::error(sprintf('Result of verification is %d, return false.', $result)); - - return false; - } - if (!\is_int($result)) { - Log::error(sprintf('Result of verification is a boolean (%d), return false.', $result)); - - return false; - } - Log::info('Signature is a match, return true.'); - - return true; - } -} diff --git a/app/Services/Bunq/Request/DeleteDeviceSessionRequest.php b/app/Services/Bunq/Request/DeleteDeviceSessionRequest.php deleted file mode 100644 index 965f68620e..0000000000 --- a/app/Services/Bunq/Request/DeleteDeviceSessionRequest.php +++ /dev/null @@ -1,57 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Request; - -use FireflyIII\Services\Bunq\Token\SessionToken; -use Log; - -/** - * @deprecated - * @codeCoverageIgnore - * Class DeleteDeviceSessionRequest. - */ -class DeleteDeviceSessionRequest extends BunqRequest -{ - /** @var SessionToken */ - private $sessionToken; - - /** - */ - public function call(): void - { - Log::debug('Going to send bunq delete session request.'); - $uri = sprintf('session/%d', $this->sessionToken->getId()); - $headers = $this->getDefaultHeaders(); - $headers['X-Bunq-Client-Authentication'] = $this->sessionToken->getToken(); - $this->sendSignedBunqDelete($uri, $headers); - - } - - /** - * @param SessionToken $sessionToken - */ - public function setSessionToken(SessionToken $sessionToken) - { - $this->sessionToken = $sessionToken; - } -} diff --git a/app/Services/Bunq/Request/DeviceServerRequest.php b/app/Services/Bunq/Request/DeviceServerRequest.php deleted file mode 100644 index 367f9133cd..0000000000 --- a/app/Services/Bunq/Request/DeviceServerRequest.php +++ /dev/null @@ -1,93 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Request; - -use FireflyIII\Services\Bunq\Id\DeviceServerId; -use FireflyIII\Services\Bunq\Token\InstallationToken; -use Log; - -/** - * @deprecated - * @codeCoverageIgnore - * Class DeviceServerRequest. - */ -class DeviceServerRequest extends BunqRequest -{ - /** @var string */ - private $description = ''; - /** @var DeviceServerId */ - private $deviceServerId; - /** @var InstallationToken */ - private $installationToken; - /** @var array */ - private $permittedIps = []; - - /** - * @throws \FireflyIII\Exceptions\FireflyException - */ - public function call(): void - { - Log::debug('Now in DeviceServerRequest::call()'); - $uri = 'device-server'; - $data = ['description' => $this->description, 'secret' => $this->secret, 'permitted_ips' => $this->permittedIps]; - $headers = $this->getDefaultHeaders(); - $headers['X-Bunq-Client-Authentication'] = $this->installationToken->getToken(); - - $response = $this->sendSignedBunqPost($uri, $data, $headers); - $deviceServerId = new DeviceServerId; - $deviceServerId->setId((int)$response['Response'][0]['Id']['id']); - $this->deviceServerId = $deviceServerId; - } - - /** - * @return DeviceServerId - */ - public function getDeviceServerId(): DeviceServerId - { - return $this->deviceServerId; - } - - /** - * @param string $description - */ - public function setDescription(string $description) - { - $this->description = $description; - } - - /** - * @param InstallationToken $installationToken - */ - public function setInstallationToken(InstallationToken $installationToken) - { - $this->installationToken = $installationToken; - } - - /** - * @param array $permittedIps - */ - public function setPermittedIps(array $permittedIps) - { - $this->permittedIps = $permittedIps; - } -} diff --git a/app/Services/Bunq/Request/DeviceSessionRequest.php b/app/Services/Bunq/Request/DeviceSessionRequest.php deleted file mode 100644 index bd8c094f25..0000000000 --- a/app/Services/Bunq/Request/DeviceSessionRequest.php +++ /dev/null @@ -1,157 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Request; - -use FireflyIII\Exceptions\FireflyException; -use FireflyIII\Services\Bunq\Id\DeviceSessionId; -use FireflyIII\Services\Bunq\Object\UserCompany; -use FireflyIII\Services\Bunq\Object\UserPerson; -use FireflyIII\Services\Bunq\Token\InstallationToken; -use FireflyIII\Services\Bunq\Token\SessionToken; - -/** - * @deprecated - * @codeCoverageIgnore - * Class DeviceSessionRequest. - */ -class DeviceSessionRequest extends BunqRequest -{ - /** @var DeviceSessionId */ - private $deviceSessionId; - /** @var InstallationToken */ - private $installationToken; - /** @var SessionToken */ - private $sessionToken; - /** @var UserCompany */ - private $userCompany; - /** @var UserPerson */ - private $userPerson; - - /** - * @throws FireflyException - */ - public function call(): void - { - $uri = 'session-server'; - $data = ['secret' => $this->secret]; - $headers = $this->getDefaultHeaders(); - $headers['X-Bunq-Client-Authentication'] = $this->installationToken->getToken(); - $response = $this->sendSignedBunqPost($uri, $data, $headers); - - $this->deviceSessionId = $this->extractDeviceSessionId($response); - $this->sessionToken = $this->extractSessionToken($response); - $this->userPerson = $this->extractUserPerson($response); - $this->userCompany = $this->extractUserCompany($response); - - } - - /** - * @return DeviceSessionId - */ - public function getDeviceSessionId(): DeviceSessionId - { - return $this->deviceSessionId; - } - - /** - * @return SessionToken - */ - public function getSessionToken(): SessionToken - { - return $this->sessionToken; - } - - /** - * @return UserCompany - */ - public function getUserCompany(): UserCompany - { - return $this->userCompany; - } - - /** - * @return UserPerson - */ - public function getUserPerson(): UserPerson - { - return $this->userPerson; - } - - /** - * @param InstallationToken $installationToken - */ - public function setInstallationToken(InstallationToken $installationToken) - { - $this->installationToken = $installationToken; - } - - /** - * @param array $response - * - * @return DeviceSessionId - */ - private function extractDeviceSessionId(array $response): DeviceSessionId - { - $data = $this->getKeyFromResponse('Id', $response); - $deviceSessionId = new DeviceSessionId; - $deviceSessionId->setId((int)$data['id']); - - return $deviceSessionId; - } - - /** - * @param array $response - * - * @return SessionToken - */ - private function extractSessionToken(array $response): SessionToken - { - $data = $this->getKeyFromResponse('Token', $response); - - return new SessionToken($data); - } - - /** - * @param $response - * - * @return UserCompany - */ - private function extractUserCompany($response): UserCompany - { - $data = $this->getKeyFromResponse('UserCompany', $response); - - return new UserCompany($data); - } - - /** - * @param $response - * - * @return UserPerson - */ - private function extractUserPerson($response): UserPerson - { - $data = $this->getKeyFromResponse('UserPerson', $response); - - return new UserPerson($data); - } -} diff --git a/app/Services/Bunq/Request/InstallationTokenRequest.php b/app/Services/Bunq/Request/InstallationTokenRequest.php deleted file mode 100644 index 0b9a2eb281..0000000000 --- a/app/Services/Bunq/Request/InstallationTokenRequest.php +++ /dev/null @@ -1,142 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Request; - -use FireflyIII\Exceptions\FireflyException; -use FireflyIII\Services\Bunq\Id\InstallationId; -use FireflyIII\Services\Bunq\Object\ServerPublicKey; -use FireflyIII\Services\Bunq\Token\InstallationToken; -use Log; - -/** - * @deprecated - * @codeCoverageIgnore - * Class InstallationTokenRequest. - */ -class InstallationTokenRequest extends BunqRequest -{ - /** @var InstallationId */ - private $installationId; - /** @var InstallationToken */ - private $installationToken; - /** @var string */ - private $publicKey = ''; - - /** - * @throws \FireflyIII\Exceptions\FireflyException - */ - public function call(): void - { - Log::debug('Now in InstallationTokenRequest::call()'); - $uri = 'installation'; - $data = ['client_public_key' => $this->publicKey]; - $headers = $this->getDefaultHeaders(); - $response = $this->sendUnsignedBunqPost($uri, $data, $headers); - //Log::debug('Installation request response', $response); - - $this->installationId = $this->extractInstallationId($response); - $this->serverPublicKey = $this->extractServerPublicKey($response); - $this->installationToken = $this->extractInstallationToken($response); - Log::debug('No errors! We have installation ID!'); - Log::debug(sprintf('Installation ID: %s', $this->installationId->getId())); - Log::debug(sprintf('Installation token: %s', $this->installationToken->getToken())); - Log::debug('Server public key: (not included)'); - } - - /** - * @return InstallationId - */ - public function getInstallationId(): InstallationId - { - return $this->installationId; - } - - /** - * @return InstallationToken - */ - public function getInstallationToken(): InstallationToken - { - return $this->installationToken; - } - - /** - * @return string - */ - public function getPublicKey(): string - { - return $this->publicKey; - } - - /** - * @param string $publicKey - */ - public function setPublicKey(string $publicKey) - { - $this->publicKey = $publicKey; - } - - /** - * @param array $response - * - * @return InstallationId - * @throws FireflyException - */ - private function extractInstallationId(array $response): InstallationId - { - $installationId = new InstallationId; - $data = $this->getKeyFromResponse('Id', $response); - - if (!isset($data['id'])) { - Log::error('No installation token in bunq response.', $response); - throw new FireflyException('There is no installation token in the bunq response. Sorry, I cannot continue.'); - } - - $installationId->setId($data['id']); - - return $installationId; - } - - /** - * @param array $response - * - * @return InstallationToken - */ - private function extractInstallationToken(array $response): InstallationToken - { - $data = $this->getKeyFromResponse('Token', $response); - - return new InstallationToken($data); - } - - /** - * @param array $response - * - * @return ServerPublicKey - */ - private function extractServerPublicKey(array $response): ServerPublicKey - { - $data = $this->getKeyFromResponse('ServerPublicKey', $response); - - return new ServerPublicKey($data); - } -} diff --git a/app/Services/Bunq/Request/ListDeviceServerRequest.php b/app/Services/Bunq/Request/ListDeviceServerRequest.php deleted file mode 100644 index 39c20fdeb0..0000000000 --- a/app/Services/Bunq/Request/ListDeviceServerRequest.php +++ /dev/null @@ -1,89 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Request; - -use FireflyIII\Services\Bunq\Object\DeviceServer; -use FireflyIII\Services\Bunq\Token\InstallationToken; -use Illuminate\Support\Collection; -use Log; - -/** - * @deprecated - * @codeCoverageIgnore - * Class ListDeviceServerRequest. - */ -class ListDeviceServerRequest extends BunqRequest -{ - /** @var Collection */ - private $devices; - /** @var InstallationToken */ - private $installationToken; - - public function __construct() - { - parent::__construct(); - $this->devices = new Collection; - Log::debug('Constructed ListDeviceServerRequest'); - } - - /** - * @throws \FireflyIII\Exceptions\FireflyException - */ - public function call(): void - { - Log::debug('Now in ListDeviceServerRequest::call()'); - $uri = 'device-server'; - $data = []; - $headers = $this->getDefaultHeaders(); - $headers['X-Bunq-Client-Authentication'] = $this->installationToken->getToken(); - $response = $this->sendSignedBunqGet($uri, $data, $headers); - Log::debug('Returned from sending device-server list request!'); - // create device server objects: - $raw = $this->getArrayFromResponse('DeviceServer', $response); - Log::debug(sprintf('Count %d entries in response array.', \count($raw))); - Log::debug('Full response', $response); - /** @var array $entry */ - foreach ($raw as $entry) { - $server = new DeviceServer($entry); - Log::debug(sprintf('Created server "%s" with IP "%s"', $server->getId()->getId(), $server->getIp())); - $this->devices->push($server); - } - - } - - /** - * @return Collection - */ - public function getDevices(): Collection - { - return $this->devices; - } - - /** - * @param InstallationToken $installationToken - */ - public function setInstallationToken(InstallationToken $installationToken) - { - $this->installationToken = $installationToken; - } -} diff --git a/app/Services/Bunq/Request/ListMonetaryAccountRequest.php b/app/Services/Bunq/Request/ListMonetaryAccountRequest.php deleted file mode 100644 index b1f6f69c8d..0000000000 --- a/app/Services/Bunq/Request/ListMonetaryAccountRequest.php +++ /dev/null @@ -1,87 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Request; - -use FireflyIII\Services\Bunq\Object\MonetaryAccountBank; -use FireflyIII\Services\Bunq\Token\SessionToken; -use Illuminate\Support\Collection; - -/** - * @deprecated - * @codeCoverageIgnore - * Class ListMonetaryAccountRequest. - */ -class ListMonetaryAccountRequest extends BunqRequest -{ - /** @var Collection */ - private $monetaryAccounts; - /** @var SessionToken */ - private $sessionToken; - /** @var int */ - private $userId = 0; - - /** - * @throws \FireflyIII\Exceptions\FireflyException - */ - public function call(): void - { - $this->monetaryAccounts = new Collection; - $uri = sprintf('user/%d/monetary-account', $this->userId); - $data = []; - $headers = $this->getDefaultHeaders(); - $headers['X-Bunq-Client-Authentication'] = $this->sessionToken->getToken(); - $response = $this->sendSignedBunqGet($uri, $data, $headers); - - // create device server objects: - $raw = $this->getArrayFromResponse('MonetaryAccountBank', $response); - foreach ($raw as $entry) { - $account = new MonetaryAccountBank($entry); - $this->monetaryAccounts->push($account); - } - - } - - /** - * @return Collection - */ - public function getMonetaryAccounts(): Collection - { - return $this->monetaryAccounts; - } - - /** - * @param SessionToken $sessionToken - */ - public function setSessionToken(SessionToken $sessionToken) - { - $this->sessionToken = $sessionToken; - } - - /** - * @param int $userId - */ - public function setUserId(int $userId) - { - $this->userId = $userId; - } -} diff --git a/app/Services/Bunq/Request/ListPaymentRequest.php b/app/Services/Bunq/Request/ListPaymentRequest.php deleted file mode 100644 index ca455daaa8..0000000000 --- a/app/Services/Bunq/Request/ListPaymentRequest.php +++ /dev/null @@ -1,107 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Request; - -use FireflyIII\Services\Bunq\Object\MonetaryAccountBank; -use FireflyIII\Services\Bunq\Object\Payment; -use FireflyIII\Services\Bunq\Token\SessionToken; -use Illuminate\Support\Collection; - - -/** - * @deprecated - * @codeCoverageIgnore - * Class ListPaymentRequest - */ -class ListPaymentRequest extends BunqRequest -{ - - /** @var MonetaryAccountBank */ - private $account; - /** @var Collection */ - private $payments; - /** @var SessionToken */ - private $sessionToken; - /** @var int */ - private $userId = 0; - - /** - * - * @throws \FireflyIII\Exceptions\FireflyException - */ - public function call(): void - { - $break = false; - $this->payments = new Collection; - $uri = sprintf('user/%d/monetary-account/%d/payment', $this->userId, $this->account->getId()); - $headers = $this->getDefaultHeaders(); - $headers['X-Bunq-Client-Authentication'] = $this->sessionToken->getToken(); - while ($break === false) { - $response = $this->sendSignedBunqGet($uri, [], $headers); - $uri = str_replace('/v1/', '', $response['Pagination']['future_url']); - $break = true; - - // create payment objects: - $raw = $this->getArrayFromResponse('Payment', $response); - foreach ($raw as $entry) { - $payment = new Payment($entry); - $this->payments->push($payment); - } - } - - } - - /** - * @return Collection - */ - public function getPayments(): Collection - { - return $this->payments; - } - - - /** - * @param MonetaryAccountBank $account - */ - public function setAccount(MonetaryAccountBank $account): void - { - $this->account = $account; - } - - /** - * @param SessionToken $sessionToken - */ - public function setSessionToken(SessionToken $sessionToken): void - { - $this->sessionToken = $sessionToken; - } - - /** - * @param int $userId - */ - public function setUserId(int $userId): void - { - $this->userId = $userId; - } -} diff --git a/app/Services/Bunq/Request/ListUserRequest.php b/app/Services/Bunq/Request/ListUserRequest.php deleted file mode 100644 index 650e4f961f..0000000000 --- a/app/Services/Bunq/Request/ListUserRequest.php +++ /dev/null @@ -1,97 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Request; - -use FireflyIII\Services\Bunq\Object\UserCompany; -use FireflyIII\Services\Bunq\Object\UserLight; -use FireflyIII\Services\Bunq\Object\UserPerson; -use FireflyIII\Services\Bunq\Token\SessionToken; - -/** - * @deprecated - * @codeCoverageIgnore - * Class ListUserRequest. - */ -class ListUserRequest extends BunqRequest -{ - /** @var SessionToken */ - private $sessionToken; - /** @var UserCompany */ - private $userCompany; - /** @var UserLight */ - private $userLight; - /** @var UserPerson */ - private $userPerson; - - /** - */ - public function call(): void - { - $uri = 'user'; - $data = []; - $headers = $this->getDefaultHeaders(); - $headers['X-Bunq-Client-Authentication'] = $this->sessionToken->getToken(); - $response = $this->sendSignedBunqGet($uri, $data, $headers); - - // create user objects: - $light = $this->getKeyFromResponse('UserLight', $response); - $company = $this->getKeyFromResponse('UserCompany', $response); - $person = $this->getKeyFromResponse('UserPerson', $response); - $this->userLight = new UserLight($light); - $this->userCompany = new UserCompany($company); - $this->userPerson = new UserPerson($person); - - } - - /** - * @return UserCompany - */ - public function getUserCompany(): UserCompany - { - return $this->userCompany; - } - - /** - * @return UserLight - */ - public function getUserLight(): UserLight - { - return $this->userLight; - } - - /** - * @return UserPerson - */ - public function getUserPerson(): UserPerson - { - return $this->userPerson; - } - - /** - * @param SessionToken $sessionToken - */ - public function setSessionToken(SessionToken $sessionToken) - { - $this->sessionToken = $sessionToken; - } -} diff --git a/app/Services/Bunq/Token/BunqToken.php b/app/Services/Bunq/Token/BunqToken.php deleted file mode 100644 index c9d61e42aa..0000000000 --- a/app/Services/Bunq/Token/BunqToken.php +++ /dev/null @@ -1,109 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Token; - -use Carbon\Carbon; - -/** - * @deprecated - * @codeCoverageIgnore - * Class BunqToken. - */ -class BunqToken -{ - /** @var Carbon */ - private $created; - /** @var int */ - private $id = 0; - /** @var string */ - private $token = ''; - /** @var Carbon */ - private $updated; - - /** - * BunqToken constructor. - * - * @param array $response - */ - public function __construct(array $response) - { - $this->makeTokenFromResponse($response); - } - - /** - * @return Carbon - */ - public function getCreated(): Carbon - { - return $this->created; - } - - /** - * @return int - */ - public function getId(): int - { - return $this->id; - } - - /** - * @return string - */ - public function getToken(): string - { - return $this->token; - } - - /** - * @return Carbon - */ - public function getUpdated(): Carbon - { - return $this->updated; - } - - /** - * @return array - */ - public function toArray(): array - { - return [ - 'id' => $this->id, - 'created' => $this->created->format('Y-m-d H:i:s.u'), - 'updated' => $this->updated->format('Y-m-d H:i:s.u'), - 'token' => $this->token, - ]; - } - - /** - * @param array $response - * - */ - protected function makeTokenFromResponse(array $response): void - { - $this->id = $response['id']; - $this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $response['created']); - $this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $response['updated']); - $this->token = $response['token']; - } -} diff --git a/app/Services/Bunq/Token/InstallationToken.php b/app/Services/Bunq/Token/InstallationToken.php deleted file mode 100644 index 40bb8c7527..0000000000 --- a/app/Services/Bunq/Token/InstallationToken.php +++ /dev/null @@ -1,32 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Services\Bunq\Token; - -/** - * @deprecated - * @codeCoverageIgnore - * Class InstallationToken. - */ -class InstallationToken extends BunqToken -{ -} diff --git a/app/Services/Bunq/Token/SessionToken.php b/app/Services/Bunq/Token/SessionToken.php deleted file mode 100644 index 89f13272b5..0000000000 --- a/app/Services/Bunq/Token/SessionToken.php +++ /dev/null @@ -1,34 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace Bunq\Token; - -namespace FireflyIII\Services\Bunq\Token; - -/** - * @deprecated - * @codeCoverageIgnore - * Class SessionToken. - */ -class SessionToken extends BunqToken -{ -} diff --git a/app/Services/Bunq/Object/Amount.php b/app/Support/Import/JobConfiguration/Bunq/BunqJobConfigurationInterface.php similarity index 50% rename from app/Services/Bunq/Object/Amount.php rename to app/Support/Import/JobConfiguration/Bunq/BunqJobConfigurationInterface.php index 3d5d7979d1..3a52f6af99 100644 --- a/app/Services/Bunq/Object/Amount.php +++ b/app/Support/Import/JobConfiguration/Bunq/BunqJobConfigurationInterface.php @@ -1,7 +1,7 @@ . */ + declare(strict_types=1); -namespace FireflyIII\Services\Bunq\Object; +namespace FireflyIII\Support\Import\JobConfiguration\Bunq; +use FireflyIII\Models\ImportJob; +use Illuminate\Support\MessageBag; /** - * @deprecated - * @codeCoverageIgnore - * Class Amount. + * Interface BunqJobConfigurationInterface */ -class Amount extends BunqObject +interface BunqJobConfigurationInterface { - /** @var string */ - private $currency; - /** @var string */ - private $value; + /** + * Return true when this stage is complete. + * + * @return bool + */ + public function configurationComplete(): bool; + /** - * Amount constructor. + * Store the job configuration. * * @param array $data + * + * @return MessageBag */ - public function __construct(array $data) - { - $this->currency = $data['currency']; - $this->value = $data['value']; - - } - - /** - * @return string - */ - public function getCurrency(): string - { - return $this->currency; - } - - /** - * @return string - */ - public function getValue(): string - { - return $this->value; - } + public function configureJob(array $data): MessageBag; /** + * Get data for config view. + * * @return array */ - public function toArray(): array - { - return [ - 'currency' => $this->currency, - 'value' => $this->value, - ]; - } -} + public function getNextData(): array; + + /** + * Get the view for this stage. + * + * @return string + */ + public function getNextView(): string; + + /** + * Set the import job. + * + * @param ImportJob $importJob + */ + public function setImportJob(ImportJob $importJob): void; + +} \ No newline at end of file diff --git a/app/Support/Import/JobConfiguration/Bunq/ChooseAccountsHandler.php b/app/Support/Import/JobConfiguration/Bunq/ChooseAccountsHandler.php new file mode 100644 index 0000000000..955800fa1c --- /dev/null +++ b/app/Support/Import/JobConfiguration/Bunq/ChooseAccountsHandler.php @@ -0,0 +1,217 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Support\Import\JobConfiguration\Bunq; + +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\Account as AccountModel; +use FireflyIII\Models\AccountType; +use FireflyIII\Models\ImportJob; +use FireflyIII\Models\TransactionCurrency; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use Illuminate\Support\MessageBag; + +/** + * Class ChooseAccountsHandler + */ +class ChooseAccountsHandler implements BunqJobConfigurationInterface +{ + + /** @var AccountRepositoryInterface */ + private $accountRepository; + /** @var CurrencyRepositoryInterface */ + private $currencyRepository; + /** @var ImportJob */ + private $importJob; + /** @var ImportJobRepositoryInterface */ + private $repository; + + /** + * Return true when this stage is complete. + * + * @return bool + */ + public function configurationComplete(): bool + { + $config = $this->repository->getConfiguration($this->importJob); + $mapping = $config['mapping'] ?? []; + $complete = \count($mapping) > 0; + if ($complete === true) { + // move job to correct stage to download transactions + $this->repository->setStage($this->importJob, 'go-for-import'); + } + + return $complete; + } + + /** + * Store the job configuration. + * + * @param array $data + * + * @return MessageBag + * @throws FireflyException + */ + public function configureJob(array $data): MessageBag + { + $config = $this->repository->getConfiguration($this->importJob); + $accounts = $config['accounts'] ?? []; + $mapping = $data['account_mapping'] ?? []; + $final = []; + if (\count($accounts) === 0) { + throw new FireflyException('No bunq accounts found. Import cannot continue.'); + } + if (\count($mapping) === 0) { + $messages = new MessageBag; + $messages->add('nomap', trans('import.bunq_no_mapping')); + + return $messages; + } + foreach ($mapping as $bunqId => $localId) { + $bunqId = (int)$bunqId; + $localId = (int)$localId; + + // validate each + $bunqId = $this->validBunqAccount($bunqId); + $accountId = $this->validLocalAccount($localId); + $final[$bunqId] = $accountId; + } + $config['mapping'] = $final; + $this->repository->setConfiguration($this->importJob, $config); + + return new MessageBag; + } + + /** + * Get data for config view. + * + * @return array + * @throws FireflyException + */ + public function getNextData(): array + { + $config = $this->repository->getConfiguration($this->importJob); + $accounts = $config['accounts'] ?? []; + if (\count($accounts) === 0) { + throw new FireflyException('No bunq accounts found. Import cannot continue.'); + } + // list the users accounts: + $collection = $this->accountRepository->getAccountsByType([AccountType::ASSET]); + + $localAccounts = []; + /** @var AccountModel $localAccount */ + foreach ($collection as $localAccount) { + $accountId = $localAccount->id; + $currencyId = (int)$this->accountRepository->getMetaValue($localAccount, 'currency_id'); + $currency = $this->getCurrency($currencyId); + $localAccounts[$accountId] = [ + 'name' => $localAccount->name, + 'iban' => $localAccount->iban, + 'code' => $currency->code, + ]; + } + + return [ + 'accounts' => $accounts, + 'local_accounts' => $localAccounts, + ]; + } + + /** + * Get the view for this stage. + * + * @return string + */ + public function getNextView(): string + { + return 'import.bunq.choose-accounts'; + } + + /** + * Set the import job. + * + * @param ImportJob $importJob + */ + public function setImportJob(ImportJob $importJob): void + { + $this->importJob = $importJob; + $this->repository = app(ImportJobRepositoryInterface::class); + $this->accountRepository = app(AccountRepositoryInterface::class); + $this->currencyRepository = app(CurrencyRepositoryInterface::class); + $this->repository->setUser($importJob->user); + $this->currencyRepository->setUser($importJob->user); + $this->accountRepository->setUser($importJob->user); + } + + /** + * @param int $currencyId + * + * @return TransactionCurrency + */ + private function getCurrency(int $currencyId): TransactionCurrency + { + $currency = $this->currencyRepository->findNull($currencyId); + if (null === $currency) { + return app('amount')->getDefaultCurrencyByUser($this->importJob->user); + } + + return $currency; + + } + + /** + * @param int $bunqId + * + * @return int + */ + private function validBunqAccount(int $bunqId): int + { + $config = $this->repository->getConfiguration($this->importJob); + $accounts = $config['accounts'] ?? []; + /** @var array $bunqAccount */ + foreach ($accounts as $bunqAccount) { + if ((int)$bunqAccount['id'] === $bunqId) { + return $bunqId; + } + } + + return 0; + } + + /** + * @param int $accountId + * + * @return int + */ + private function validLocalAccount(int $accountId): int + { + $account = $this->accountRepository->findNull($accountId); + if (null === $account) { + return 0; + } + + return $accountId; + } +} \ No newline at end of file diff --git a/app/Support/Import/JobConfiguration/Bunq/NewBunqJobHandler.php b/app/Support/Import/JobConfiguration/Bunq/NewBunqJobHandler.php new file mode 100644 index 0000000000..3d929d3db6 --- /dev/null +++ b/app/Support/Import/JobConfiguration/Bunq/NewBunqJobHandler.php @@ -0,0 +1,96 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Support\Import\JobConfiguration\Bunq; + +use FireflyIII\Models\ImportJob; +use Illuminate\Support\MessageBag; +use Log; + +/** + * @codeCoverageIgnore + * Class NewBunqJobHandler + */ +class NewBunqJobHandler implements BunqJobConfigurationInterface +{ + + /** + * Return true when this stage is complete. + * + * @return bool + */ + public function configurationComplete(): bool + { + Log::debug('NewBunqJobHandler::configurationComplete always returns true.'); + + return true; + } + + /** + * Store the job configuration. + * + * @param array $data + * + * @return MessageBag + */ + public function configureJob(array $data): MessageBag + { + Log::debug('NewBunqJobHandler::configureJob always returns an empty message bag.'); + + return new MessageBag; + } + + /** + * Get data for config view. + * + * @return array + */ + public function getNextData(): array + { + Log::debug('NewBunqJobHandler::getNextData always returns an empty array.'); + + return []; + } + + /** + * Get the view for this stage. + * + * @return string + */ + public function getNextView(): string + { + Log::debug('NewBunqJobHandler::getNextView always returns "".'); + + return ''; + } + + /** + * Set the import job. + * + * @param ImportJob $importJob + */ + public function setImportJob(ImportJob $importJob): void + { + Log::debug('NewBunqJobHandler::setImportJob does nothing.'); + } +} \ No newline at end of file diff --git a/app/Support/Import/JobConfiguration/Spectre/AuthenticatedHandler.php b/app/Support/Import/JobConfiguration/Spectre/AuthenticatedHandler.php index b477232fd8..1c9fff6b4f 100644 --- a/app/Support/Import/JobConfiguration/Spectre/AuthenticatedHandler.php +++ b/app/Support/Import/JobConfiguration/Spectre/AuthenticatedHandler.php @@ -32,7 +32,7 @@ use Log; * * Class AuthenticatedHandler */ -class AuthenticatedHandler implements SpectreConfigurationInterface +class AuthenticatedHandler implements SpectreJobConfigurationInterface { /** * Return true when this stage is complete. diff --git a/app/Support/Import/JobConfiguration/Spectre/ChooseAccountsHandler.php b/app/Support/Import/JobConfiguration/Spectre/ChooseAccountsHandler.php index a4d0b3daec..ee85ebfb8d 100644 --- a/app/Support/Import/JobConfiguration/Spectre/ChooseAccountsHandler.php +++ b/app/Support/Import/JobConfiguration/Spectre/ChooseAccountsHandler.php @@ -41,7 +41,7 @@ use Log; * Class ChooseAccountsHandler * */ -class ChooseAccountsHandler implements SpectreConfigurationInterface +class ChooseAccountsHandler implements SpectreJobConfigurationInterface { /** @var AccountRepositoryInterface */ diff --git a/app/Support/Import/JobConfiguration/Spectre/ChooseLoginHandler.php b/app/Support/Import/JobConfiguration/Spectre/ChooseLoginHandler.php index 1fa0547366..1687a0689d 100644 --- a/app/Support/Import/JobConfiguration/Spectre/ChooseLoginHandler.php +++ b/app/Support/Import/JobConfiguration/Spectre/ChooseLoginHandler.php @@ -42,7 +42,7 @@ use Log; * Class ChooseLoginHandler * */ -class ChooseLoginHandler implements SpectreConfigurationInterface +class ChooseLoginHandler implements SpectreJobConfigurationInterface { use GetSpectreCustomerTrait, GetSpectreTokenTrait; /** @var ImportJob */ diff --git a/app/Support/Import/JobConfiguration/Spectre/DoAuthenticateHandler.php b/app/Support/Import/JobConfiguration/Spectre/DoAuthenticateHandler.php index 351ff99132..0699e9dd72 100644 --- a/app/Support/Import/JobConfiguration/Spectre/DoAuthenticateHandler.php +++ b/app/Support/Import/JobConfiguration/Spectre/DoAuthenticateHandler.php @@ -36,7 +36,7 @@ use Log; * Class AuthenticateConfig * */ -class DoAuthenticateHandler implements SpectreConfigurationInterface +class DoAuthenticateHandler implements SpectreJobConfigurationInterface { use GetSpectreTokenTrait, GetSpectreCustomerTrait; /** @var ImportJob */ diff --git a/app/Support/Import/JobConfiguration/Spectre/NewSpectreJobHandler.php b/app/Support/Import/JobConfiguration/Spectre/NewSpectreJobHandler.php index 4b135225bc..8381de8639 100644 --- a/app/Support/Import/JobConfiguration/Spectre/NewSpectreJobHandler.php +++ b/app/Support/Import/JobConfiguration/Spectre/NewSpectreJobHandler.php @@ -34,7 +34,7 @@ use Log; * Class NewSpectreJobHandler * */ -class NewSpectreJobHandler implements SpectreConfigurationInterface +class NewSpectreJobHandler implements SpectreJobConfigurationInterface { /** diff --git a/app/Support/Import/JobConfiguration/Spectre/SpectreConfigurationInterface.php b/app/Support/Import/JobConfiguration/Spectre/SpectreJobConfigurationInterface.php similarity index 94% rename from app/Support/Import/JobConfiguration/Spectre/SpectreConfigurationInterface.php rename to app/Support/Import/JobConfiguration/Spectre/SpectreJobConfigurationInterface.php index f3b30bc336..6dbf38b1b4 100644 --- a/app/Support/Import/JobConfiguration/Spectre/SpectreConfigurationInterface.php +++ b/app/Support/Import/JobConfiguration/Spectre/SpectreJobConfigurationInterface.php @@ -28,10 +28,10 @@ use FireflyIII\Models\ImportJob; use Illuminate\Support\MessageBag; /** - * Interface SpectreJobConfig + * Interface SpectreJobConfigurationInterface * */ -interface SpectreConfigurationInterface +interface SpectreJobConfigurationInterface { /** * Return true when this stage is complete. diff --git a/app/Support/Import/Routine/Bunq/StageImportDataHandler.php b/app/Support/Import/Routine/Bunq/StageImportDataHandler.php new file mode 100644 index 0000000000..a913e63c5c --- /dev/null +++ b/app/Support/Import/Routine/Bunq/StageImportDataHandler.php @@ -0,0 +1,291 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Support\Import\Routine\Bunq; + +use bunq\Context\ApiContext; +use bunq\Context\BunqContext; +use bunq\Model\Generated\Endpoint\Payment; +use bunq\Model\Generated\Object\LabelMonetaryAccount; +use Carbon\Carbon; +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Factory\AccountFactory; +use FireflyIII\Models\Account as LocalAccount; +use FireflyIII\Models\AccountType; +use FireflyIII\Models\ImportJob; +use FireflyIII\Models\Preference; +use FireflyIII\Models\TransactionType; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use Log; + +/** + * Class StageImportDataHandler + */ +class StageImportDataHandler +{ + /** @var AccountFactory */ + private $accountFactory; + /** @var AccountRepositoryInterface */ + private $accountRepository; + /** @var ImportJob */ + private $importJob; + /** @var ImportJobRepositoryInterface */ + private $repository; + /** @var array */ + private $transactions; + + /** + * @return array + */ + public function getTransactions(): array + { + return $this->transactions; + } + + /** + * + * @throws FireflyException + */ + public function run(): void + { + $this->getContext(); + $config = $this->repository->getConfiguration($this->importJob); + $accounts = $config['accounts'] ?? []; + $mapping = $config['mapping'] ?? []; + $collection = [[]]; + /** @var array $bunqAccount */ + foreach ($accounts as $bunqAccount) { + $bunqAccountId = $bunqAccount['id'] ?? 0; + $localId = $mapping[$bunqAccountId] ?? 0; + if ($localId !== 0 && $bunqAccountId !== 0) { + $localAccount = $this->getLocalAccount((int)$localId); + $collection[] = $this->getTransactionsFromBunq($bunqAccountId, $localAccount); + } + } + $totalSet = array_merge(...$collection); + $this->transactions = $totalSet; + } + + /** + * @param ImportJob $importJob + * + * @return void + */ + public function setImportJob(ImportJob $importJob): void + { + $this->transactions = []; + $this->importJob = $importJob; + $this->repository = app(ImportJobRepositoryInterface::class); + $this->accountRepository = app(AccountRepositoryInterface::class); + $this->accountFactory = app(AccountFactory::class);; + $this->repository->setUser($importJob->user); + $this->accountRepository->setUser($importJob->user); + $this->accountFactory->setUser($importJob->user); + } + + /** + * @param Payment $payment + * @param LocalAccount $source + * + * @return array + */ + private function convertPayment(Payment $payment, LocalAccount $source): array + { + Log::debug(sprintf('Now at payment with ID #%d', $payment->getId())); + $type = TransactionType::WITHDRAWAL; + $counterParty = $payment->getCounterpartyAlias(); + $amount = $payment->getAmount(); + $paymentId = $payment->getId(); + + Log::debug(sprintf('Amount is %s %s', $amount->getCurrency(), $amount->getValue())); + $expected = AccountType::EXPENSE; + if (bccomp($amount->getValue(), '0') === 1) { + // amount + means that its a deposit. + $expected = AccountType::REVENUE; + $type = TransactionType::DEPOSIT; + Log::debug('Will make opposing account revenue.'); + } + $destination = $this->convertToAccount($counterParty, $expected); + + // switch source and destination if necessary. + if (bccomp($amount->getValue(), '0') === 1) { + Log::debug('Will make it a deposit.'); + [$source, $destination] = [$destination, $source]; + } + + if ($source->accountType->type === AccountType::ASSET && $destination->accountType->type === AccountType::ASSET) { + $type = TransactionType::TRANSFER; + Log::debug('Both are assets, will make transfer.'); + } + + $created = new Carbon($payment->getCreated()); + $storeData = [ + 'user' => $this->importJob->user_id, + 'type' => $type, + 'date' => $created->format('Y-m-d'), + 'description' => $payment->getDescription(), + 'piggy_bank_id' => null, + 'piggy_bank_name' => null, + 'bill_id' => null, + 'bill_name' => null, + 'tags' => [$payment->getType(), $payment->getSubType()], + 'internal_reference' => $paymentId, + 'external_id' => $paymentId, + 'notes' => null, + 'bunq_payment_id' => $paymentId, + 'transactions' => [ + // single transaction: + [ + 'description' => null, + 'amount' => $amount->getValue(), + 'currency_id' => null, + 'currency_code' => $amount->getCurrency(), + 'foreign_amount' => null, + 'foreign_currency_id' => null, + 'foreign_currency_code' => null, + 'budget_id' => null, + 'budget_name' => null, + 'category_id' => null, + 'category_name' => null, + 'source_id' => $source->id, + 'source_name' => null, + 'destination_id' => $destination->id, + 'destination_name' => null, + 'reconciled' => false, + 'identifier' => 0, + ], + ], + ]; + + return $storeData; + } + + /** + * @param LabelMonetaryAccount $party + * @param string $expectedType + * + * @return LocalAccount + */ + private function convertToAccount(LabelMonetaryAccount $party, string $expectedType): LocalAccount + { + Log::debug('in convertToAccount()'); + if ($party->getIban() !== null) { + // find opposing party by IBAN first. + $result = $this->accountRepository->findByIbanNull($party->getIban(), [$expectedType]); + if (null !== $result) { + Log::debug(sprintf('Search for %s resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id)); + + return $result; + } + + // try to find asset account just in case: + if ($expectedType !== AccountType::ASSET) { + $result = $this->accountRepository->findByIbanNull($party->getIban(), [AccountType::ASSET]); + if (null !== $result) { + Log::debug(sprintf('Search for Asset "%s" resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id)); + + return $result; + } + } + } + + // create new account: + $data = [ + 'user_id' => $this->importJob->user_id, + 'iban' => $party->getIban(), + 'name' => $party->getLabelUser()->getDisplayName(), + 'account_type_id' => null, + 'accountType' => $expectedType, + 'virtualBalance' => null, + 'active' => true, + ]; + $account = $this->accountFactory->create($data); + Log::debug( + sprintf( + 'Converted label monetary account %s to %s account %s (#%d)', + $party->getLabelUser()->getDisplayName(), + $expectedType, + $account->name, $account->id + ) + ); + + return $account; + } + + /** + * @throws FireflyException + */ + private function getContext(): void + { + /** @var Preference $preference */ + $preference = app('preferences')->getForUser($this->importJob->user, 'bunq_api_context', null); + if (null !== $preference && '' !== (string)$preference->data) { + // restore API context + $apiContext = ApiContext::fromJson($preference->data); + BunqContext::loadApiContext($apiContext); + + return; + } + throw new FireflyException('The bunq API context is unexpectedly empty.'); + } + + /** + * @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)); // @codeCoverageIgnore + } + if ($account->accountType->type !== AccountType::ASSET) { + throw new FireflyException(sprintf('Account with ID #%d is not an asset account. Job must stop now.', $accountId)); // @codeCoverageIgnore + } + + return $account; + } + + /** + * @param int $bunqAccountId + * @param LocalAccount $localAccount + * + * @return array + */ + private function getTransactionsFromBunq(int $bunqAccountId, LocalAccount $localAccount): array + { + $return = []; + // make request: + $result = Payment::listing($bunqAccountId); + // loop result: + /** @var Payment $payment */ + foreach ($result->getValue() as $payment) { + $return[] = $this->convertPayment($payment, $localAccount); + } + + return $return; + } +} \ No newline at end of file diff --git a/app/Support/Import/Routine/Bunq/StageNewHandler.php b/app/Support/Import/Routine/Bunq/StageNewHandler.php new file mode 100644 index 0000000000..a1df1d1546 --- /dev/null +++ b/app/Support/Import/Routine/Bunq/StageNewHandler.php @@ -0,0 +1,130 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Support\Import\Routine\Bunq; + +use bunq\Context\ApiContext; +use bunq\Context\BunqContext; +use bunq\Model\Generated\Endpoint\MonetaryAccount; +use bunq\Model\Generated\Endpoint\MonetaryAccountBank; +use bunq\Model\Generated\Object\Pointer; +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\ImportJob; +use FireflyIII\Models\Preference; +use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use Log; +/** + * Class StageNewHandler + */ +class StageNewHandler +{ + /** @var ImportJob */ + private $importJob; + /** @var ImportJobRepositoryInterface */ + private $repository; + + /** + * @throws FireflyException + */ + public function run(): void + { + /** @var Preference $preference */ + $preference = app('preferences')->getForUser($this->importJob->user, 'bunq_api_context', null); + if (null !== $preference && '' !== (string)$preference->data) { + // restore API context + $apiContext = ApiContext::fromJson($preference->data); + BunqContext::loadApiContext($apiContext); + + // list bunq accounts: + $accounts = $this->listAccounts(); + + // store in job: + $config = $this->repository->getConfiguration($this->importJob); + $config['accounts'] = $accounts; + $this->repository->setConfiguration($this->importJob, $config); + return; + } + throw new FireflyException('The bunq API context is unexpectedly empty.'); + } + + /** + * @param ImportJob $importJob + * + * @return void + */ + public function setImportJob(ImportJob $importJob): void + { + $this->importJob = $importJob; + $this->repository = app(ImportJobRepositoryInterface::class); + $this->repository->setUser($importJob->user); + } + + /** + * @return array + */ + private function listAccounts(): array + { + $accounts = []; + $monetaryAccountList = MonetaryAccount::listing(); + /** @var MonetaryAccount $monetaryAccount */ + foreach ($monetaryAccountList->getValue() as $monetaryAccount) { + $mab = $monetaryAccount->getMonetaryAccountBank(); + $array = $this->processMab($mab); + $accounts[] = $array; + } + + return $accounts; + } + + /** + * @param MonetaryAccountBank $mab + * + * @return array + */ + private function processMab(MonetaryAccountBank $mab): array + { + $return = [ + 'id' => $mab->getId(), + 'currency_code' => $mab->getCurrency(), + 'description' => $mab->getDescription(), + 'balance' => $mab->getBalance(), + 'status' => $mab->getStatus(), + 'aliases' => [], + 'settings' => [ + 'color' => $mab->getSetting()->getColor(), + 'default_avatar_status' => $mab->getSetting()->getDefaultAvatarStatus(), + 'restriction_chat' => $mab->getSetting()->getRestrictionChat(), + ], + ]; + /** @var Pointer $alias */ + foreach ($mab->getAlias() as $alias) { + $return['aliases'][] = [ + 'type' => $alias->getType(), + 'name' => $alias->getName(), + 'value' => $alias->getValue(), + ]; + } + + return $return; + } +} \ No newline at end of file diff --git a/config/import.php b/config/import.php index 0412b2767c..17cfde17f9 100644 --- a/config/import.php +++ b/config/import.php @@ -22,11 +22,14 @@ declare(strict_types=1); +use FireflyIII\Import\JobConfiguration\BunqJobConfiguration; use FireflyIII\Import\JobConfiguration\FakeJobConfiguration; use FireflyIII\Import\JobConfiguration\FileJobConfiguration; use FireflyIII\Import\JobConfiguration\SpectreJobConfiguration; +use FireflyIII\Import\Prerequisites\BunqPrerequisites; use FireflyIII\Import\Prerequisites\FakePrerequisites; use FireflyIII\Import\Prerequisites\SpectrePrerequisites; +use FireflyIII\Import\Routine\BunqRoutine; use FireflyIII\Import\Routine\FakeRoutine; use FireflyIII\Import\Routine\FileRoutine; use FireflyIII\Import\Routine\SpectreRoutine; @@ -37,7 +40,7 @@ return [ 'enabled' => [ 'fake' => true, 'file' => true, - 'bunq' => false, + 'bunq' => true, 'spectre' => true, 'plaid' => false, 'quovo' => false, @@ -77,7 +80,7 @@ return [ 'prerequisites' => [ 'fake' => FakePrerequisites::class, 'file' => false, - 'bunq' => false, + 'bunq' => BunqPrerequisites::class, 'spectre' => SpectrePrerequisites::class, 'plaid' => false, 'quovo' => false, @@ -87,7 +90,7 @@ return [ 'has_job_config' => [ 'fake' => true, 'file' => true, - 'bunq' => false, + 'bunq' => true, 'spectre' => true, 'plaid' => false, 'quovo' => false, @@ -97,7 +100,7 @@ return [ 'configuration' => [ 'fake' => FakeJobConfiguration::class, 'file' => FileJobConfiguration::class, - 'bunq' => false, + 'bunq' => BunqJobConfiguration::class, 'spectre' => SpectreJobConfiguration::class, 'plaid' => false, 'quovo' => false, @@ -107,7 +110,7 @@ return [ 'routine' => [ 'fake' => FakeRoutine::class, 'file' => FileRoutine::class, - 'bunq' => false, + 'bunq' => BunqRoutine::class, 'spectre' => SpectreRoutine::class, 'plaid' => false, 'quovo' => false, diff --git a/public/js/ff/import/status_v2.js b/public/js/ff/import/status_v2.js index 7f3be7dfc4..b5d230eee4 100644 --- a/public/js/ff/import/status_v2.js +++ b/public/js/ff/import/status_v2.js @@ -29,6 +29,10 @@ var maxLoops = 60; var totalLoops = 0; var startCount = 0; var jobFailed = false; +// set to true when error is reported. +// will prevent double error reporting +var reportedError = false; + $(function () { "use strict"; @@ -40,10 +44,10 @@ $(function () { */ function checkJobJSONStatus() { console.log('In checkJobJSONStatus()'); - if(jobFailed === false) { + if (jobFailed === false) { $.getJSON(jobStatusUri).done(reportJobJSONDone).fail(reportJobJSONFailure); } - if(jobFailed === true) { + if (jobFailed === true) { console.error('Job has failed, will not check.'); } } @@ -106,6 +110,7 @@ function showJobResults(data) { if (data.errors.length > 0) { $('#import-status-error-txt').show(); data.errors.forEach(function (element) { + console.error(element); $('#import-status-errors').append($('
  • ').text(element)); }); @@ -128,7 +133,7 @@ function recheckJobJSONStatus() { if (maxLoops !== 0) { console.log('max: ' + maxLoops + ' current: ' + totalLoops); } - if(jobFailed === true) { + if (jobFailed === true) { console.error('Job has failed, will not do recheck.'); } totalLoops++; @@ -143,7 +148,7 @@ function sendJobPOSTStart() { console.log('Import job already started!'); return; } - if(jobFailed === true) { + if (jobFailed === true) { console.log('Job has failed, will not start again.'); return; } @@ -161,7 +166,7 @@ function sendJobPOSTStore() { console.log('Store job already started!'); return; } - if(jobFailed === true) { + if (jobFailed === true) { console.log('Job has failed, will not start again.'); return; } @@ -181,18 +186,19 @@ function sendJobPOSTStore() { function reportJobJSONFailure(xhr, status, error) { console.log('In reportJobJSONFailure()'); jobFailed = true; - // cancel checking again for job status: - clearTimeout(timeOutId); + if (reportedError === false) { + reportedError = true; + // cancel checking again for job status: + clearTimeout(timeOutId); - // hide status boxes: - $('.statusbox').hide(); + // hide status boxes: + $('.statusbox').hide(); - // show fatal error box: - $('.fatal_error').show(); - - $('.fatal_error_txt').text('Cannot get status of current job: ' + status + ': ' + error); - // show error box. + // show fatal error box: + $('.fatal_error').show(); + $('.fatal_error_txt').text('Cannot get status of current job: ' + status + ': ' + error); + } } /** @@ -238,15 +244,17 @@ function reportJobPOSTFailure(xhr, status, error) { console.log('In reportJobPOSTFailure()'); // cancel checking again for job status: clearTimeout(timeOutId); + if (reportedError === false) { + reportedError = true; + // hide status boxes: + $('.statusbox').hide(); - // hide status boxes: - $('.statusbox').hide(); - - // show fatal error box: - $('.fatal_error').show(); - - $('.fatal_error_txt').text('Job could not be started or crashed: ' + status + ': ' + error); - // show error box. + // show fatal error box: + $('.fatal_error').show(); + console.error('Job could not be started or crashed: ' + status + ': ' + error); + $('.fatal_error_txt').text('Job could not be started or crashed: ' + status + ': ' + error); + // show error box. + } } /** @@ -256,20 +264,21 @@ function reportJobError(data) { console.log('In reportJobError()'); // cancel checking again for job status: clearTimeout(timeOutId); - - // hide status boxes: - $('.statusbox').hide(); - - // show fatal error box: - $('.fatal_error').show(); - - $('.fatal_error_txt').text('Job reports error. Please start again. Apologies. Error message is: ' + data.report_txt); - // show error box. + if (reportedError === false) { + reportedError = true; + // hide status boxes: + $('.statusbox').hide(); + // show fatal error box: + $('.fatal_error').show(); + console.error(data.report_txt); + $('.fatal_error_txt').text('Job reports error. Please start again. Apologies. Error message is: ' + data.report_txt); + } } function reportJobPOSTDone(data) { console.log('In function reportJobPOSTDone() with status "' + data.status + '"'); - if (data.status === 'NOK') { + if (data.status === 'NOK' && reportedError === false) { + reportedError = true; // cancel checking again for job status: clearTimeout(timeOutId); @@ -278,8 +287,9 @@ function reportJobPOSTDone(data) { // show fatal error box: $('.fatal_error').show(); - + console.error(data.message); $('.fatal_error_txt').text('Job could not be started or crashed: ' + data.message); - // show error box. + + } } \ No newline at end of file diff --git a/resources/lang/en_US/import.php b/resources/lang/en_US/import.php index 7b71a29fdd..1b9ba075e5 100644 --- a/resources/lang/en_US/import.php +++ b/resources/lang/en_US/import.php @@ -27,6 +27,7 @@ return [ 'index_breadcrumb' => 'Import data into Firefly III', 'prerequisites_breadcrumb_fake' => 'Prerequisites for the fake import provider', 'prerequisites_breadcrumb_spectre' => 'Prerequisites for Spectre', + 'prerequisites_breadcrumb_bunq' => 'Prerequisites for Bunq', 'job_configuration_breadcrumb' => 'Configuration for ":key"', 'job_status_breadcrumb' => 'Import status for ":key"', 'cannot_create_for_provider' => 'Firefly III cannot create a job for the ":provider"-provider.', @@ -72,9 +73,13 @@ return [ 'prereq_spectre_title' => 'Prerequisites for an import using the Spectre API', 'prereq_spectre_text' => 'In order to import data using the Spectre API (v4), you must provide Firefly III with two secret values. They can be found on the secrets page.', 'prereq_spectre_pub' => 'Likewise, the Spectre API needs to know the public key you see below. Without it, it will not recognize you. Please enter this public key on your secrets page.', + 'prereq_bunq_title' => 'Prerequisites for an import from Bunq', + 'prereq_bunq_text' => 'In order to import from bunq, you need to obtain an API key. You can do this through the app. Please note that the import function for bunq is in BETA. It has only been tested against the sandbox API.', + 'prereq_bunq_ip' => 'Bunq requires your externally facing IP address. Firefly III has tried to fill this in using the ipify service. Make sure this IP address is correct, or the import will fail.', // prerequisites success messages: 'prerequisites_saved_for_fake' => 'Fake API key stored successfully!', 'prerequisites_saved_for_spectre' => 'App ID and secret stored!', + 'prerequisites_saved_for_bunq' => 'API key and IP stored!', // job configuration: 'job_config_apply_rules_title' => 'Job configuration - apply your rules?', @@ -122,6 +127,10 @@ return [ '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', + // job configuration for Bunq: + 'job_config_bunq_accounts_title' => 'Bunq accounts', + 'job_config_bunq_accounts_text' => 'These are the accounts associated with your bunq account. Please select the accounts from which you want to import, and in which account the transactions must be imported.', + 'bunq_no_mapping' => 'It seems you have not selected any accounts.', // keys from "extra" array: 'spectre_extra_key_iban' => 'IBAN', diff --git a/resources/views/import/bunq/accounts.twig b/resources/views/import/bunq/choose-accounts.twig similarity index 67% rename from resources/views/import/bunq/accounts.twig rename to resources/views/import/bunq/choose-accounts.twig index 9556218302..6fbd144ce4 100644 --- a/resources/views/import/bunq/accounts.twig +++ b/resources/views/import/bunq/choose-accounts.twig @@ -5,18 +5,18 @@ {% endblock %} {% block content %}
    -
    +
    -

    {{ trans('import.bunq_accounts_title') }}

    +

    {{ trans('import.job_config_bunq_accounts_title') }}

    - {{ trans('import.bunq_accounts_text')|raw }} + {{ trans('import.job_config_bunq_accounts_text') }}

    @@ -28,15 +28,13 @@   {{ trans('list.account_at_bunq') }} {{ trans('list.account') }} - {{ trans('list.do_import') }} - {% for account in data.config.accounts %} + {% for account in data.accounts %} - + - {{ account.description }}
    {% for alias in account.aliases %} {% if alias.type == 'IBAN' %} @@ -45,21 +43,19 @@ {% endfor %} - + + {% for localId, localAccount in data.local_accounts %} + {% if localAccount.code == account.currency_code %} + + {% endif %} {% endfor %} - -
    - -
    - - {% endfor %} diff --git a/resources/views/import/bunq/prerequisites.twig b/resources/views/import/bunq/prerequisites.twig index 0e45d3223f..07a089fda7 100644 --- a/resources/views/import/bunq/prerequisites.twig +++ b/resources/views/import/bunq/prerequisites.twig @@ -10,34 +10,34 @@
    -

    {{ trans('import.bunq_prerequisites_title') }}

    +

    {{ trans('import.prereq_bunq_title') }}

    - {{ trans('import.bunq_prerequisites_text') }} + {{ trans('import.prereq_bunq_text') }}

    - {{ ExpandedForm.text('api_key', key) }} + {{ ExpandedForm.text('api_key', api_key) }}

    - {{ trans('import.bunq_prerequisites_text_ip')|raw }} + {{ trans('import.prereq_bunq_ip')|raw }}

    - {{ ExpandedForm.text('external_ip', ip) }} + {{ ExpandedForm.text('external_ip', external_ip) }}