From 0f229e4d7b9d04b222134a7b29064b2151b84a22 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 26 Aug 2017 06:21:22 +0200 Subject: [PATCH] Improved extraction of bunq data. --- .../Controllers/Import/BankController.php | 2 +- app/Services/Bunq/Object/Alias.php | 69 ++++++++++ app/Services/Bunq/Object/Amount.php | 58 ++++++++ app/Services/Bunq/Object/Avatar.php | 23 ++++ .../Bunq/Object/MonetaryAccountBank.php | 124 +++++++++++++++++- .../Bunq/Object/MonetaryAccountProfile.php | 43 ++++++ .../Bunq/Object/MonetaryAccountSetting.php | 67 ++++++++++ .../Bunq/Object/NotificationFilter.php | 32 +++++ app/Services/Bunq/Object/UserCompany.php | 10 ++ .../Request/ListMonetaryAccountRequest.php | 79 +++++++++++ .../Import/Information/BunqInformation.php | 101 +++++++++++--- .../Information/InformationInterface.php | 14 +- .../Prerequisites/BunqPrerequisites.php | 3 +- config/firefly.php | 2 +- 14 files changed, 605 insertions(+), 22 deletions(-) create mode 100644 app/Services/Bunq/Object/Alias.php create mode 100644 app/Services/Bunq/Object/Amount.php create mode 100644 app/Services/Bunq/Object/Avatar.php create mode 100644 app/Services/Bunq/Object/MonetaryAccountProfile.php create mode 100644 app/Services/Bunq/Object/MonetaryAccountSetting.php create mode 100644 app/Services/Bunq/Object/NotificationFilter.php create mode 100644 app/Services/Bunq/Request/ListMonetaryAccountRequest.php diff --git a/app/Http/Controllers/Import/BankController.php b/app/Http/Controllers/Import/BankController.php index d54fa5726d..d8a0279063 100644 --- a/app/Http/Controllers/Import/BankController.php +++ b/app/Http/Controllers/Import/BankController.php @@ -34,7 +34,7 @@ class BankController extends Controller $object->setUser(auth()->user()); if ($object->hasPrerequisites()) { - return redirect(route('import.banq.prerequisites', [$bank])); + return redirect(route('import.bank.prerequisites', [$bank])); } $class = config(sprintf('firefly.import_info.%s', $bank)); /** @var InformationInterface $object */ diff --git a/app/Services/Bunq/Object/Alias.php b/app/Services/Bunq/Object/Alias.php new file mode 100644 index 0000000000..7d1703eabc --- /dev/null +++ b/app/Services/Bunq/Object/Alias.php @@ -0,0 +1,69 @@ +type = $data['type']; + $this->name = $data['name']; + $this->value = $data['value']; + + return; + } + + /** + * @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; + } + + + +} \ No newline at end of file diff --git a/app/Services/Bunq/Object/Amount.php b/app/Services/Bunq/Object/Amount.php new file mode 100644 index 0000000000..857e85f304 --- /dev/null +++ b/app/Services/Bunq/Object/Amount.php @@ -0,0 +1,58 @@ +currency = $data['currency']; + $this->value = $data['value']; + + return; + } + + /** + * @return string + */ + public function getCurrency(): string + { + return $this->currency; + } + + /** + * @return string + */ + public function getValue(): string + { + return $this->value; + } + + + +} \ No newline at end of file diff --git a/app/Services/Bunq/Object/Avatar.php b/app/Services/Bunq/Object/Avatar.php new file mode 100644 index 0000000000..adfc41cde6 --- /dev/null +++ b/app/Services/Bunq/Object/Avatar.php @@ -0,0 +1,23 @@ +description; + } + + /** + * @return int + */ + public function getId(): int + { + return $this->id; + } + + /** + * @return array + */ + public function getAliases(): array + { + return $this->aliases; + } + + /** + * @return string + */ + public function getCurrency(): string + { + return $this->currency; + } + + /** + * @return Amount + */ + public function getBalance(): Amount + { + return $this->balance; + } + + /** + * @return MonetaryAccountSetting + */ + public function getSetting(): MonetaryAccountSetting + { + return $this->setting; + } + + + /** * MonetaryAccountBank constructor. * * @param array $data */ - public function __construct(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->status = $data['status']; + $this->subStatus = $data['sub_status']; + $this->monetaryAccountProfile = new MonetaryAccountProfile($data['monetary_account_profile']); + $this->setting = new MonetaryAccountSetting($data['setting']); + $this->overdraftLimit = new Amount($data['overdraft_limit']); + $this->publicUuid = $data['public_uuid']; + + // create aliases: + foreach ($data['alias'] as $alias) { + $this->aliases[] = new Alias($alias); + } + foreach ($data['notification_filters'] as $filter) { + $this->notificationFilters = new NotificationFilter($filter); + } + + return; } } \ No newline at end of file diff --git a/app/Services/Bunq/Object/MonetaryAccountProfile.php b/app/Services/Bunq/Object/MonetaryAccountProfile.php new file mode 100644 index 0000000000..e4995ea19c --- /dev/null +++ b/app/Services/Bunq/Object/MonetaryAccountProfile.php @@ -0,0 +1,43 @@ +profileDrain = null; + $this->profileFill = null; + $this->profileActionRequired = $data['profile_action_required']; + $this->profileAmountRequired = new Amount($data['profile_amount_required']); + return; + } + +} \ No newline at end of file diff --git a/app/Services/Bunq/Object/MonetaryAccountSetting.php b/app/Services/Bunq/Object/MonetaryAccountSetting.php new file mode 100644 index 0000000000..e1277c3dbc --- /dev/null +++ b/app/Services/Bunq/Object/MonetaryAccountSetting.php @@ -0,0 +1,67 @@ +color = $data['color']; + $this->defaultAvatarStatus = $data['default_avatar_status']; + $this->restrictionChat = $data['restriction_chat']; + return; + } + + /** + * @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; + } + + +} \ No newline at end of file diff --git a/app/Services/Bunq/Object/NotificationFilter.php b/app/Services/Bunq/Object/NotificationFilter.php new file mode 100644 index 0000000000..f12843c159 --- /dev/null +++ b/app/Services/Bunq/Object/NotificationFilter.php @@ -0,0 +1,32 @@ +id; + } + + + } \ No newline at end of file diff --git a/app/Services/Bunq/Request/ListMonetaryAccountRequest.php b/app/Services/Bunq/Request/ListMonetaryAccountRequest.php new file mode 100644 index 0000000000..8022149b71 --- /dev/null +++ b/app/Services/Bunq/Request/ListMonetaryAccountRequest.php @@ -0,0 +1,79 @@ +monetaryAccounts; + } + + /** + * + */ + public function call(): void + { + $this->monetaryAccounts = new Collection; + $uri = sprintf('/v1/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; + } + + /** + * @param SessionToken $sessionToken + */ + public function setSessionToken(SessionToken $sessionToken) + { + $this->sessionToken = $sessionToken; + } + + /** + * @param int $userId + */ + public function setUserId(int $userId) + { + $this->userId = $userId; + } + +} \ No newline at end of file diff --git a/app/Support/Import/Information/BunqInformation.php b/app/Support/Import/Information/BunqInformation.php index 3c41800fa1..9acf363f2e 100644 --- a/app/Support/Import/Information/BunqInformation.php +++ b/app/Support/Import/Information/BunqInformation.php @@ -12,8 +12,12 @@ declare(strict_types=1); namespace FireflyIII\Support\Import\Information; +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Services\Bunq\Object\Alias; +use FireflyIII\Services\Bunq\Object\MonetaryAccountBank; use FireflyIII\Services\Bunq\Request\DeleteDeviceSessionRequest; use FireflyIII\Services\Bunq\Request\DeviceSessionRequest; +use FireflyIII\Services\Bunq\Request\ListMonetaryAccountRequest; use FireflyIII\Services\Bunq\Request\ListUserRequest; use FireflyIII\Services\Bunq\Token\SessionToken; use FireflyIII\User; @@ -35,20 +39,52 @@ class BunqInformation implements InformationInterface /** * Returns a collection of accounts. Preferrably, these follow a uniform Firefly III format so they can be managed over banks. * - * @return Collection + * The format for these bank accounts is basically this: + * + * id: bank specific id + * name: bank appointed name + * number: account number (usually IBAN) + * currency: ISO code of currency + * balance: current balance + * + * + * any other fields are optional but can be useful: + * image: logo or account specific thing + * color: any associated color. + * + * @return array */ - public function getAccounts(): Collection + public function getAccounts(): array { Log::debug('Now in getAccounts()'); $sessionToken = $this->startSession(); - $this->getUserInformation($sessionToken); + $id = $this->getUserInformation($sessionToken); // get list of Bunq accounts: + $accounts = $this->getMonetaryAccounts($sessionToken, $id); + $return = []; + /** @var MonetaryAccountBank $account */ + foreach ($accounts as $account) { + $current = [ + 'id' => $account->getId(), + 'name' => $account->getDescription(), + 'currency' => $account->getCurrency(), + 'balance' => $account->getBalance()->getValue(), + 'color' => $account->getSetting()->getColor(), + ]; + /** @var Alias $alias */ + foreach ($account->getAliases() as $alias) { + if ($alias->getType() === 'IBAN') { + $current['number'] = $alias->getValue(); + } + } + $return[] = $current; + } $this->closeSession($sessionToken); - return new Collection; + return $return; } /** @@ -78,19 +114,49 @@ class BunqInformation implements InformationInterface $request->setServerPublicKey($serverPublicKey); $request->setSessionToken($sessionToken); $request->call(); + return; } /** * @param SessionToken $sessionToken + * @param int $userId + * + * @return Collection */ - private function getUserInformation(SessionToken $sessionToken): void + private function getMonetaryAccounts(SessionToken $sessionToken, int $userId): Collection { - $apiKey = Preferences::getForUser($this->user, 'bunq_api_key')->data; - $serverPublicKey = Preferences::getForUser($this->user, 'bunq_server_public_key')->data; - $server = config('firefly.bunq.server'); - $privateKey = Preferences::getForUser($this->user, 'bunq_private_key')->data; - $request = new ListUserRequest; + $apiKey = Preferences::getForUser($this->user, 'bunq_api_key')->data; + $serverPublicKey = Preferences::getForUser($this->user, 'bunq_server_public_key')->data; + $server = config('firefly.bunq.server'); + $privateKey = Preferences::getForUser($this->user, 'bunq_private_key')->data; + $request = new ListMonetaryAccountRequest; + + $request->setSessionToken($sessionToken); + $request->setSecret($apiKey); + $request->setServerPublicKey($serverPublicKey); + $request->setServer($server); + $request->setPrivateKey($privateKey); + $request->setUserId($userId); + $request->call(); + + return $request->getMonetaryAccounts(); + + } + + /** + * @param SessionToken $sessionToken + * + * @return int + * @throws FireflyException + */ + private function getUserInformation(SessionToken $sessionToken): int + { + $apiKey = Preferences::getForUser($this->user, 'bunq_api_key')->data; + $serverPublicKey = Preferences::getForUser($this->user, 'bunq_server_public_key')->data; + $server = config('firefly.bunq.server'); + $privateKey = Preferences::getForUser($this->user, 'bunq_private_key')->data; + $request = new ListUserRequest; $request->setSessionToken($sessionToken); $request->setSecret($apiKey); $request->setServerPublicKey($serverPublicKey); @@ -98,12 +164,15 @@ class BunqInformation implements InformationInterface $request->setPrivateKey($privateKey); $request->call(); // return the first that isn't null? - // get all objects, try to find ID. - var_dump($request->getUserCompany()); - var_dump($request->getUserLight()); - var_dump($request->getUserPerson()); - - return; + $company = $request->getUserCompany(); + if ($company->getId() > 0) { + return $company->getId(); + } + $user = $request->getUserPerson(); + if ($user->getId() > 0) { + return $user->getId(); + } + throw new FireflyException('Expected user or company from Bunq, but got neither.'); } /** diff --git a/app/Support/Import/Information/InformationInterface.php b/app/Support/Import/Information/InformationInterface.php index a3a8fb6dca..47dbf90ef4 100644 --- a/app/Support/Import/Information/InformationInterface.php +++ b/app/Support/Import/Information/InformationInterface.php @@ -33,7 +33,17 @@ interface InformationInterface /** * Returns a collection of accounts. Preferrably, these follow a uniform Firefly III format so they can be managed over banks. * - * @return Collection + * The format for these bank accounts is basically this: + * + * id: bank specific id + * name: bank appointed name + * number: account number (usually IBAN) + * currency: ISO code of currency + * + * any other fields are optional but can be useful: + * image: logo or account specific thing + * + * @return array */ - public function getAccounts(): Collection; + public function getAccounts(): array; } \ No newline at end of file diff --git a/app/Support/Import/Prerequisites/BunqPrerequisites.php b/app/Support/Import/Prerequisites/BunqPrerequisites.php index 44abdf488b..022d1e44b9 100644 --- a/app/Support/Import/Prerequisites/BunqPrerequisites.php +++ b/app/Support/Import/Prerequisites/BunqPrerequisites.php @@ -68,7 +68,8 @@ class BunqPrerequisites implements PrerequisitesInterface { $apiKey = Preferences::getForUser($this->user, 'bunq_api_key', false); - return ($apiKey->data === false); + + return ($apiKey->data === false || is_null($apiKey->data)); } /** diff --git a/config/firefly.php b/config/firefly.php index a31becc9af..51c26ecb91 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -46,7 +46,7 @@ return [ 'bunq' => 'FireflyIII\Support\Import\Information\BunqInformation', ], 'bunq' => [ - 'server' => 'https://api.bunq.com', + 'server' => 'https://sandbox.public.api.bunq.com', ], 'default_export_format' => 'csv', 'default_import_format' => 'csv',