Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Development Commands

### Testing
- `composer run integration-tests` - Run integration tests using Pest
- `composer run acceptance-tests` - Run acceptance tests using Pest
- `vendor/bin/pest --test-directory tests/integration` - Run integration tests directly
- `vendor/bin/pest --test-directory tests/acceptance` - Run acceptance tests directly

### Code Quality
- `composer run analyse` - Run PHPStan static analysis (level 9)
- `composer run cs-fix` - Run PHP CS Fixer for code style fixes
- `composer run checks` - Run all checks (analysis, code style, and all tests)

### PHPUnit Configuration
- Integration and acceptance tests use Pest framework
- Test configuration in `phpunit.xml.dist`
- Test helpers available in `tests/acceptance/Pest.php` and `tests/integration/Pest.php`

## Architecture Overview

### Core Client Structure
The library follows a factory-based architecture with dependency injection:

- **Client Entry Point**: `TrueLayer\Client::configure()` returns a `ClientConfigInterface` for fluent configuration
- **Client Factory**: `ClientFactory` creates the main `Client` instance with all dependencies
- **API Client**: Decorated with middleware for authentication, signing, retries, and idempotency
- **Entity Factory**: Creates domain entities from API responses
- **API Factory**: Creates API service instances (payments, payouts, merchant accounts, webhooks)

### Key Components

#### API Client Decorators (Applied in Order)
1. `AccessTokenDecorator` - Handles OAuth2 authentication
2. `ExponentialBackoffDecorator` - Implements retry logic with backoff
3. `SigningDecorator` - Signs requests using TrueLayer's signing library
4. `IdempotencyKeyDecorator` - Manages idempotency keys for safe retries
5. `TLAgentDecorator` - Adds user agent headers

#### Domain Entities
- **Payments**: Payment creation, retrieval, authorization flows, refunds
- **Payouts**: External account payouts, business account payouts, payment source refunds
- **Merchant Accounts**: Account management and balance retrieval
- **Webhooks**: Event handling with signature verification
- **Account Identifiers**: Support for IBAN, SCAN, NRB, BBAN account types

#### Builder Pattern Usage
The library extensively uses builders for complex entity creation:
- `BeneficiaryBuilder` for payment beneficiaries
- `PaymentMethodBuilder` for payment methods
- `ProviderSelectionBuilder` for provider filtering
- `SchemeSelectionBuilder` for payment scheme selection

### Configuration and Environment
- Supports both sandbox and production environments
- Configurable via environment variables or programmatic setup
- Optional caching support for OAuth tokens (PSR-16 compatible)
- Requires PSR-18 HTTP client implementation

### Security Features
- Request signing using private keys (EC512 supported)
- Webhook signature verification
- OAuth2 client credentials flow
- Encrypted token caching when cache is enabled

### Constants and Enums
Located in `src/Constants/` directory:
- Payment statuses, currencies, countries
- Webhook event types
- API endpoints and HTTP methods
- Account identifier types and schemes

### Error Handling
Custom exceptions in `src/Exceptions/`:
- `ApiResponseUnsuccessfulException` for API errors
- `SignerException` for signing failures
- `WebhookVerificationFailedException` for webhook security
- All extend base `Exception` class

### API Reference
- Use `Payments_API_V3_specs` file as the Payments API specs reference (as noted in CLAUDE.local.md)
- Comprehensive examples available in README.md for all major operations

## Testing Notes
- Acceptance tests require environment variables in `.env` file
- Integration tests use mocked HTTP responses
- Test helpers available for common operations like payment creation
- Mock responses and test utilities in `tests/integration/Mocks/`
6 changes: 6 additions & 0 deletions config/bindings.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,11 @@
Interfaces\SignupPlus\SignupPlusUserDataRequestInterface::class => Entities\SignupPlus\SignupPlusUserDataRequest::class,
Interfaces\SignupPlus\SignupPlusUserDataRetrievedInterface::class => Entities\SignupPlus\SignupPlusUserDataRetrieved::class,

Interfaces\PaymentsProvider\SearchProvidersRequestBuilderInterface::class => Entities\PaymentsProvider\SearchProvidersRequestBuilder::class,
Interfaces\PaymentsProvider\SearchProvidersRequestInterface::class => Entities\PaymentsProvider\SearchProvidersRequest::class,
Interfaces\PaymentsProvider\AuthorizationFlowConfigurationInterface::class => Entities\PaymentsProvider\AuthorizationFlowConfiguration::class,
Interfaces\PaymentsProvider\SearchCapabilitiesInterface::class => Entities\PaymentsProvider\SearchCapabilities::class,
Interfaces\PaymentsProvider\PaymentsProviderInterface::class => Entities\PaymentsProvider\PaymentsProvider::class,

Interfaces\RequestOptionsInterface::class => Entities\RequestOptions::class,
];
1 change: 1 addition & 0 deletions src/Constants/Endpoints.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Endpoints
public const PAYMENTS_REFUNDS_RETRIEVE_ALL = '/v3/payments/{id}/refunds';
public const PAYMENTS_REFUNDS_RETRIEVE = '/v3/payments/{id}/refunds/{refund_id}';
public const PAYMENTS_PROVIDER_RETURN = '/v3/payments-provider-return';
public const PAYMENTS_PROVIDERS_SEARCH = '/v3/payments-providers/search';

public const MERCHANT_ACCOUNTS = '/v3/merchant-accounts';
public const TRANSACTIONS = '/v3/merchant-accounts/{id}/transactions';
Expand Down
105 changes: 105 additions & 0 deletions src/Entities/PaymentsProvider/AuthorizationFlowConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

declare(strict_types=1);

namespace TrueLayer\Entities\PaymentsProvider;

use TrueLayer\Entities\Entity;
use TrueLayer\Interfaces\PaymentsProvider\AuthorizationFlowConfigurationInterface;

class AuthorizationFlowConfiguration extends Entity implements AuthorizationFlowConfigurationInterface
{
/**
* @var array<string, mixed>|\stdClass
*/
protected $redirect;

/**
* @var array<string, mixed>|\stdClass
*/
protected $providerSelection;

/**
* @var array<string, mixed>
*/
protected array $form;

/**
* @var array<string, mixed>
*/
protected array $consent;

/**
* @var array<string>
*/
protected array $arrayFields = [
'redirect',
'provider_selection',
'form',
'consent',
];

/**
* @return $this
*/
public function redirect(): self
{
$this->redirect = (object) [];

return $this;
}

/**
* @return $this
*/
public function providerSelection(): self
{
$this->providerSelection = (object) [];

return $this;
}

/**
* @param string $size
*
* @return $this
*/
public function providerSelectionWithIcon(string $size): self
{
$this->providerSelection = [
'icon' => [
'size' => $size,
],
];

return $this;
}

/**
* @param string[] $inputTypes
*
* @return $this
*/
public function form(array $inputTypes): self
{
$this->form = [
'input_types' => $inputTypes,
];

return $this;
}

/**
* @param string $requirements
*
* @return $this
*/
public function consent(string $requirements): self
{
$this->consent = [
'requirements' => $requirements,
];

return $this;
}
}
143 changes: 143 additions & 0 deletions src/Entities/PaymentsProvider/PaymentsProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?php

declare(strict_types=1);

namespace TrueLayer\Entities\PaymentsProvider;

use TrueLayer\Entities\Entity;
use TrueLayer\Interfaces\PaymentsProvider\PaymentsProviderInterface;

class PaymentsProvider extends Entity implements PaymentsProviderInterface
{
/**
* @var string
*/
protected string $id;

/**
* @var string|null
*/
protected ?string $displayName = null;

/**
* @var string|null
*/
protected ?string $iconUri = null;

/**
* @var string|null
*/
protected ?string $logoUri = null;

/**
* @var string|null
*/
protected ?string $bgColor = null;

/**
* @var string|null
*/
protected ?string $countryCode = null;

/**
* @var string|null
*/
protected ?string $swiftCode = null;

/**
* @var mixed[]
*/
protected array $capabilities = [];

/**
* @var mixed[]|null
*/
protected ?array $binRanges = null;

/**
* @var array<string>
*/
protected array $arrayFields = [
'id',
'display_name',
'icon_uri',
'logo_uri',
'bg_color',
'country_code',
'swift_code',
'capabilities',
'bin_ranges',
];

/**
* @return string
*/
public function getId(): string
{
return $this->id;
}

/**
* @return string|null
*/
public function getDisplayName(): ?string
{
return $this->displayName;
}

/**
* @return string|null
*/
public function getIconUri(): ?string
{
return $this->iconUri;
}

/**
* @return string|null
*/
public function getLogoUri(): ?string
{
return $this->logoUri;
}

/**
* @return string|null
*/
public function getBgColor(): ?string
{
return $this->bgColor;
}

/**
* @return string|null
*/
public function getCountryCode(): ?string
{
return $this->countryCode;
}

/**
* @return string|null
*/
public function getSwiftCode(): ?string
{
return $this->swiftCode;
}

/**
* @return mixed[]
*/
public function getCapabilities(): array
{
return $this->capabilities;
}

/**
* @return mixed[]|null
*/
public function getBinRanges(): ?array
{
return $this->binRanges;
}
}
Loading