Skip to content

Commit dd34c08

Browse files
Changes generated by 0fe868312ff4790bf641573f71b0ec4478393e43
This commit was automatically created from gocardless/gocardless-pro-php-template@0fe8683 by the `push-files` action. Workflow run: https://github.com/gocardless/gocardless-pro-php-template/actions/runs/12713595863
1 parent dde41d5 commit dd34c08

32 files changed

+317
-83
lines changed

lib/Services/BillingRequestsService.php

+70
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,76 @@ public function create($params = array())
6262
return $this->getResourceForResponse($response);
6363
}
6464

65+
/**
66+
* [ACH/PAD only] Create a Billing Request with instalments (with dates)
67+
*
68+
* Example URL: /billing_requests
69+
*
70+
* @param array<string, mixed> $params An associative array for any params
71+
* @return BillingRequest
72+
**/
73+
public function createWithInstalmentsWithDates($params = array())
74+
{
75+
$path = "/billing_requests";
76+
if(isset($params['params'])) {
77+
$params['body'] = json_encode(array($this->envelope_key => (object)$params['params']));
78+
79+
unset($params['params']);
80+
}
81+
82+
83+
try {
84+
$response = $this->api_client->post($path, $params);
85+
} catch(InvalidStateException $e) {
86+
if ($e->isIdempotentCreationConflict()) {
87+
if ($this->api_client->error_on_idempotency_conflict) {
88+
throw $e;
89+
}
90+
return $this->get($e->getConflictingResourceId());
91+
}
92+
93+
throw $e;
94+
}
95+
96+
97+
return $this->getResourceForResponse($response);
98+
}
99+
100+
/**
101+
* [ACH/PAD only] Create a Billing Request with instalments (with schedule)
102+
*
103+
* Example URL: /billing_requests
104+
*
105+
* @param array<string, mixed> $params An associative array for any params
106+
* @return BillingRequest
107+
**/
108+
public function createWithInstalmentsWithSchedule($params = array())
109+
{
110+
$path = "/billing_requests";
111+
if(isset($params['params'])) {
112+
$params['body'] = json_encode(array($this->envelope_key => (object)$params['params']));
113+
114+
unset($params['params']);
115+
}
116+
117+
118+
try {
119+
$response = $this->api_client->post($path, $params);
120+
} catch(InvalidStateException $e) {
121+
if ($e->isIdempotentCreationConflict()) {
122+
if ($this->api_client->error_on_idempotency_conflict) {
123+
throw $e;
124+
}
125+
return $this->get($e->getConflictingResourceId());
126+
}
127+
128+
throw $e;
129+
}
130+
131+
132+
return $this->getResourceForResponse($response);
133+
}
134+
65135
/**
66136
* Collect customer details
67137
*

tests/Integration/BillingRequestsIntegrationTest.php

+152
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,158 @@ public function testBillingRequestsCreateWithIdempotencyConflict()
9090
$this->assertEquals($getRequest->getUri()->getPath(), '/billing_requests/ID123');
9191
}
9292

93+
public function testBillingRequestsCreateWithInstalmentsWithDates()
94+
{
95+
$fixture = $this->loadJsonFixture('billing_requests')->create_with_instalments_with_dates;
96+
$this->stub_request($fixture);
97+
98+
$service = $this->client->billingRequests();
99+
$response = call_user_func_array(array($service, 'createWithInstalmentsWithDates'), (array)$fixture->url_params);
100+
101+
$body = $fixture->body->billing_requests;
102+
103+
$this->assertInstanceOf('\GoCardlessPro\Resources\BillingRequest', $response);
104+
105+
$this->assertEquals($body->actions, $response->actions);
106+
$this->assertEquals($body->created_at, $response->created_at);
107+
$this->assertEquals($body->fallback_enabled, $response->fallback_enabled);
108+
$this->assertEquals($body->fallback_occurred, $response->fallback_occurred);
109+
$this->assertEquals($body->id, $response->id);
110+
$this->assertEquals($body->instalment_schedule_request, $response->instalment_schedule_request);
111+
$this->assertEquals($body->links, $response->links);
112+
$this->assertEquals($body->mandate_request, $response->mandate_request);
113+
$this->assertEquals($body->metadata, $response->metadata);
114+
$this->assertEquals($body->payment_request, $response->payment_request);
115+
$this->assertEquals($body->purpose_code, $response->purpose_code);
116+
$this->assertEquals($body->resources, $response->resources);
117+
$this->assertEquals($body->status, $response->status);
118+
$this->assertEquals($body->subscription_request, $response->subscription_request);
119+
120+
121+
$expectedPathRegex = $this->extract_resource_fixture_path_regex($fixture);
122+
$dispatchedRequest = $this->history[0]['request'];
123+
$this->assertMatchesRegularExpression($expectedPathRegex, $dispatchedRequest->getUri()->getPath());
124+
}
125+
126+
public function testBillingRequestsCreateWithInstalmentsWithDatesWithIdempotencyConflict()
127+
{
128+
$fixture = $this->loadJsonFixture('billing_requests')->create_with_instalments_with_dates;
129+
130+
$idempotencyConflictResponseFixture = $this->loadFixture('idempotent_creation_conflict_invalid_state_error');
131+
132+
// The POST request responds with a 409 to our original POST, due to an idempotency conflict
133+
$this->mock->append(new \GuzzleHttp\Psr7\Response(409, [], $idempotencyConflictResponseFixture));
134+
135+
// The client makes a second request to fetch the resource that was already
136+
// created using our idempotency key. It responds with the created resource,
137+
// which looks just like the response for a successful POST request.
138+
$this->mock->append(new \GuzzleHttp\Psr7\Response(200, [], json_encode($fixture->body)));
139+
140+
$service = $this->client->billingRequests();
141+
$response = call_user_func_array(array($service, 'createWithInstalmentsWithDates'), (array)$fixture->url_params);
142+
$body = $fixture->body->billing_requests;
143+
144+
$this->assertInstanceOf('\GoCardlessPro\Resources\BillingRequest', $response);
145+
146+
$this->assertEquals($body->actions, $response->actions);
147+
$this->assertEquals($body->created_at, $response->created_at);
148+
$this->assertEquals($body->fallback_enabled, $response->fallback_enabled);
149+
$this->assertEquals($body->fallback_occurred, $response->fallback_occurred);
150+
$this->assertEquals($body->id, $response->id);
151+
$this->assertEquals($body->instalment_schedule_request, $response->instalment_schedule_request);
152+
$this->assertEquals($body->links, $response->links);
153+
$this->assertEquals($body->mandate_request, $response->mandate_request);
154+
$this->assertEquals($body->metadata, $response->metadata);
155+
$this->assertEquals($body->payment_request, $response->payment_request);
156+
$this->assertEquals($body->purpose_code, $response->purpose_code);
157+
$this->assertEquals($body->resources, $response->resources);
158+
$this->assertEquals($body->status, $response->status);
159+
$this->assertEquals($body->subscription_request, $response->subscription_request);
160+
161+
162+
$expectedPathRegex = $this->extract_resource_fixture_path_regex($fixture);
163+
$conflictRequest = $this->history[0]['request'];
164+
$this->assertMatchesRegularExpression($expectedPathRegex, $conflictRequest->getUri()->getPath());
165+
$getRequest = $this->history[1]['request'];
166+
$this->assertEquals($getRequest->getUri()->getPath(), '/billing_requests/ID123');
167+
}
168+
169+
public function testBillingRequestsCreateWithInstalmentsWithSchedule()
170+
{
171+
$fixture = $this->loadJsonFixture('billing_requests')->create_with_instalments_with_schedule;
172+
$this->stub_request($fixture);
173+
174+
$service = $this->client->billingRequests();
175+
$response = call_user_func_array(array($service, 'createWithInstalmentsWithSchedule'), (array)$fixture->url_params);
176+
177+
$body = $fixture->body->billing_requests;
178+
179+
$this->assertInstanceOf('\GoCardlessPro\Resources\BillingRequest', $response);
180+
181+
$this->assertEquals($body->actions, $response->actions);
182+
$this->assertEquals($body->created_at, $response->created_at);
183+
$this->assertEquals($body->fallback_enabled, $response->fallback_enabled);
184+
$this->assertEquals($body->fallback_occurred, $response->fallback_occurred);
185+
$this->assertEquals($body->id, $response->id);
186+
$this->assertEquals($body->instalment_schedule_request, $response->instalment_schedule_request);
187+
$this->assertEquals($body->links, $response->links);
188+
$this->assertEquals($body->mandate_request, $response->mandate_request);
189+
$this->assertEquals($body->metadata, $response->metadata);
190+
$this->assertEquals($body->payment_request, $response->payment_request);
191+
$this->assertEquals($body->purpose_code, $response->purpose_code);
192+
$this->assertEquals($body->resources, $response->resources);
193+
$this->assertEquals($body->status, $response->status);
194+
$this->assertEquals($body->subscription_request, $response->subscription_request);
195+
196+
197+
$expectedPathRegex = $this->extract_resource_fixture_path_regex($fixture);
198+
$dispatchedRequest = $this->history[0]['request'];
199+
$this->assertMatchesRegularExpression($expectedPathRegex, $dispatchedRequest->getUri()->getPath());
200+
}
201+
202+
public function testBillingRequestsCreateWithInstalmentsWithScheduleWithIdempotencyConflict()
203+
{
204+
$fixture = $this->loadJsonFixture('billing_requests')->create_with_instalments_with_schedule;
205+
206+
$idempotencyConflictResponseFixture = $this->loadFixture('idempotent_creation_conflict_invalid_state_error');
207+
208+
// The POST request responds with a 409 to our original POST, due to an idempotency conflict
209+
$this->mock->append(new \GuzzleHttp\Psr7\Response(409, [], $idempotencyConflictResponseFixture));
210+
211+
// The client makes a second request to fetch the resource that was already
212+
// created using our idempotency key. It responds with the created resource,
213+
// which looks just like the response for a successful POST request.
214+
$this->mock->append(new \GuzzleHttp\Psr7\Response(200, [], json_encode($fixture->body)));
215+
216+
$service = $this->client->billingRequests();
217+
$response = call_user_func_array(array($service, 'createWithInstalmentsWithSchedule'), (array)$fixture->url_params);
218+
$body = $fixture->body->billing_requests;
219+
220+
$this->assertInstanceOf('\GoCardlessPro\Resources\BillingRequest', $response);
221+
222+
$this->assertEquals($body->actions, $response->actions);
223+
$this->assertEquals($body->created_at, $response->created_at);
224+
$this->assertEquals($body->fallback_enabled, $response->fallback_enabled);
225+
$this->assertEquals($body->fallback_occurred, $response->fallback_occurred);
226+
$this->assertEquals($body->id, $response->id);
227+
$this->assertEquals($body->instalment_schedule_request, $response->instalment_schedule_request);
228+
$this->assertEquals($body->links, $response->links);
229+
$this->assertEquals($body->mandate_request, $response->mandate_request);
230+
$this->assertEquals($body->metadata, $response->metadata);
231+
$this->assertEquals($body->payment_request, $response->payment_request);
232+
$this->assertEquals($body->purpose_code, $response->purpose_code);
233+
$this->assertEquals($body->resources, $response->resources);
234+
$this->assertEquals($body->status, $response->status);
235+
$this->assertEquals($body->subscription_request, $response->subscription_request);
236+
237+
238+
$expectedPathRegex = $this->extract_resource_fixture_path_regex($fixture);
239+
$conflictRequest = $this->history[0]['request'];
240+
$this->assertMatchesRegularExpression($expectedPathRegex, $conflictRequest->getUri()->getPath());
241+
$getRequest = $this->history[1]['request'];
242+
$this->assertEquals($getRequest->getUri()->getPath(), '/billing_requests/ID123');
243+
}
244+
93245
public function testBillingRequestsCollectCustomerDetails()
94246
{
95247
$fixture = $this->loadJsonFixture('billing_requests')->collect_customer_details;

tests/fixtures/bank_authorisations.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
"method": "POST",
44
"path_template": "/bank_authorisations",
55
"url_params": {},
6-
"body": {"bank_authorisations":{"authorisation_type":"example authorisation_type 8081","authorised_at":"2020-01-01T12:00:00.000Z","created_at":"2024-12-20T09:38:46.389Z","expires_at":"2024-12-20T09:38:46.389Z","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"}}
6+
"body": {"bank_authorisations":{"authorisation_type":"example authorisation_type 8081","authorised_at":"2020-01-01T12:00:00.000Z","created_at":"2025-01-10T16:45:29.221Z","expires_at":"2025-01-10T16:45:29.221Z","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"}}
77
},
88
"get": {
99
"method": "GET",
1010
"path_template": "/bank_authorisations/:identity",
1111
"url_params": {"identity": "BAU123"},
12-
"body": {"bank_authorisations":{"authorisation_type":"example authorisation_type 7887","authorised_at":"2020-01-01T12:00:00.000Z","created_at":"2024-12-20T09:38:46.389Z","expires_at":"2024-12-20T09:38:46.389Z","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"}}
12+
"body": {"bank_authorisations":{"authorisation_type":"example authorisation_type 7887","authorised_at":"2020-01-01T12:00:00.000Z","created_at":"2025-01-10T16:45:29.221Z","expires_at":"2025-01-10T16:45:29.221Z","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"}}
1313
}
1414
}
1515

tests/fixtures/billing_request_flows.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
"method": "POST",
44
"path_template": "/billing_request_flows",
55
"url_params": {},
6-
"body": {"billing_request_flows":{"authorisation_url":"https://monzo.com/abc-123-things","auto_fulfil":false,"created_at":"2024-12-20T09:38:46.401Z","customer_details_captured":true,"exit_uri":"https://my-website.com/abc/callback","expires_at":"2024-12-20T09:38:46.401Z","id":"BRF123","language":"en","links":{"billing_request":"BRQ123"},"lock_bank_account":true,"lock_currency":true,"lock_customer_details":false,"prefilled_bank_account":{"account_type":"savings"},"prefilled_customer":{"address_line1":"221B Baker Street","address_line2":"Marylebone","address_line3":"City of Westminster","city":"London","company_name":"Hamilton Trading Ltd.","country_code":"GB","danish_identity_number":"220550-6218","email":"[email protected]","family_name":"Osborne","given_name":"Frank","postal_code":"NW1 6XE","region":"Greater London","swedish_identity_number":"556564-5404"},"redirect_uri":"https://my-website.com/abc/callback","session_token":"sesh_123","show_redirect_buttons":true,"show_success_redirect_button":false,"skip_success_screen":false}}
6+
"body": {"billing_request_flows":{"authorisation_url":"https://monzo.com/abc-123-things","auto_fulfil":true,"created_at":"2025-01-10T16:45:29.226Z","customer_details_captured":true,"exit_uri":"https://my-website.com/abc/callback","expires_at":"2025-01-10T16:45:29.226Z","id":"BRF123","language":"en","links":{"billing_request":"BRQ123"},"lock_bank_account":false,"lock_currency":false,"lock_customer_details":false,"prefilled_bank_account":{"account_type":"savings"},"prefilled_customer":{"address_line1":"221B Baker Street","address_line2":"Marylebone","address_line3":"City of Westminster","city":"London","company_name":"Hamilton Trading Ltd.","country_code":"GB","danish_identity_number":"220550-6218","email":"[email protected]","family_name":"Osborne","given_name":"Frank","postal_code":"NW1 6XE","region":"Greater London","swedish_identity_number":"556564-5404"},"redirect_uri":"https://my-website.com/abc/callback","session_token":"sesh_123","show_redirect_buttons":true,"show_success_redirect_button":true,"skip_success_screen":false}}
77
},
88
"initialise": {
99
"method": "POST",
1010
"path_template": "/billing_request_flows/:identity/actions/initialise",
1111
"url_params": {"identity": "BRF123"},
12-
"body": {"billing_request_flows":{"authorisation_url":"https://monzo.com/abc-123-things","auto_fulfil":true,"created_at":"2024-12-20T09:38:46.401Z","customer_details_captured":true,"exit_uri":"https://my-website.com/abc/callback","expires_at":"2024-12-20T09:38:46.401Z","id":"BRF123","language":"en","links":{"billing_request":"BRQ123"},"lock_bank_account":false,"lock_currency":false,"lock_customer_details":true,"prefilled_bank_account":{"account_type":"savings"},"prefilled_customer":{"address_line1":"221B Baker Street","address_line2":"Marylebone","address_line3":"City of Westminster","city":"London","company_name":"Hamilton Trading Ltd.","country_code":"GB","danish_identity_number":"220550-6218","email":"[email protected]","family_name":"Osborne","given_name":"Frank","postal_code":"NW1 6XE","region":"Greater London","swedish_identity_number":"556564-5404"},"redirect_uri":"https://my-website.com/abc/callback","session_token":"sesh_123","show_redirect_buttons":false,"show_success_redirect_button":true,"skip_success_screen":false}}
12+
"body": {"billing_request_flows":{"authorisation_url":"https://monzo.com/abc-123-things","auto_fulfil":false,"created_at":"2025-01-10T16:45:29.227Z","customer_details_captured":false,"exit_uri":"https://my-website.com/abc/callback","expires_at":"2025-01-10T16:45:29.227Z","id":"BRF123","language":"en","links":{"billing_request":"BRQ123"},"lock_bank_account":false,"lock_currency":true,"lock_customer_details":false,"prefilled_bank_account":{"account_type":"savings"},"prefilled_customer":{"address_line1":"221B Baker Street","address_line2":"Marylebone","address_line3":"City of Westminster","city":"London","company_name":"Hamilton Trading Ltd.","country_code":"GB","danish_identity_number":"220550-6218","email":"[email protected]","family_name":"Osborne","given_name":"Frank","postal_code":"NW1 6XE","region":"Greater London","swedish_identity_number":"556564-5404"},"redirect_uri":"https://my-website.com/abc/callback","session_token":"sesh_123","show_redirect_buttons":true,"show_success_redirect_button":true,"skip_success_screen":true}}
1313
}
1414
}
1515

0 commit comments

Comments
 (0)