Skip to content

Commit 28859e9

Browse files
authored
[ACL-259][ACL-249]: Send additional information through Tl-Agent + Add support for PLN payouts (#80)
1 parent 1b19ac2 commit 28859e9

File tree

12 files changed

+153
-33
lines changed

12 files changed

+153
-33
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
66
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [3.1.0] - 2025-03-07
9+
10+
### Added
11+
12+
- Support for PLN payouts
13+
- Send php version and cache usage via Tl-Agent
14+
815
## [3.0.2] - 2025-02-27
916

1017
### Added

README.md

+11-7
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ $beneficiary = $client->beneficiary()
192192
->verification($remitterVerification);
193193
```
194194

195-
For your *merchant account beneficiary* you can pass a statement reference that should be set on the end user's statement. Not all banks support setting such a reference, this value will be used wherever possible.
195+
For your *merchant account beneficiary* you can pass a statement reference that should be set on the end user's
196+
statement. Not all banks support setting such a reference, this value will be used wherever possible.
196197

197198
```php
198199
$beneficiary->statementReference('Statement reference.');
@@ -332,7 +333,7 @@ $paymentMethod = $client->paymentMethod()->bankTransfer()
332333
$payment = $client->payment()
333334
->user($user)
334335
->amountInMinor(1)
335-
->currency(\TrueLayer\Constants\Currencies::GBP) // You can use other currencies defined in this class.
336+
->currency(\TrueLayer\Constants\PaymentCurrencies::GBP) // You can use other currencies defined in this class.
336337
->metadata([ // add custom key value pairs
337338
'key' => 'value'
338339
])
@@ -359,7 +360,7 @@ If you prefer, you can work directly with arrays by calling the `fill` method:
359360
```php
360361
$paymentData = [
361362
'amount_in_minor' => 1,
362-
'currency' => Currencies::GBP,
363+
'currency' => PaymentCurrencies::GBP,
363364
'payment_method' => [
364365
'type' => PaymentMethods::BANK_TRANSFER,
365366
'beneficiary' => [
@@ -868,7 +869,7 @@ $beneficiary = $client->payoutBeneficiary()->externalAccount()
868869
$payout = $client->payout()
869870
->amountInMinor(1)
870871
->beneficiary($beneficiary)
871-
->currency(\TrueLayer\Constants\Currencies::GBP)
872+
->currency(\TrueLayer\Constants\PayoutCurrencies::GBP)
872873
->merchantAccountId($merchantAccount->getId())
873874
->metadata([
874875
"foo" => "bar",
@@ -890,7 +891,7 @@ $beneficiary = $client->payoutBeneficiary()->paymentSource()
890891
$payout = $client->payout()
891892
->amountInMinor(1)
892893
->beneficiary($beneficiary)
893-
->currency(\TrueLayer\Constants\Currencies::GBP)
894+
->currency(\TrueLayer\Constants\PayoutCurrencies::GBP)
894895
->merchantAccountId($merchantAccount->getId())
895896
->metadata([
896897
"foo" => "bar",
@@ -911,7 +912,7 @@ $beneficiary = $client->payoutBeneficiary()
911912
$payout = $client->payout()
912913
->amountInMinor(1)
913914
->beneficiary($beneficiary)
914-
->currency(\TrueLayer\Constants\Currencies::GBP)
915+
->currency(\TrueLayer\Constants\PayoutCurrencies::GBP)
915916
->merchantAccountId($merchantAccount->getId())
916917
->metadata([
917918
"foo" => "bar",
@@ -927,9 +928,11 @@ $payout->getId();
927928
You can optionally specify the payment scheme for a payout.
928929

929930
```php
931+
use \TrueLayer\Constants\SchemeIds;
932+
930933
$schemeSelection = $client->payoutSchemeSelection()->instantPreferred(); // Attempt to select a payment scheme that supports instant payments based on currency and geography, fallback to a non-instant scheme if instant payment is unavailable. This is used by default if no scheme selection is provided.
931934
$schemeSelection = $client->payoutSchemeSelection()->instantOnly(); // Automatically select a payment scheme that supports instant payments based on currency and geography.
932-
$schemeSelection = $client->payoutSchemeSelection()->preselected()->schemeId('faster_payments_service'); // Set the scheme manually. Scheme ID is required.
935+
$schemeSelection = $client->payoutSchemeSelection()->preselected()->schemeId(SchemeIds::FASTER_PAYMENTS_SERVICE); // Set the scheme manually. Scheme ID is required.
933936

934937

935938
$client->payout()
@@ -957,6 +960,7 @@ if ($payout instanceof PayoutRetrievedInterface) {
957960
$payout->getAmountInMinor();
958961
$payout->getMerchantAccountId();
959962
$payout->getStatus();
963+
$payout->getSchemeId();
960964
$payout->getBeneficiary();
961965
$payout->getMetadata();
962966
$payout->getCreatedAt();

src/Constants/PaymentCurrencies.php

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TrueLayer\Constants;
6+
7+
class PaymentCurrencies extends Currencies
8+
{
9+
10+
}

src/Constants/PayoutCurrencies.php

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TrueLayer\Constants;
6+
7+
class PayoutCurrencies
8+
{
9+
public const GBP = 'GBP';
10+
public const EUR = 'EUR';
11+
public const PLN = 'PLN';
12+
}

src/Constants/SchemeIds.php

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TrueLayer\Constants;
6+
7+
class SchemeIds
8+
{
9+
public const FASTER_PAYMENTS_SERVICE = 'faster_payments_service';
10+
public const SEPA_CREDIT_TRANSFER_INSTANT = 'sepa_credit_transfer_instant';
11+
public const SEPA_CREDIT_TRANSFER = 'sepa_credit_transfer';
12+
public const POLISH_DOMESTIC_STANDARD = 'polish_domestic_standard';
13+
public const POLISH_DOMESTIC_EXPRESS = 'polish_domestic_express';
14+
}

src/Entities/Payout/PayoutRetrieved.php

+14
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ abstract class PayoutRetrieved extends Entity implements PayoutRetrievedInterfac
4545
*/
4646
protected string $status;
4747

48+
/**
49+
* @var string
50+
*/
51+
protected string $schemeId;
52+
4853
/**
4954
* @var \DateTimeInterface
5055
*/
@@ -69,6 +74,7 @@ abstract class PayoutRetrieved extends Entity implements PayoutRetrievedInterfac
6974
'beneficiary',
7075
'metadata',
7176
'status',
77+
'scheme_id',
7278
'created_at',
7379
];
7480

@@ -128,6 +134,14 @@ public function getStatus(): string
128134
return $this->status;
129135
}
130136

137+
/**
138+
* @return string|null
139+
*/
140+
public function getSchemeId(): ?string
141+
{
142+
return $this->schemeId ?? null;
143+
}
144+
131145
/**
132146
* @return \DateTimeInterface
133147
*/

src/Factories/ClientFactory.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ final class ClientFactory implements ClientFactoryInterface
3737
/**
3838
* @param ClientConfigInterface $config
3939
*
40-
* @throws MissingHttpImplementationException
40+
* @return ClientInterface
4141
* @throws SignerException
4242
*
43-
* @return ClientInterface
43+
* @throws MissingHttpImplementationException
4444
*/
4545
public function make(ClientConfigInterface $config): ClientInterface
4646
{
@@ -125,7 +125,7 @@ private function makeApiClient(ClientConfigInterface $config): void
125125
$this->apiClient = new Decorators\ExponentialBackoffDecorator($this->apiClient);
126126
$this->apiClient = new Decorators\SigningDecorator($this->apiClient, $signer);
127127
$this->apiClient = new Decorators\IdempotencyKeyDecorator($this->apiClient);
128-
$this->apiClient = new Decorators\TLAgentDecorator($this->apiClient);
128+
$this->apiClient = new Decorators\TLAgentDecorator($this->apiClient, ['client.cache' => !!$config->getCache()]);
129129
}
130130

131131
/**

src/Interfaces/Payout/PayoutRetrievedInterface.php

+5
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ public function getMetadata(): array;
4444
*/
4545
public function getStatus(): string;
4646

47+
/**
48+
* @return string|null
49+
*/
50+
public function getSchemeId(): ?string;
51+
4752
/**
4853
* @return \DateTimeInterface
4954
*/

src/Services/ApiClient/Decorators/TLAgentDecorator.php

+25-9
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,44 @@
99
use TrueLayer\Exceptions\ApiRequestJsonSerializationException;
1010
use TrueLayer\Exceptions\ApiResponseUnsuccessfulException;
1111
use TrueLayer\Exceptions\SignerException;
12+
use TrueLayer\Interfaces\ApiClient\ApiClientInterface;
1213
use TrueLayer\Interfaces\ApiClient\ApiRequestInterface;
1314

1415
final class TLAgentDecorator extends BaseApiClientDecorator
1516
{
17+
private string $headerValue = 'truelayer-php';
18+
19+
/**
20+
* @param ApiClientInterface $next
21+
* @param array<string, string|bool> $meta
22+
*/
23+
public function __construct(ApiClientInterface $next, array $meta = [])
24+
{
25+
parent::__construct($next);
26+
27+
try {
28+
$clientVersion = InstalledVersions::getPrettyVersion('truelayer/client');
29+
30+
$commentItems = array_merge(['php.version' => phpversion()], $meta);
31+
$comment = json_encode($commentItems);
32+
33+
$this->headerValue .= " / {$clientVersion} {$comment}";
34+
} catch (\Exception) {
35+
}
36+
}
37+
1638
/**
1739
* @param ApiRequestInterface $apiRequest
1840
*
19-
* @throws ApiResponseUnsuccessfulException
41+
* @return mixed
2042
* @throws SignerException
2143
* @throws ApiRequestJsonSerializationException
2244
*
23-
* @return mixed
45+
* @throws ApiResponseUnsuccessfulException
2446
*/
2547
public function send(ApiRequestInterface $apiRequest)
2648
{
27-
try {
28-
$version = InstalledVersions::getPrettyVersion('truelayer/client');
29-
} catch (\OutOfBoundsException $e) {
30-
$version = 'unknown';
31-
}
32-
33-
$apiRequest->header(CustomHeaders::TL_AGENT, "truelayer-php/{$version}");
49+
$apiRequest->header(CustomHeaders::TL_AGENT, $this->headerValue);
3450

3551
return $this->next->send($apiRequest);
3652
}

tests/acceptance/PayoutTest.php

+42-9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use Ramsey\Uuid\Uuid;
66
use TrueLayer\Constants\Currencies;
7+
use TrueLayer\Constants\PayoutCurrencies;
8+
use TrueLayer\Constants\SchemeIds;
79
use TrueLayer\Interfaces\MerchantAccount\MerchantAccountInterface;
810
use TrueLayer\Interfaces\Payment\AuthorizationFlow\Action\RedirectActionInterface;
911
use TrueLayer\Interfaces\Payment\PaymentSettledInterface;
@@ -18,7 +20,7 @@
1820

1921
$account = Arr::first(
2022
$helper->client()->getMerchantAccounts(),
21-
fn (MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
23+
fn(MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
2224
);
2325

2426
$merchantBeneficiary = $helper->merchantBeneficiary($account);
@@ -76,7 +78,7 @@
7678

7779
$account = Arr::first(
7880
$client->getMerchantAccounts(),
79-
fn (MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
81+
fn(MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
8082
);
8183

8284
$payoutBeneficiary = $client->payoutBeneficiary()->externalAccount()
@@ -116,7 +118,7 @@
116118

117119
$account = Arr::first(
118120
$helper->client()->getMerchantAccounts(),
119-
fn (MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
121+
fn(MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
120122
);
121123

122124
$merchantBeneficiary = $helper->merchantBeneficiary($account);
@@ -174,7 +176,7 @@
174176

175177
$account = Arr::first(
176178
$client->getMerchantAccounts(),
177-
fn (MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
179+
fn(MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
178180
);
179181

180182
$payoutBeneficiary = $client->payoutBeneficiary()->externalAccount()
@@ -221,7 +223,7 @@
221223

222224
$account = Arr::first(
223225
$helper->client()->getMerchantAccounts(),
224-
fn (MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
226+
fn(MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
225227
);
226228

227229
$merchantBeneficiary = $helper->merchantBeneficiary($account);
@@ -275,7 +277,7 @@
275277

276278
$account = Arr::first(
277279
$client->getMerchantAccounts(),
278-
fn (MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
280+
fn(MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
279281
);
280282

281283
$payoutBeneficiary = $client->payoutBeneficiary()->externalAccount()
@@ -318,7 +320,7 @@
318320

319321
$account = Arr::first(
320322
$client->getMerchantAccounts(),
321-
fn (MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
323+
fn(MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
322324
);
323325

324326
$payoutBeneficiary = $client->payoutBeneficiary()->externalAccount()
@@ -354,7 +356,7 @@
354356

355357
$account = Arr::first(
356358
$client->getMerchantAccounts(),
357-
fn (MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
359+
fn(MerchantAccountInterface $account) => $account->getCurrency() === 'GBP'
358360
);
359361

360362
$payoutBeneficiary = $client->payoutBeneficiary()->externalAccount()
@@ -376,7 +378,38 @@
376378

377379
\expect($response->getId())->toBeString();
378380

379-
/** @var PayoutRetrievedInterface $payout */
381+
$payout = $client->getPayout($response->getId());
382+
383+
\expect($payout)->toBeInstanceOf(PayoutRetrievedInterface::class);
384+
});
385+
386+
\it('creates PLN payout', function () {
387+
$client = \client();
388+
389+
$account = Arr::first(
390+
$client->getMerchantAccounts(),
391+
fn(MerchantAccountInterface $account) => $account->getCurrency() === PayoutCurrencies::PLN
392+
);
393+
394+
$payoutBeneficiary = $client->payoutBeneficiary()->externalAccount()
395+
->accountIdentifier(
396+
$client->accountIdentifier()->iban()->iban('GB29NWBK60161331926819')
397+
)
398+
->accountHolderName('Test name')
399+
->reference('Test reference');
400+
401+
$schemeSelection = $client->payoutSchemeSelection()->preselected()->schemeId(SchemeIds::POLISH_DOMESTIC_EXPRESS);
402+
403+
$response = $client->payout()
404+
->amountInMinor(1)
405+
->currency(PayoutCurrencies::PLN)
406+
->merchantAccountId($account->getId())
407+
->beneficiary($payoutBeneficiary)
408+
->schemeSelection($schemeSelection)
409+
->create();
410+
411+
\expect($response->getId())->toBeString();
412+
380413
$payout = $client->getPayout($response->getId());
381414

382415
\expect($payout)->toBeInstanceOf(PayoutRetrievedInterface::class);

tests/integration/ApiClient/UserAgentTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
$apiRequestUserAgent = \getSentHttpRequests()[1]->getHeaderLine(CustomHeaders::TL_AGENT);
1414

1515
$version = InstalledVersions::getPrettyVersion('truelayer/client');
16-
$userAgent = "truelayer-php/{$version}";
16+
$userAgent = "truelayer-php / {$version}";
1717

18-
\expect($authRequestUserAgent)->toBe($userAgent);
19-
\expect($apiRequestUserAgent)->toBe($userAgent);
18+
\expect($authRequestUserAgent)->toStartWith($userAgent);
19+
\expect($apiRequestUserAgent)->toStartWith($userAgent);
2020
});
2121

2222
\it('uses custom agent header', function () {

0 commit comments

Comments
 (0)