Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes from gocardless/gocardless-pro-php-template #196

Merged
merged 10 commits into from
Jan 28, 2025
Merged
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
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "gocardless/gocardless-pro",
"description": "GoCardless Pro PHP Client Library",
"version": "6.1.0",
"version": "6.2.0",
"keywords": [
"gocardless",
"direct debit",
Expand Down
4 changes: 2 additions & 2 deletions lib/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function __construct($config)
'Content-Type' => 'application/json',
'Authorization' => "Bearer " . $access_token,
'GoCardless-Client-Library' => 'gocardless-pro-php',
'GoCardless-Client-Version' => '6.1.0',
'GoCardless-Client-Version' => '6.2.0',
'User-Agent' => $this->getUserAgent()
),
'http_errors' => false,
Expand Down Expand Up @@ -664,7 +664,7 @@ private function getUserAgent()
{
$curlinfo = curl_version();
$uagent = array();
$uagent[] = 'gocardless-pro-php/6.1.0';
$uagent[] = 'gocardless-pro-php/6.2.0';
$uagent[] = 'schema-version/2015-07-06';
if (defined('\GuzzleHttp\Client::MAJOR_VERSION')) {
$uagent[] = 'GuzzleHttp/' . \GuzzleHttp\Client::MAJOR_VERSION;
Expand Down
6 changes: 6 additions & 0 deletions lib/Resources/MandateImportEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*
* @property-read mixed $created_at
* @property-read mixed $links
* @property-read mixed $processing_errors
* @property-read mixed $record_identifier
*/
class MandateImportEntry extends BaseResource
Expand All @@ -30,6 +31,11 @@ class MandateImportEntry extends BaseResource
*/
protected $links;

/**
* Per-resource processing errors
*/
protected $processing_errors;

/**
* A unique identifier for this entry, which you can use (once the import
* has been
Expand Down
70 changes: 70 additions & 0 deletions lib/Services/BillingRequestsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,76 @@ public function create($params = array())
return $this->getResourceForResponse($response);
}

/**
* [ACH/PAD only] Create a Billing Request with instalments (with dates)
*
* Example URL: /billing_requests
*
* @param array<string, mixed> $params An associative array for any params
* @return BillingRequest
**/
public function createWithInstalmentsWithDates($params = array())
{
$path = "/billing_requests";
if(isset($params['params'])) {
$params['body'] = json_encode(array($this->envelope_key => (object)$params['params']));

unset($params['params']);
}


try {
$response = $this->api_client->post($path, $params);
} catch(InvalidStateException $e) {
if ($e->isIdempotentCreationConflict()) {
if ($this->api_client->error_on_idempotency_conflict) {
throw $e;
}
return $this->get($e->getConflictingResourceId());
}

throw $e;
}


return $this->getResourceForResponse($response);
}

/**
* [ACH/PAD only] Create a Billing Request with instalments (with schedule)
*
* Example URL: /billing_requests
*
* @param array<string, mixed> $params An associative array for any params
* @return BillingRequest
**/
public function createWithInstalmentsWithSchedule($params = array())
{
$path = "/billing_requests";
if(isset($params['params'])) {
$params['body'] = json_encode(array($this->envelope_key => (object)$params['params']));

unset($params['params']);
}


try {
$response = $this->api_client->post($path, $params);
} catch(InvalidStateException $e) {
if ($e->isIdempotentCreationConflict()) {
if ($this->api_client->error_on_idempotency_conflict) {
throw $e;
}
return $this->get($e->getConflictingResourceId());
}

throw $e;
}


return $this->getResourceForResponse($response);
}

/**
* Collect customer details
*
Expand Down
152 changes: 152 additions & 0 deletions tests/Integration/BillingRequestsIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,158 @@ public function testBillingRequestsCreateWithIdempotencyConflict()
$this->assertEquals($getRequest->getUri()->getPath(), '/billing_requests/ID123');
}

public function testBillingRequestsCreateWithInstalmentsWithDates()
{
$fixture = $this->loadJsonFixture('billing_requests')->create_with_instalments_with_dates;
$this->stub_request($fixture);

$service = $this->client->billingRequests();
$response = call_user_func_array(array($service, 'createWithInstalmentsWithDates'), (array)$fixture->url_params);

$body = $fixture->body->billing_requests;

$this->assertInstanceOf('\GoCardlessPro\Resources\BillingRequest', $response);

$this->assertEquals($body->actions, $response->actions);
$this->assertEquals($body->created_at, $response->created_at);
$this->assertEquals($body->fallback_enabled, $response->fallback_enabled);
$this->assertEquals($body->fallback_occurred, $response->fallback_occurred);
$this->assertEquals($body->id, $response->id);
$this->assertEquals($body->instalment_schedule_request, $response->instalment_schedule_request);
$this->assertEquals($body->links, $response->links);
$this->assertEquals($body->mandate_request, $response->mandate_request);
$this->assertEquals($body->metadata, $response->metadata);
$this->assertEquals($body->payment_request, $response->payment_request);
$this->assertEquals($body->purpose_code, $response->purpose_code);
$this->assertEquals($body->resources, $response->resources);
$this->assertEquals($body->status, $response->status);
$this->assertEquals($body->subscription_request, $response->subscription_request);


$expectedPathRegex = $this->extract_resource_fixture_path_regex($fixture);
$dispatchedRequest = $this->history[0]['request'];
$this->assertMatchesRegularExpression($expectedPathRegex, $dispatchedRequest->getUri()->getPath());
}

public function testBillingRequestsCreateWithInstalmentsWithDatesWithIdempotencyConflict()
{
$fixture = $this->loadJsonFixture('billing_requests')->create_with_instalments_with_dates;

$idempotencyConflictResponseFixture = $this->loadFixture('idempotent_creation_conflict_invalid_state_error');

// The POST request responds with a 409 to our original POST, due to an idempotency conflict
$this->mock->append(new \GuzzleHttp\Psr7\Response(409, [], $idempotencyConflictResponseFixture));

// The client makes a second request to fetch the resource that was already
// created using our idempotency key. It responds with the created resource,
// which looks just like the response for a successful POST request.
$this->mock->append(new \GuzzleHttp\Psr7\Response(200, [], json_encode($fixture->body)));

$service = $this->client->billingRequests();
$response = call_user_func_array(array($service, 'createWithInstalmentsWithDates'), (array)$fixture->url_params);
$body = $fixture->body->billing_requests;

$this->assertInstanceOf('\GoCardlessPro\Resources\BillingRequest', $response);

$this->assertEquals($body->actions, $response->actions);
$this->assertEquals($body->created_at, $response->created_at);
$this->assertEquals($body->fallback_enabled, $response->fallback_enabled);
$this->assertEquals($body->fallback_occurred, $response->fallback_occurred);
$this->assertEquals($body->id, $response->id);
$this->assertEquals($body->instalment_schedule_request, $response->instalment_schedule_request);
$this->assertEquals($body->links, $response->links);
$this->assertEquals($body->mandate_request, $response->mandate_request);
$this->assertEquals($body->metadata, $response->metadata);
$this->assertEquals($body->payment_request, $response->payment_request);
$this->assertEquals($body->purpose_code, $response->purpose_code);
$this->assertEquals($body->resources, $response->resources);
$this->assertEquals($body->status, $response->status);
$this->assertEquals($body->subscription_request, $response->subscription_request);


$expectedPathRegex = $this->extract_resource_fixture_path_regex($fixture);
$conflictRequest = $this->history[0]['request'];
$this->assertMatchesRegularExpression($expectedPathRegex, $conflictRequest->getUri()->getPath());
$getRequest = $this->history[1]['request'];
$this->assertEquals($getRequest->getUri()->getPath(), '/billing_requests/ID123');
}

public function testBillingRequestsCreateWithInstalmentsWithSchedule()
{
$fixture = $this->loadJsonFixture('billing_requests')->create_with_instalments_with_schedule;
$this->stub_request($fixture);

$service = $this->client->billingRequests();
$response = call_user_func_array(array($service, 'createWithInstalmentsWithSchedule'), (array)$fixture->url_params);

$body = $fixture->body->billing_requests;

$this->assertInstanceOf('\GoCardlessPro\Resources\BillingRequest', $response);

$this->assertEquals($body->actions, $response->actions);
$this->assertEquals($body->created_at, $response->created_at);
$this->assertEquals($body->fallback_enabled, $response->fallback_enabled);
$this->assertEquals($body->fallback_occurred, $response->fallback_occurred);
$this->assertEquals($body->id, $response->id);
$this->assertEquals($body->instalment_schedule_request, $response->instalment_schedule_request);
$this->assertEquals($body->links, $response->links);
$this->assertEquals($body->mandate_request, $response->mandate_request);
$this->assertEquals($body->metadata, $response->metadata);
$this->assertEquals($body->payment_request, $response->payment_request);
$this->assertEquals($body->purpose_code, $response->purpose_code);
$this->assertEquals($body->resources, $response->resources);
$this->assertEquals($body->status, $response->status);
$this->assertEquals($body->subscription_request, $response->subscription_request);


$expectedPathRegex = $this->extract_resource_fixture_path_regex($fixture);
$dispatchedRequest = $this->history[0]['request'];
$this->assertMatchesRegularExpression($expectedPathRegex, $dispatchedRequest->getUri()->getPath());
}

public function testBillingRequestsCreateWithInstalmentsWithScheduleWithIdempotencyConflict()
{
$fixture = $this->loadJsonFixture('billing_requests')->create_with_instalments_with_schedule;

$idempotencyConflictResponseFixture = $this->loadFixture('idempotent_creation_conflict_invalid_state_error');

// The POST request responds with a 409 to our original POST, due to an idempotency conflict
$this->mock->append(new \GuzzleHttp\Psr7\Response(409, [], $idempotencyConflictResponseFixture));

// The client makes a second request to fetch the resource that was already
// created using our idempotency key. It responds with the created resource,
// which looks just like the response for a successful POST request.
$this->mock->append(new \GuzzleHttp\Psr7\Response(200, [], json_encode($fixture->body)));

$service = $this->client->billingRequests();
$response = call_user_func_array(array($service, 'createWithInstalmentsWithSchedule'), (array)$fixture->url_params);
$body = $fixture->body->billing_requests;

$this->assertInstanceOf('\GoCardlessPro\Resources\BillingRequest', $response);

$this->assertEquals($body->actions, $response->actions);
$this->assertEquals($body->created_at, $response->created_at);
$this->assertEquals($body->fallback_enabled, $response->fallback_enabled);
$this->assertEquals($body->fallback_occurred, $response->fallback_occurred);
$this->assertEquals($body->id, $response->id);
$this->assertEquals($body->instalment_schedule_request, $response->instalment_schedule_request);
$this->assertEquals($body->links, $response->links);
$this->assertEquals($body->mandate_request, $response->mandate_request);
$this->assertEquals($body->metadata, $response->metadata);
$this->assertEquals($body->payment_request, $response->payment_request);
$this->assertEquals($body->purpose_code, $response->purpose_code);
$this->assertEquals($body->resources, $response->resources);
$this->assertEquals($body->status, $response->status);
$this->assertEquals($body->subscription_request, $response->subscription_request);


$expectedPathRegex = $this->extract_resource_fixture_path_regex($fixture);
$conflictRequest = $this->history[0]['request'];
$this->assertMatchesRegularExpression($expectedPathRegex, $conflictRequest->getUri()->getPath());
$getRequest = $this->history[1]['request'];
$this->assertEquals($getRequest->getUri()->getPath(), '/billing_requests/ID123');
}

public function testBillingRequestsCollectCustomerDetails()
{
$fixture = $this->loadJsonFixture('billing_requests')->collect_customer_details;
Expand Down
5 changes: 5 additions & 0 deletions tests/Integration/MandateImportEntriesIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public function testMandateImportEntriesCreate()

$this->assertEquals($body->created_at, $response->created_at);
$this->assertEquals($body->links, $response->links);
$this->assertEquals($body->processing_errors, $response->processing_errors);
$this->assertEquals($body->record_identifier, $response->record_identifier);


Expand Down Expand Up @@ -68,6 +69,10 @@ public function testMandateImportEntriesList()
$this->assertEquals($body[$num]->links, $record->links);
}

if (isset($body[$num]->processing_errors)) {
$this->assertEquals($body[$num]->processing_errors, $record->processing_errors);
}

if (isset($body[$num]->record_identifier)) {
$this->assertEquals($body[$num]->record_identifier, $record->record_identifier);
}
Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures/bank_authorisations.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
"method": "POST",
"path_template": "/bank_authorisations",
"url_params": {},
"body": {"bank_authorisations":{"authorisation_type":"example authorisation_type 8081","authorised_at":"2020-01-01T12:00:00.000Z","created_at":"2024-12-02T16:42:36.882Z","expires_at":"2024-12-02T16:42:36.882Z","id":"BAU123","last_visited_at":"2020-01-01T12:00:00.000Z","links":{"billing_request":"BRQ123","institution":"monzo"},"qr_code_url":"https://pay.gocardless.com/obauth/BAU123/qr_code","redirect_uri":"https://my-website.com/abc/callback","url":"https://pay.gocardless.com/obauth/BAU123"}}
"body": {"bank_authorisations":{"authorisation_type":"example authorisation_type 8081","authorised_at":"2020-01-01T12:00:00.000Z","created_at":"2025-01-27T15:00:29.881Z","expires_at":"2025-01-27T15:00:29.881Z","id":"BAU123","last_visited_at":"2020-01-01T12:00:00.000Z","links":{"billing_request":"BRQ123","institution":"monzo"},"qr_code_url":"https://pay.gocardless.com/obauth/BAU123/qr_code","redirect_uri":"https://my-website.com/abc/callback","url":"https://pay.gocardless.com/obauth/BAU123"}}
},
"get": {
"method": "GET",
"path_template": "/bank_authorisations/:identity",
"url_params": {"identity": "BAU123"},
"body": {"bank_authorisations":{"authorisation_type":"example authorisation_type 7887","authorised_at":"2020-01-01T12:00:00.000Z","created_at":"2024-12-02T16:42:36.882Z","expires_at":"2024-12-02T16:42:36.882Z","id":"BAU123","last_visited_at":"2020-01-01T12:00:00.000Z","links":{"billing_request":"BRQ123","institution":"monzo"},"qr_code_url":"https://pay.gocardless.com/obauth/BAU123/qr_code","redirect_uri":"https://my-website.com/abc/callback","url":"https://pay.gocardless.com/obauth/BAU123"}}
"body": {"bank_authorisations":{"authorisation_type":"example authorisation_type 7887","authorised_at":"2020-01-01T12:00:00.000Z","created_at":"2025-01-27T15:00:29.881Z","expires_at":"2025-01-27T15:00:29.881Z","id":"BAU123","last_visited_at":"2020-01-01T12:00:00.000Z","links":{"billing_request":"BRQ123","institution":"monzo"},"qr_code_url":"https://pay.gocardless.com/obauth/BAU123/qr_code","redirect_uri":"https://my-website.com/abc/callback","url":"https://pay.gocardless.com/obauth/BAU123"}}
}
}

Loading
Loading