Skip to content

Commit 0540904

Browse files
committed
Added statements()
1 parent 413b399 commit 0540904

File tree

6 files changed

+157
-21
lines changed

6 files changed

+157
-21
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/Entity/Statement.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace SpojeNet\KbAccountsApi\Entity;
4+
5+
class Statement
6+
{
7+
public function __construct(
8+
public readonly \DateTimeImmutable $issued,
9+
public readonly int $sequenceNumber,
10+
public readonly int $pagesCount,
11+
public readonly int $statementId,
12+
public readonly bool $archive,
13+
) {
14+
}
15+
}

src/KbClient.php

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515
use SpojeNet\KbAccountsApi\Entity\ApplicationReq;
1616
use SpojeNet\KbAccountsApi\Entity\ClientReq;
1717
use SpojeNet\KbAccountsApi\Entity\ClientRes;
18+
use SpojeNet\KbAccountsApi\Entity\Statement;
1819
use SpojeNet\KbAccountsApi\Entity\Token;
1920
use SpojeNet\KbAccountsApi\Entity\Tokens;
2021
use SpojeNet\KbAccountsApi\Entity\Transactions;
21-
use SpojeNet\KbAccountsApi\Entity\TransactionSelection;
2222
use SpojeNet\KbAccountsApi\Exception\KbClientException;
23+
use SpojeNet\KbAccountsApi\Selection\StatementPdfSelection;
24+
use SpojeNet\KbAccountsApi\Selection\StatementsSelection;
25+
use SpojeNet\KbAccountsApi\Selection\TransactionSelection;
2326
use SpojeNet\KbAccountsApi\Utils\DtoMapper;
2427
use SpojeNet\KbAccountsApi\Utils\Random;
2528

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

324327
/* Other steps is just requested data for account like transactions */
325328

329+
/**
330+
* @param TransactionSelection $selection
331+
* @throws KbClientException
332+
* @return Transactions
333+
*/
326334
public function transactions(string $accessToken, TransactionSelection $selection): Transactions
327335
{
328336
$data = $this->sendAdaaRequest(
@@ -340,6 +348,33 @@ public function transactions(string $accessToken, TransactionSelection $selectio
340348
}
341349

342350

351+
/**
352+
* @throws KbClientException
353+
* @return Statement[]
354+
*/
355+
public function statements(string $accessToken, StatementsSelection $selection): array
356+
{
357+
$data = $this->sendAdaaRequest(
358+
accessToken: $accessToken,
359+
endpoint: "/accounts/{$selection->accountId}/statements",
360+
params: [
361+
'dateFrom' => $selection->dateFrom->format('Y-m-d\TH:i:s\Z'),
362+
],
363+
);
364+
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+
);
376+
}
377+
343378
/* Utilities */
344379

345380
/**
@@ -365,16 +400,24 @@ private static function formUrlEncode(array $params): string
365400

366401
/**
367402
* @throws KbClientException
368-
* @return mixed[]
403+
* @return mixed[]|string
369404
*/
370-
private function sendAdaaRequest(string $accessToken, string $endpoint, array $params = []): array
405+
private function sendAdaaRequest(string $accessToken, string $endpoint, array $params = [], array $headers = []): array|string
371406
{
372407
$request = $this->requestFactory
373-
->createRequest('GET', self::buildUri("{$this->config->adaaUri}{$endpoint}", $params))
374-
->withHeader('X-Correlation-Id', Random::correlationId())
375-
->withHeader('apiKey', $this->config->adaaApiKey)
376-
->withHeader('Authorization', "Bearer {$accessToken}")
377-
->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+
}
378421

379422
try {
380423
$response = $this->httpClient->sendRequest($request);
@@ -388,6 +431,8 @@ private function sendAdaaRequest(string $accessToken, string $endpoint, array $p
388431
throw new KbClientException($response->getReasonPhrase(), compact('request', 'response', 'responseBody'));
389432
}
390433

391-
return json_decode($responseBody, associative: true);
434+
return $headers['Accept'] === 'application/json'
435+
? json_decode($responseBody, associative: true)
436+
: $responseBody;
392437
}
393438
}
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+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace SpojeNet\KbAccountsApi\Selection;
4+
5+
use DateTimeImmutable;
6+
7+
class StatementsSelection
8+
{
9+
public function __construct(
10+
public readonly string $accountId,
11+
public readonly DateTimeImmutable $dateFrom,
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)