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($('