Skip to content

Commit e19be15

Browse files
committed
Added endpoints for statements
1 parent 98f8d94 commit e19be15

File tree

5 files changed

+115
-26
lines changed

5 files changed

+115
-26
lines changed

example/index.php

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
* php -S localhost:8000 -t example/
55
*/
66

7-
use SpojeNet\KbAccountsApi\Entity\Tokens;
8-
use SpojeNet\KbAccountsApi\Entity\ClientReq;
97
use SpojeNet\KbAccountsApi\Entity\ApplicationReq;
10-
use SpojeNet\KbAccountsApi\Entity\TransactionSelection;
8+
use SpojeNet\KbAccountsApi\Entity\ClientReq;
9+
use SpojeNet\KbAccountsApi\Entity\Tokens;
1110
use SpojeNet\KbAccountsApi\Exception\KbClientException;
1211
use SpojeNet\KbAccountsApi\KbClient;
12+
use SpojeNet\KbAccountsApi\Selection\StatementPdfSelection;
13+
use SpojeNet\KbAccountsApi\Selection\StatementsSelection;
14+
use SpojeNet\KbAccountsApi\Selection\TransactionSelection;
1315
use SpojeNet\KbAccountsApi\Utils\Random;
1416
use Tracy\Debugger;
1517

@@ -202,7 +204,7 @@ function application(): void
202204
type: $app->client->type,
203205
encryptionKey: $app->client->encryptionKey,
204206
), $app->id);
205-
$clientIdLabel = '<a href="' . $uri . '" target="_blank">authorize</a>';
207+
$clientIdLabel = '<a href="' . $uri . '" target="_blank" rel="opener">authorize</a>';
206208
}
207209

208210
$tokenLabel = 'Missing Client ID!';
@@ -211,7 +213,7 @@ function application(): void
211213
$tokenLabel .= $app->tokens->refresh->isValid() ? '' : ' 🚫';
212214
} elseif (isset($app->client->clientId)) {
213215
$uri = $kbClient->clientAuthorizationCodeUri($app->client->clientId);
214-
$tokenLabel = '<a href="' . $uri . '" target="_blank">authorize</a>';
216+
$tokenLabel = '<a href="' . $uri . '" target="_blank" rel="opener">authorize</a>';
215217
}
216218

217219
echo <<<HTML
@@ -246,25 +248,41 @@ function application(): void
246248
<table>
247249
<tr><th>ID</th><th>IBAN</th><th>Currency</th></tr>
248250
HTML;
249-
$accountIdForTransactions = null;
251+
$firstAccountId = null;
250252
foreach ($accounts as $account) {
251-
$accountIdForTransactions ??= $account->accountId;
253+
$firstAccountId ??= $account->accountId;
252254
$accountId = short($account->accountId);
253255
echo <<<HTML
254256
<tr><td>{$accountId}</td><td>{$account->iban}</td><td>{$account->currency}</td></tr>
255257
HTML;
256258
}
257259
echo '</table>';
258260

259-
writeLabel("Transactions for account ID {$accountIdForTransactions}");
260-
$transactions = $kbClient->transactions($app->tokens->access->token, new TransactionSelection($accountIdForTransactions));
261+
writeLabel("Transactions for account ID {$firstAccountId}");
262+
$transactions = $kbClient->transactions($app->tokens->access->token, new TransactionSelection($firstAccountId));
261263
echo <<<HTML
262264
<table>
263265
<tr><th>Items:</th><td>{$transactions->numberOfElements}</td></tr>
264266
<tr><th>Pages:</th><td>{$transactions->totalPages}</td></tr>
265267
</table>
266268
HTML;
267269
array_map(fn($item) => writeOutput($item), $transactions->content);
270+
271+
writeLabel("Statements for account ID {$firstAccountId}");
272+
$statements = $kbClient->statements($app->tokens->access->token, new StatementsSelection($firstAccountId, new DateTimeImmutable()));
273+
echo <<<HTML
274+
<table>
275+
<tr><th>ID</th><th>Issued</th><th>Archived</th><th></th></tr>
276+
HTML;
277+
foreach ($statements as $statement) {
278+
$issued = $statement->issued->format('Y-m-d H:i:s');
279+
$archive = $statement->archive ? 'yes' : 'no';
280+
$link = "/dl?account={$firstAccountId}&statement={$statement->statementId}";
281+
echo <<<HTML
282+
<tr><td>{$statement->statementId}</td><td>{$issued}</td><td>{$archive}</td><td><a href="{$link}" target="_blank">PDF</a></td></tr>
283+
HTML;
284+
}
285+
echo '</table>';
268286
}
269287

270288
function delete(): void {
@@ -309,7 +327,7 @@ function callback(): void {
309327
<tr><th>API key</th><td>{$apiKey}</td></tr>
310328
</table>
311329
<br />
312-
<button onclick="window.onbeforeunload = () => {window.opener.location.href = '/app'}; window.close()">app detail</button>
330+
<button onclick="window.opener.location.href = '/app'; window.close()">app detail</button>
313331
HTML;
314332
}
315333
/** Callback from client's authorization of scope */
@@ -327,11 +345,40 @@ function callback(): void {
327345
<tr><th>Access token</th><td>{$accessToken}</td></tr>
328346
</table>
329347
<br />
330-
<button onclick="window.onbeforeunload = () => window.opener.location.reload(); window.close()">app detail</button>
348+
<button onclick="window.opener.location.reload(); window.close()">app detail</button>
331349
HTML;
332350
}
333351
}
334352

353+
function download(): void {
354+
global $storage, $kbClient;
355+
356+
$app = $storage->get();
357+
358+
if ($app === null) {
359+
writeLabel('Application not found');
360+
return;
361+
}
362+
363+
if (isset($_GET['statement'])) {
364+
$content = $kbClient->statementPdf($app->tokens->access->token, new StatementPdfSelection(
365+
accountId: sanitizeInput('account'),
366+
statementId: sanitizeInput('statement'),
367+
));
368+
369+
ob_clean();
370+
header('Content-Type: application/pdf'); // nebo jiný vhodný MIME type
371+
header('Content-Disposition: attachment; filename="statement.pdf"');
372+
header('Content-Length: ' . strlen($content));
373+
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
374+
header('Pragma: public');
375+
header('Expires: 0');
376+
377+
echo $content;
378+
exit;
379+
}
380+
}
381+
335382
// Application logic **************************************************************************************************
336383
function run(): void
337384
{
@@ -343,6 +390,7 @@ function run(): void
343390
'/app' => fn() => application(),
344391
'/del' => fn() => delete(),
345392
'/back' => fn() => callback(),
393+
'/dl' => fn() => download(),
346394
default => null,
347395
};
348396

@@ -366,6 +414,7 @@ function run(): void
366414
}
367415

368416
// HTML ***************************************************************************************************************
417+
ob_start();
369418
?>
370419
<!DOCTYPE html>
371420
<html lang="en">
@@ -406,3 +455,4 @@ function run(): void
406455
<?php run(); ?>
407456
</body>
408457
</html>
458+
<?php echo ob_get_clean();

src/KbClient.php

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
use SpojeNet\KbAccountsApi\Entity\ClientReq;
1717
use SpojeNet\KbAccountsApi\Entity\ClientRes;
1818
use SpojeNet\KbAccountsApi\Entity\Statement;
19-
use SpojeNet\KbAccountsApi\Entity\StatementsSelection;
2019
use SpojeNet\KbAccountsApi\Entity\Token;
2120
use SpojeNet\KbAccountsApi\Entity\Tokens;
2221
use SpojeNet\KbAccountsApi\Entity\Transactions;
23-
use SpojeNet\KbAccountsApi\Entity\TransactionSelection;
2422
use SpojeNet\KbAccountsApi\Exception\KbClientException;
23+
use SpojeNet\KbAccountsApi\Selection\StatementPdfSelection;
24+
use SpojeNet\KbAccountsApi\Selection\StatementsSelection;
25+
use SpojeNet\KbAccountsApi\Selection\TransactionSelection;
2526
use SpojeNet\KbAccountsApi\Utils\DtoMapper;
2627
use SpojeNet\KbAccountsApi\Utils\Random;
2728

@@ -325,6 +326,11 @@ public function accounts(string $accessToken): array
325326

326327
/* Other steps is just requested data for account like transactions */
327328

329+
/**
330+
* @param TransactionSelection $selection
331+
* @throws KbClientException
332+
* @return Transactions
333+
*/
328334
public function transactions(string $accessToken, TransactionSelection $selection): Transactions
329335
{
330336
$data = $this->sendAdaaRequest(
@@ -356,7 +362,17 @@ public function statements(string $accessToken, StatementsSelection $selection):
356362
],
357363
);
358364

359-
return array_map(static fn(array $item) => DtoMapper::map(Statement::class, $item), $data);
365+
return array_map(static fn (array $item) => DtoMapper::map(Statement::class, $item), $data);
366+
}
367+
368+
369+
public function statementPdf(string $accessToken, StatementPdfSelection $selection): string
370+
{
371+
return $this->sendAdaaRequest(
372+
accessToken: $accessToken,
373+
endpoint: "/accounts/{$selection->accountId}/statements/{$selection->statementId}",
374+
headers: ['Accept' => 'application/pdf'],
375+
);
360376
}
361377

362378
/* Utilities */
@@ -384,16 +400,24 @@ private static function formUrlEncode(array $params): string
384400

385401
/**
386402
* @throws KbClientException
387-
* @return mixed[]
403+
* @return mixed[]|string
388404
*/
389-
private function sendAdaaRequest(string $accessToken, string $endpoint, array $params = []): array
405+
private function sendAdaaRequest(string $accessToken, string $endpoint, array $params = [], array $headers = []): array|string
390406
{
391407
$request = $this->requestFactory
392-
->createRequest('GET', self::buildUri("{$this->config->adaaUri}{$endpoint}", $params))
393-
->withHeader('X-Correlation-Id', Random::correlationId())
394-
->withHeader('apiKey', $this->config->adaaApiKey)
395-
->withHeader('Authorization', "Bearer {$accessToken}")
396-
->withHeader('Accept', 'application/json');
408+
->createRequest('GET', self::buildUri("{$this->config->adaaUri}{$endpoint}", $params));
409+
410+
$headers = [
411+
'Accept' => 'application/json',
412+
'Authorization' => "Bearer {$accessToken}",
413+
'apiKey' => $this->config->adaaApiKey,
414+
'X-Correlation-Id' => Random::correlationId(),
415+
...$headers,
416+
];
417+
418+
foreach ($headers as $name => $value) {
419+
$request = $request->withHeader($name, $value);
420+
}
397421

398422
try {
399423
$response = $this->httpClient->sendRequest($request);
@@ -407,6 +431,8 @@ private function sendAdaaRequest(string $accessToken, string $endpoint, array $p
407431
throw new KbClientException($response->getReasonPhrase(), compact('request', 'response', 'responseBody'));
408432
}
409433

410-
return json_decode($responseBody, associative: true);
434+
return $headers['Accept'] === 'application/json'
435+
? json_decode($responseBody, associative: true)
436+
: $responseBody;
411437
}
412438
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace SpojeNet\KbAccountsApi\Selection;
4+
5+
class StatementPdfSelection
6+
{
7+
public function __construct(
8+
public readonly string $accountId,
9+
public readonly int $statementId,
10+
) {
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace SpojeNet\KbAccountsApi\Entity;
3+
namespace SpojeNet\KbAccountsApi\Selection;
44

55
use DateTimeImmutable;
66

@@ -9,5 +9,6 @@ class StatementsSelection
99
public function __construct(
1010
public readonly string $accountId,
1111
public readonly DateTimeImmutable $dateFrom,
12-
) {}
13-
}
12+
) {
13+
}
14+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace SpojeNet\KbAccountsApi\Entity;
3+
namespace SpojeNet\KbAccountsApi\Selection;
44

55
use DateTimeInterface;
66

0 commit comments

Comments
 (0)