• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlocati / nexi / 8571051831

05 Apr 2024 02:05PM UTC coverage: 5.917% (+0.8%) from 5.079%
8571051831

push

github

mlocati
Document some of the features

111 of 1876 relevant lines covered (5.92%)

0.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Client.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace MLocati\Nexi;
6

7
use MLocati\Nexi\HttpClient\Response;
8
use MLocati\Nexi\Service\QueryEntityInterface;
9
use stdClass;
10

11
/*
12
 * WARNING: DO NOT EDIT THIS FILE
13
 * It has been generated automaticlly from a template.
14
 * Edit the template instead.
15
 */
16

17
class Client
18
{
19
    /**
20
     * @var \MLocati\Nexi\Configuration
21
     */
22
    protected $configuration;
23

24
    /**
25
     * @var \MLocati\Nexi\HttpClient
26
     */
27
    protected $httpClient;
28

29
    /**
30
     * @var \MLocati\Nexi\CorrelationProvider
31
     */
32
    protected $correlationProvider;
33

34
    /**
35
     * @var \MLocati\Nexi\Entity\Webhook\Request|null
36
     */
37
    private $notificationRequest;
38

39
    /**
40
     * @throws \MLocati\Nexi\Exception\NoHttpClient if $httpClient is NULL and no HTTP client is available
41
     */
42
    public function __construct(
43
        Configuration $configuration,
44
        ?HttpClient $httpClient = null,
45
        ?CorrelationProvider $correlationProvider = null
46
    ) {
47
        $this->configuration = $configuration;
×
48
        $this->httpClient = $httpClient ?? $this->buildHttpClient();
×
49
        $this->correlationProvider = $correlationProvider ?? $this->buildCorrelationProvider();
×
50
    }
×
51

52
    /**
53
     * @throws \MLocati\Nexi\Exception\InvalidJson is no (valid) request data is detected
54
     * @throws \MLocati\Nexi\Exception\MissingField is the received data does not contain a security token
55
     */
56
    public function getNotificationRequest(): Entity\Webhook\Request
57
    {
58
        if ($this->notificationRequest === null) {
×
59
            $data = $this->decodeJsonToObject(file_get_contents('php://input') ?: '');
×
60
            $notificationRequest = new Entity\Webhook\Request($data);
×
61
            $notificationRequest->checkRequiredFields('webhookRequest', 'receive');
×
62
            if ((string) $notificationRequest->getSecurityToken() === '') {
×
63
                throw new Exception\MissingField('securityToken');
×
64
            }
65
            $this->notificationRequest = $notificationRequest;
×
66
        }
67

68
        return $this->notificationRequest;
×
69
    }
70

71
    /**
72
     * Initiating payment through the Hosted Payment Page solution, the API returns the URL to redirect the customer to complete the transaction. For more information, please refer to the dedicated page Hosted Payment Page.
73
     *
74
     * @see https://developer.nexi.it/en/api/post-orders-hpp
75
     *
76
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
77
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
78
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
79
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
80
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
81
     * @throws \MLocati\Nexi\Exception\ErrorResponse
82
     */
83
    public function createOrderForHostedPayment(Entity\CreateOrderForHostedPayment\Request $requestBody): Entity\CreateOrderForHostedPayment\Response
84
    {
85
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
86
        $url = $this->buildUrl('/orders/hpp');
×
87
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
88
        if ($response->getStatusCode() === 200) {
×
89
            $data = $this->decodeJsonToObject($response->getBody());
×
90

91
            return new Entity\CreateOrderForHostedPayment\Response($data);
×
92
        }
93
        $this->throwErrorResponse($response, [
×
94
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
95
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
96
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
97
        ]);
98
    }
×
99

100
    /**
101
     * Generate a link to share with the customer to execute a payment. For more information, please refer to the dedicated page Pay-by-Link.
102
     *
103
     * @see https://developer.nexi.it/en/api/post-orders-paybylink
104
     *
105
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
106
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
107
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
108
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
109
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
110
     * @throws \MLocati\Nexi\Exception\ErrorResponse
111
     */
112
    public function createOrderForPayByLink(Entity\CreateOrderForPayByLink\Request $requestBody): Entity\PayByLinkResponse
113
    {
114
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
115
        $url = $this->buildUrl('/orders/paybylink');
×
116
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
117
        if ($response->getStatusCode() === 200) {
×
118
            $data = $this->decodeJsonToObject($response->getBody());
×
119

120
            return new Entity\PayByLinkResponse($data);
×
121
        }
122
        $this->throwErrorResponse($response, [
×
123
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
124
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
125
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
126
        ]);
127
    }
×
128

129
    /**
130
     * Cancel a Pay-By-Link that has not yet been paid. For more information on the Pay-by-Link solution, please refer to the dedicated page Pay-by-Link.
131
     *
132
     * @param string $linkId Unpaid Pay-By-Link ID to be canceled.
133
     *
134
     * @see https://developer.nexi.it/en/api/post-paybylink-linkId-cancels
135
     *
136
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
137
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
138
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Request rejected (HTTP code: 400)
139
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
140
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
141
     * @throws \MLocati\Nexi\Exception\ErrorResponse
142
     *
143
     * @return bool returns FALSE if not found
144
     */
145
    public function cancelPayByLink(string $linkId): bool
146
    {
147
        $url = $this->buildUrl('/paybylink/{linkId}/cancels', ['linkId' => $linkId]);
×
148
        $response = $this->invoke('POST', $url, 3);
×
149
        if ($response->getStatusCode() === 200) {
×
150
            return true;
×
151
        }
152
        if ($response->getStatusCode() === 404) {
×
153
            return false;
×
154
        }
155
        $this->throwErrorResponse($response, [
×
156
            ['from' => 400, 'to' => 400, 'description' => 'Request rejected', 'detailed' => true],
×
157
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
158
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
159
        ]);
160
    }
×
161

162
    /**
163
     * Verify registration with the 3DS protocol. This operation initiates the 2-step Server-to-Server payment flow. For more information, please refer to the dedicated page Payment 2 Steps.
164
     *
165
     * @see https://developer.nexi.it/en/api/post-orders-2steps-init
166
     *
167
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
168
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
169
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
170
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
171
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
172
     * @throws \MLocati\Nexi\Exception\ErrorResponse
173
     */
174
    public function twoSteps3DSInit(Entity\MultiStepInitRequest $requestBody): Entity\MultiStepInitResponse
175
    {
176
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
177
        $url = $this->buildUrl('/orders/2steps/init');
×
178
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
179
        if ($response->getStatusCode() === 200) {
×
180
            $data = $this->decodeJsonToObject($response->getBody());
×
181

182
            return new Entity\MultiStepInitResponse($data);
×
183
        }
184
        $this->throwErrorResponse($response, [
×
185
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
186
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
187
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
188
        ]);
189
    }
×
190

191
    /**
192
     * Payment Authorization. This completes the 2-step Server-to-Server payment flow. For more information, refer to the dedicated page Pagamento 2 Steps.
193
     *
194
     * @see https://developer.nexi.it/en/api/post-orders-2steps-payment
195
     *
196
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
197
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
198
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
199
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
200
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
201
     * @throws \MLocati\Nexi\Exception\ErrorResponse
202
     */
203
    public function twoSteps3DSPayment(Entity\MultiStepPaymentRequest $requestBody): Entity\OperationResult
204
    {
205
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
206
        $url = $this->buildUrl('/orders/2steps/payment');
×
207
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
208
        if ($response->getStatusCode() === 200) {
×
209
            $data = $this->decodeJsonToObject($response->getBody());
×
210

211
            return new Entity\OperationResult($data);
×
212
        }
213
        $this->throwErrorResponse($response, [
×
214
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
215
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
216
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
217
        ]);
218
    }
×
219

220
    /**
221
     * Verify registration with the 3DS protocol. This operation initiates the 3-step Server-to-Server payment flow. For more information, please refer to the dedicated page Payment 3 Steps.
222
     *
223
     * @see https://developer.nexi.it/en/api/post-orders-3steps-init
224
     *
225
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
226
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
227
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
228
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
229
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
230
     * @throws \MLocati\Nexi\Exception\ErrorResponse
231
     */
232
    public function threeSteps3DSInit(Entity\MultiStepInitRequest $requestBody): Entity\MultiStepInitResponse
233
    {
234
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
235
        $url = $this->buildUrl('/orders/3steps/init');
×
236
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
237
        if ($response->getStatusCode() === 200) {
×
238
            $data = $this->decodeJsonToObject($response->getBody());
×
239

240
            return new Entity\MultiStepInitResponse($data);
×
241
        }
242
        $this->throwErrorResponse($response, [
×
243
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
244
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
245
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
246
        ]);
247
    }
×
248

249
    /**
250
     * Validation of the 3DS authentication outcome. This operation is required during the 3-step Server-to-Server payment flow. For more information, please refer to the dedicated page Payment 3 Steps.
251
     *
252
     * @see https://developer.nexi.it/en/api/post-orders-3steps-validation
253
     *
254
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
255
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
256
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
257
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
258
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
259
     * @throws \MLocati\Nexi\Exception\ErrorResponse
260
     */
261
    public function threeSteps3DSValidation(Entity\ThreeSteps3DSValidation\Request $requestBody): Entity\ThreeSteps3DSValidation\Response
262
    {
263
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
264
        $url = $this->buildUrl('/orders/3steps/validation');
×
265
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
266
        if ($response->getStatusCode() === 200) {
×
267
            $data = $this->decodeJsonToObject($response->getBody());
×
268

269
            return new Entity\ThreeSteps3DSValidation\Response($data);
×
270
        }
271
        $this->throwErrorResponse($response, [
×
272
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
273
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
274
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
275
        ]);
276
    }
×
277

278
    /**
279
     * Payment authorization. This operation completes the 3-step Server-to-Server payment flow. For more information, please refer to the dedicated page Payment 3 Steps.
280
     *
281
     * @see https://developer.nexi.it/en/api/post-orders-3steps-payment
282
     *
283
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
284
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
285
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
286
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
287
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
288
     * @throws \MLocati\Nexi\Exception\ErrorResponse
289
     */
290
    public function threeSteps3DSPayment(Entity\MultiStepPaymentRequest $requestBody): Entity\OperationResult
291
    {
292
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
293
        $url = $this->buildUrl('/orders/3steps/payment');
×
294
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
295
        if ($response->getStatusCode() === 200) {
×
296
            $data = $this->decodeJsonToObject($response->getBody());
×
297

298
            return new Entity\OperationResult($data);
×
299
        }
300
        $this->throwErrorResponse($response, [
×
301
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
302
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
303
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
304
        ]);
305
    }
×
306

307
    /**
308
     * MIT (Merchant Initiated Transaction) payment, a recurring payment method used in services such as subscriptions. For more information, please refer to the dedicated page Recurring Payments.
309
     *
310
     * @param string $idempotencyKey an identifier of the request (to be used on subsequent retries); if empty, it will be set as output
311
     *
312
     * @see https://developer.nexi.it/en/api/post-orders-mit
313
     *
314
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
315
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
316
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
317
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
318
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
319
     * @throws \MLocati\Nexi\Exception\ErrorResponse
320
     */
321
    public function createOrderForMerchantInitiatedTransaction(Entity\CreateOrderForMerchantInitiatedTransaction\Request $requestBody, string &$idempotencyKey = ''): Entity\OperationResult
322
    {
323
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
324
        $url = $this->buildUrl('/orders/mit');
×
325
        $response = $this->invoke('POST', $url, 7, $requestBody, $idempotencyKey);
×
326
        if ($response->getStatusCode() === 200) {
×
327
            $data = $this->decodeJsonToObject($response->getBody());
×
328

329
            return new Entity\OperationResult($data);
×
330
        }
331
        $this->throwErrorResponse($response, [
×
332
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
333
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
334
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
335
        ]);
336
    }
×
337

338
    /**
339
     * Card verification operation, without any charge, with the sole purpose of confirming the validity of the card data entered by the customer.This API is a feature dedicated to the Server to Server integration mode, and is therefore subject to obtaining PCI DSS security certification (SAQ D questionnaire).This API is not subject to 3D Secure authentication.
340
     *
341
     * @see https://developer.nexi.it/en/api/post-orders-card_verification
342
     *
343
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
344
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
345
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
346
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
347
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
348
     * @throws \MLocati\Nexi\Exception\ErrorResponse
349
     */
350
    public function cardVerification(Entity\CardVerification\Request $requestBody): Entity\OperationResult
351
    {
352
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
353
        $url = $this->buildUrl('/orders/card_verification');
×
354
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
355
        if ($response->getStatusCode() === 200) {
×
356
            $data = $this->decodeJsonToObject($response->getBody());
×
357

358
            return new Entity\OperationResult($data);
×
359
        }
360
        $this->throwErrorResponse($response, [
×
361
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
362
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
363
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
364
        ]);
365
    }
×
366

367
    /**
368
     * Server-to-Server MOTO payment. For more information, please refer to the dedicated page M.O.T.O..
369
     *
370
     * @see https://developer.nexi.it/en/api/post-orders-moto
371
     *
372
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
373
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
374
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
375
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
376
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
377
     * @throws \MLocati\Nexi\Exception\ErrorResponse
378
     */
379
    public function createOrderForMotoPayment(Entity\CreateOrderForMotoPayment\Request $requestBody): Entity\OperationResult
380
    {
381
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
382
        $url = $this->buildUrl('/orders/moto');
×
383
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
384
        if ($response->getStatusCode() === 200) {
×
385
            $data = $this->decodeJsonToObject($response->getBody());
×
386

387
            return new Entity\OperationResult($data);
×
388
        }
389
        $this->throwErrorResponse($response, [
×
390
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
391
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
392
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
393
        ]);
394
    }
×
395

396
    /**
397
     * Server to Server payment (PCI certification required) via virtual card.
398
     *
399
     * @see https://developer.nexi.it/en/api/post-orders-virtual_card
400
     *
401
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
402
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
403
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
404
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
405
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
406
     * @throws \MLocati\Nexi\Exception\ErrorResponse
407
     */
408
    public function createVirtualCartOrder(Entity\CreateVirtualCartOrder\Request $requestBody): Entity\OperationResult
409
    {
410
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
411
        $url = $this->buildUrl('/orders/virtual_card');
×
412
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
413
        if ($response->getStatusCode() === 200) {
×
414
            $data = $this->decodeJsonToObject($response->getBody());
×
415

416
            return new Entity\OperationResult($data);
×
417
        }
418
        $this->throwErrorResponse($response, [
×
419
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
420
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
421
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
422
        ]);
423
    }
×
424

425
    /**
426
     * Create an order and initiate the payment using the XPay Build solution.
427
     * WARNING: for the proper functioning of XPay Build solution, it is necessary for the browser used to allow the use of third-party cookies.
428
     *
429
     * @see https://developer.nexi.it/en/api/post-orders-build
430
     *
431
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
432
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
433
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
434
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
435
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
436
     * @throws \MLocati\Nexi\Exception\ErrorResponse
437
     */
438
    public function createXPayBuildOrder(Entity\CreateXPayBuildOrder\Request $requestBody): Entity\FieldSet
439
    {
440
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
441
        $url = $this->buildUrl('/orders/build');
×
442
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
443
        if ($response->getStatusCode() === 200) {
×
444
            $data = $this->decodeJsonToObject($response->getBody());
×
445

446
            return new Entity\FieldSet($data);
×
447
        }
448
        $this->throwErrorResponse($response, [
×
449
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
450
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
451
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
452
        ]);
453
    }
×
454

455
    /**
456
     * Conclude a payment using the XPay Build solution.
457
     *
458
     * @see https://developer.nexi.it/en/api/post-build-finalize-payment
459
     *
460
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
461
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
462
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
463
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
464
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
465
     * @throws \MLocati\Nexi\Exception\ErrorResponse
466
     */
467
    public function finalizeXPayBuildOrder(Entity\Session $requestBody): Entity\FinalizeXPayBuildOrder\Response
468
    {
469
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
470
        $url = $this->buildUrl('/build/finalize_payment');
×
471
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
472
        if ($response->getStatusCode() === 200) {
×
473
            $data = $this->decodeJsonToObject($response->getBody());
×
474

475
            return new Entity\FinalizeXPayBuildOrder\Response($data);
×
476
        }
477
        $this->throwErrorResponse($response, [
×
478
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
479
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
480
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
481
        ]);
482
    }
×
483

484
    /**
485
     * Cancel a payment session XPay Build. Once a session is invalidated, any further submissions of requests related to the canceled session are destined to fail. Therefore, it will be necessary to invoke the API POST /orders/build for the generation of a new sessionId. This API can be applied to a payment cancellation button placed in the merchant's checkout: it is not mandatory to implement the API; in case it is not used, any session will be invalidated upon session expiration (5 minutes).
486
     *
487
     * @see https://developer.nexi.it/en/api/post-build-cancel
488
     *
489
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
490
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
491
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
492
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
493
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
494
     * @throws \MLocati\Nexi\Exception\ErrorResponse
495
     */
496
    public function cancelXPayBuildOrder(Entity\Session $requestBody): Entity\CancelXPayBuildOrder\Response
497
    {
498
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
499
        $url = $this->buildUrl('/build/cancel');
×
500
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
501
        if ($response->getStatusCode() === 200) {
×
502
            $data = $this->decodeJsonToObject($response->getBody());
×
503

504
            return new Entity\CancelXPayBuildOrder\Response($data);
×
505
        }
506
        $this->throwErrorResponse($response, [
×
507
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
508
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
509
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
510
        ]);
511
    }
×
512

513
    /**
514
     * Get current payment status via XPay Build solution.
515
     *
516
     * @see https://developer.nexi.it/en/api/get-build-state
517
     *
518
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
519
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
520
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
521
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
522
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
523
     * @throws \MLocati\Nexi\Exception\ErrorResponse
524
     */
525
    public function getXPayBuildOrderStatus(?Entity\Session $query = null): Entity\GetXPayBuildOrderStatus\Response
526
    {
527
        if ($query !== null) {
×
528
            $query->checkRequiredFields(__FUNCTION__, 'send');
×
529
        }
530
        $url = $this->buildUrl('/build/state', [], $query);
×
531
        $response = $this->invoke('GET', $url, 3);
×
532
        if ($response->getStatusCode() === 200) {
×
533
            $data = $this->decodeJsonToObject($response->getBody());
×
534

535
            return new Entity\GetXPayBuildOrderStatus\Response($data);
×
536
        }
537
        $this->throwErrorResponse($response, [
×
538
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
539
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
540
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
541
        ]);
542
    }
×
543

544
    /**
545
     * List of orders in reverse chronological order. For more information about orders, please refer to the dedicated page Orders.
546
     *
547
     * @see https://developer.nexi.it/en/api/get-orders
548
     *
549
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
550
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
551
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
552
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
553
     * @throws \MLocati\Nexi\Exception\ErrorResponse
554
     */
555
    public function findOrders(?Entity\FindOrders\Query $query = null): Entity\FindOrders\Response
556
    {
557
        if ($query !== null) {
×
558
            $query->checkRequiredFields(__FUNCTION__, 'send');
×
559
        }
560
        $url = $this->buildUrl('/orders', [], $query);
×
561
        $response = $this->invoke('GET', $url, 3);
×
562
        if ($response->getStatusCode() === 200) {
×
563
            $data = $this->decodeJsonToObject($response->getBody());
×
564

565
            return new Entity\FindOrders\Response($data);
×
566
        }
567
        $this->throwErrorResponse($response, [
×
568
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
569
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
570
        ]);
571
    }
×
572

573
    /**
574
     * Searches for an order and returns its details. For more information about orders, please refer to the dedicated page Orders.
575
     *
576
     * @param string $orderId Identification code sent during the payment initialization phase (it must be unique).
577
     *
578
     * @see https://developer.nexi.it/en/api/get-orders-orderId
579
     *
580
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
581
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
582
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
583
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
584
     * @throws \MLocati\Nexi\Exception\ErrorResponse
585
     *
586
     * @return \MLocati\Nexi\Entity\FindOrderById\Response|null returns NULL if not found
587
     */
588
    public function findOrderById(string $orderId): ?Entity\FindOrderById\Response
589
    {
590
        $url = $this->buildUrl('/orders/{orderId}', ['orderId' => $orderId]);
×
591
        $response = $this->invoke('GET', $url, 3);
×
592
        if ($response->getStatusCode() === 200) {
×
593
            $data = $this->decodeJsonToObject($response->getBody());
×
594

595
            return new Entity\FindOrderById\Response($data);
×
596
        }
597
        if ($response->getStatusCode() === 404) {
×
598
            return null;
×
599
        }
600
        $this->throwErrorResponse($response, [
×
601
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
602
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
603
        ]);
604
    }
×
605

606
    /**
607
     * List of all operations created within the specified time range. For more information on operations, refer to the dedicated page Operations.
608
     *
609
     * @see https://developer.nexi.it/en/api/get-operations
610
     *
611
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
612
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
613
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
614
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
615
     * @throws \MLocati\Nexi\Exception\ErrorResponse
616
     */
617
    public function findOperations(?Entity\FindOperations\Query $query = null): Entity\FindOperations\Response
618
    {
619
        if ($query !== null) {
×
620
            $query->checkRequiredFields(__FUNCTION__, 'send');
×
621
        }
622
        $url = $this->buildUrl('/operations', [], $query);
×
623
        $response = $this->invoke('GET', $url, 3);
×
624
        if ($response->getStatusCode() === 200) {
×
625
            $data = $this->decodeJsonToObject($response->getBody());
×
626

627
            return new Entity\FindOperations\Response($data);
×
628
        }
629
        $this->throwErrorResponse($response, [
×
630
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
631
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
632
        ]);
633
    }
×
634

635
    /**
636
     * Searches for an operation and returns its details. For more information on operations, please refer to the dedicated page Operations.
637
     *
638
     * @param string $operationId Identification code of the operation.
639
     *
640
     * @see https://developer.nexi.it/en/api/get-operations-operationId
641
     *
642
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
643
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
644
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
645
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
646
     * @throws \MLocati\Nexi\Exception\ErrorResponse
647
     *
648
     * @return \MLocati\Nexi\Entity\Operation|null returns NULL if not found
649
     */
650
    public function findOperationById(string $operationId): ?Entity\Operation
651
    {
652
        $url = $this->buildUrl('/operations/{operationId}', ['operationId' => $operationId]);
×
653
        $response = $this->invoke('GET', $url, 3);
×
654
        if ($response->getStatusCode() === 200) {
×
655
            $data = $this->decodeJsonToObject($response->getBody());
×
656

657
            return new Entity\Operation($data);
×
658
        }
659
        if ($response->getStatusCode() === 404) {
×
660
            return null;
×
661
        }
662
        $this->throwErrorResponse($response, [
×
663
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
664
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
665
        ]);
666
    }
×
667

668
    /**
669
     * Retrieve the allowed actions associated to an operation and the range of value acceptable. For more information on operations, please refer to the dedicated page Operations.
670
     *
671
     * @param string $operationId Operation id
672
     *
673
     * @see https://developer.nexi.it/en/api/get-operations-operationId-actions
674
     *
675
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
676
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
677
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
678
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
679
     * @throws \MLocati\Nexi\Exception\ErrorResponse
680
     *
681
     * @return \MLocati\Nexi\Entity\GetOperationActions\Response|null returns NULL if not found
682
     */
683
    public function getOperationActions(string $operationId): ?Entity\GetOperationActions\Response
684
    {
685
        $url = $this->buildUrl('/operations/{operationId}/actions', ['operationId' => $operationId]);
×
686
        $response = $this->invoke('GET', $url, 3);
×
687
        if ($response->getStatusCode() === 200) {
×
688
            $data = $this->decodeJsonToObject($response->getBody());
×
689

690
            return new Entity\GetOperationActions\Response($data);
×
691
        }
692
        if ($response->getStatusCode() === 404) {
×
693
            return null;
×
694
        }
695
        $this->throwErrorResponse($response, [
×
696
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
697
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
698
        ]);
699
    }
×
700

701
    /**
702
     * Partial/total refund or cancellation based on the order status. For more information on operations, please refer to the dedicated page Operations.
703
     *
704
     * @param string $operationId Identification code of the operation.
705
     * @param string $idempotencyKey an identifier of the request (to be used on subsequent retries); if empty, it will be set as output
706
     *
707
     * @see https://developer.nexi.it/en/api/post-operations-operationId-refunds
708
     *
709
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
710
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
711
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Request rejected (HTTP code: 400)
712
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
713
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
714
     * @throws \MLocati\Nexi\Exception\ErrorResponse
715
     *
716
     * @return \MLocati\Nexi\Entity\OperationInfo|null returns NULL if not found
717
     */
718
    public function refund(string $operationId, Entity\AmountWithDescription $requestBody, string &$idempotencyKey = ''): ?Entity\OperationInfo
719
    {
720
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
721
        $url = $this->buildUrl('/operations/{operationId}/refunds', ['operationId' => $operationId]);
×
722
        $response = $this->invoke('POST', $url, 7, $requestBody, $idempotencyKey);
×
723
        if ($response->getStatusCode() === 200) {
×
724
            $data = $this->decodeJsonToObject($response->getBody());
×
725

726
            return new Entity\OperationInfo($data);
×
727
        }
728
        if ($response->getStatusCode() === 404) {
×
729
            return null;
×
730
        }
731
        $this->throwErrorResponse($response, [
×
732
            ['from' => 400, 'to' => 400, 'description' => 'Request rejected', 'detailed' => true],
×
733
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
734
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
735
        ]);
736
    }
×
737

738
    /**
739
     * Partial or total accounting. For more information on operations, refer to the dedicated page Operations..
740
     *
741
     * @param string $operationId Identification code of the operation.
742
     * @param string $idempotencyKey an identifier of the request (to be used on subsequent retries); if empty, it will be set as output
743
     *
744
     * @see https://developer.nexi.it/en/api/post-operations-operationId-captures
745
     *
746
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
747
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
748
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Request rejected (HTTP code: 400)
749
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
750
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
751
     * @throws \MLocati\Nexi\Exception\ErrorResponse
752
     *
753
     * @return \MLocati\Nexi\Entity\OperationInfo|null returns NULL if not found
754
     */
755
    public function capture(string $operationId, Entity\AmountWithDescription $requestBody, string &$idempotencyKey = ''): ?Entity\OperationInfo
756
    {
757
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
758
        $url = $this->buildUrl('/operations/{operationId}/captures', ['operationId' => $operationId]);
×
759
        $response = $this->invoke('POST', $url, 7, $requestBody, $idempotencyKey);
×
760
        if ($response->getStatusCode() === 200) {
×
761
            $data = $this->decodeJsonToObject($response->getBody());
×
762

763
            return new Entity\OperationInfo($data);
×
764
        }
765
        if ($response->getStatusCode() === 404) {
×
766
            return null;
×
767
        }
768
        $this->throwErrorResponse($response, [
×
769
            ['from' => 400, 'to' => 400, 'description' => 'Request rejected', 'detailed' => true],
×
770
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
771
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
772
        ]);
773
    }
×
774

775
    /**
776
     * Cancels a accounting operation. Does not apply to any other type of operation. For more information about operations, please refer to the dedicated page Operations.
777
     *
778
     * @param string $operationId Operation id of a capture operation to be cancelled.
779
     *
780
     * @see https://developer.nexi.it/en/api/post-operations-operationId-cancels
781
     *
782
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
783
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
784
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Request rejected (HTTP code: 400)
785
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
786
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
787
     * @throws \MLocati\Nexi\Exception\ErrorResponse
788
     *
789
     * @return \MLocati\Nexi\Entity\OperationInfo|null returns NULL if not found
790
     */
791
    public function cancel(string $operationId, Entity\Cancel\Request $requestBody): ?Entity\OperationInfo
792
    {
793
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
794
        $url = $this->buildUrl('/operations/{operationId}/cancels', ['operationId' => $operationId]);
×
795
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
796
        if ($response->getStatusCode() === 200) {
×
797
            $data = $this->decodeJsonToObject($response->getBody());
×
798

799
            return new Entity\OperationInfo($data);
×
800
        }
801
        if ($response->getStatusCode() === 404) {
×
802
            return null;
×
803
        }
804
        $this->throwErrorResponse($response, [
×
805
            ['from' => 400, 'to' => 400, 'description' => 'Request rejected', 'detailed' => true],
×
806
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
807
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
808
        ]);
809
    }
×
810

811
    /**
812
     * Search for contracts using the customer's identification. For more information on contracts, refer to the dedicated Contracts page.
813
     *
814
     * @param string $customerId Customer identification code.
815
     *
816
     * @see https://developer.nexi.it/en/api/get-contracts-customers-customerId
817
     *
818
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
819
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
820
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
821
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
822
     * @throws \MLocati\Nexi\Exception\ErrorResponse
823
     *
824
     * @return \MLocati\Nexi\Entity\FindRecurringContractsByCustomerId\Response|null returns NULL if not found
825
     */
826
    public function findRecurringContractsByCustomerId(string $customerId): ?Entity\FindRecurringContractsByCustomerId\Response
827
    {
828
        $url = $this->buildUrl('/contracts/customers/{customerId}', ['customerId' => $customerId]);
×
829
        $response = $this->invoke('GET', $url, 3);
×
830
        if ($response->getStatusCode() === 200) {
×
831
            $data = $this->decodeJsonToObject($response->getBody());
×
832

833
            return new Entity\FindRecurringContractsByCustomerId\Response($data);
×
834
        }
835
        if ($response->getStatusCode() === 404) {
×
836
            return null;
×
837
        }
838
        $this->throwErrorResponse($response, [
×
839
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
840
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
841
        ]);
842
    }
×
843

844
    /**
845
     * Disable a contract. For more information on contracts, please refer to the dedicated Contracts page.
846
     *
847
     * @param string $contractId Recurring contract ID.
848
     *
849
     * @see https://developer.nexi.it/en/api/post-contracts-contractId-deactivation
850
     *
851
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
852
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
853
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
854
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
855
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
856
     * @throws \MLocati\Nexi\Exception\ErrorResponse
857
     */
858
    public function disableContract(string $contractId): void
859
    {
860
        $url = $this->buildUrl('/contracts/{contractId}/deactivation', ['contractId' => $contractId]);
×
861
        $response = $this->invoke('POST', $url, 3);
×
862
        if ($response->getStatusCode() === 200) {
×
863
            return;
×
864
        }
865
        $this->throwErrorResponse($response, [
×
866
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
867
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
868
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
869
        ]);
870
    }
×
871

872
    /**
873
     * List of payment methods supported by the merchant terminal along with associated attributes.
874
     *
875
     * @see https://developer.nexi.it/en/api/post-payment_methods
876
     *
877
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
878
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
879
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
880
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
881
     * @throws \MLocati\Nexi\Exception\ErrorResponse
882
     */
883
    public function listSupportedPaymentMethods(): Entity\ListSupportedPaymentMethods\Response
884
    {
885
        $url = $this->buildUrl('/payment_methods');
×
886
        $response = $this->invoke('GET', $url, 3);
×
887
        if ($response->getStatusCode() === 200) {
×
888
            $data = $this->decodeJsonToObject($response->getBody());
×
889

890
            return new Entity\ListSupportedPaymentMethods\Response($data);
×
891
        }
892
        $this->throwErrorResponse($response, [
×
893
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
894
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
895
        ]);
896
    }
×
897

898
    /**
899
     * Create Terms and Condition for orders.
900
     *
901
     * @see https://developer.nexi.it/en/api/post-termsAndConditions
902
     *
903
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
904
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
905
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
906
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
907
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
908
     * @throws \MLocati\Nexi\Exception\ErrorResponse
909
     */
910
    public function createTermsAndConditions(Entity\CreateTermsAndConditions\Request $requestBody): Entity\CreateTermsAndConditions\Response
911
    {
912
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
913
        $url = $this->buildUrl('/termsAndConditions');
×
914
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
915
        if ($response->getStatusCode() === 200) {
×
916
            $data = $this->decodeJsonToObject($response->getBody());
×
917

918
            return new Entity\CreateTermsAndConditions\Response($data);
×
919
        }
920
        $this->throwErrorResponse($response, [
×
921
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
922
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
923
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
924
        ]);
925
    }
×
926

927
    /**
928
     * Retrieve one Terms and Conditions details.
929
     *
930
     * @param string $termsAndConditionsId Terms and Conditions ID.
931
     *
932
     * @see https://developer.nexi.it/en/api/get-terms_and_conditions-termsAndConditionsId
933
     *
934
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
935
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
936
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
937
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
938
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
939
     * @throws \MLocati\Nexi\Exception\ErrorResponse
940
     */
941
    public function findTermsAndConditionsById(string $termsAndConditionsId): Entity\FindTermsAndConditionsById\Response
942
    {
943
        $url = $this->buildUrl('/terms_and_conditions/{termsAndConditionsId}', ['termsAndConditionsId' => $termsAndConditionsId]);
×
944
        $response = $this->invoke('GET', $url, 3);
×
945
        if ($response->getStatusCode() === 200) {
×
946
            $data = $this->decodeJsonToObject($response->getBody());
×
947

948
            return new Entity\FindTermsAndConditionsById\Response($data);
×
949
        }
950
        $this->throwErrorResponse($response, [
×
951
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
952
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
953
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
954
        ]);
955
    }
×
956

957
    /**
958
     * Incremental of a pre-authorization.
959
     *
960
     * @param string $idempotencyKey an identifier of the request (to be used on subsequent retries); if empty, it will be set as output
961
     *
962
     * @see https://developer.nexi.it/en/api/post-incrementals
963
     *
964
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
965
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
966
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
967
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
968
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
969
     * @throws \MLocati\Nexi\Exception\ErrorResponse
970
     */
971
    public function incrementOrder(Entity\ChangeAmountRequest $requestBody, string &$idempotencyKey = ''): Entity\OperationResult
972
    {
973
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
974
        $url = $this->buildUrl('/incrementals');
×
975
        $response = $this->invoke('POST', $url, 7, $requestBody, $idempotencyKey);
×
976
        if ($response->getStatusCode() === 200) {
×
977
            $data = $this->decodeJsonToObject($response->getBody());
×
978

979
            return new Entity\OperationResult($data);
×
980
        }
981
        $this->throwErrorResponse($response, [
×
982
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
983
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
984
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
985
        ]);
986
    }
×
987

988
    /**
989
     * Cancel a T&C not associated to any operation.
990
     *
991
     * @param string $termsAndConditionsId Terms and Conditions ID.
992
     *
993
     * @see https://developer.nexi.it/en/api/post-terms_and_conditions-termsAndConditionsId-cancels
994
     *
995
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
996
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
997
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Request rejected (HTTP code: 400)
998
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
999
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1000
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1001
     *
1002
     * @return bool returns FALSE if not found
1003
     */
1004
    public function cancelTermsAndConditions(string $termsAndConditionsId): bool
1005
    {
1006
        $url = $this->buildUrl('/terms_and_conditions/{termsAndConditionsId}/cancels', ['termsAndConditionsId' => $termsAndConditionsId]);
×
1007
        $response = $this->invoke('POST', $url, 3);
×
1008
        if ($response->getStatusCode() === 200) {
×
1009
            return true;
×
1010
        }
1011
        if ($response->getStatusCode() === 404) {
×
1012
            return false;
×
1013
        }
1014
        $this->throwErrorResponse($response, [
×
1015
            ['from' => 400, 'to' => 400, 'description' => 'Request rejected', 'detailed' => true],
×
1016
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1017
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1018
        ]);
1019
    }
×
1020

1021
    /**
1022
     * Possibility of making additional charges for example for a customer who has used the mini bar or has caused damage to the property.
1023
     *
1024
     * @param string $idempotencyKey an identifier of the request (to be used on subsequent retries); if empty, it will be set as output
1025
     *
1026
     * @see https://developer.nexi.it/en/api/post-delay_charges
1027
     *
1028
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1029
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1030
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1031
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1032
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1033
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1034
     */
1035
    public function delayedCharge(Entity\ChangeAmountRequest $requestBody, string &$idempotencyKey = ''): Entity\OperationResult
1036
    {
1037
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1038
        $url = $this->buildUrl('/delay_charges');
×
1039
        $response = $this->invoke('POST', $url, 7, $requestBody, $idempotencyKey);
×
1040
        if ($response->getStatusCode() === 200) {
×
1041
            $data = $this->decodeJsonToObject($response->getBody());
×
1042

1043
            return new Entity\OperationResult($data);
×
1044
        }
1045
        $this->throwErrorResponse($response, [
×
1046
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1047
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1048
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1049
        ]);
1050
    }
×
1051

1052
    /**
1053
     * If the customer does not show up and the reservation has not been canceled within the defined terms and conditions, you can charge the card for the amount corresponding to an overnight stay.
1054
     *
1055
     * @param string $idempotencyKey an identifier of the request (to be used on subsequent retries); if empty, it will be set as output
1056
     *
1057
     * @see https://developer.nexi.it/en/api/post-no_shows
1058
     *
1059
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1060
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1061
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1062
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1063
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1064
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1065
     */
1066
    public function noShowCharge(Entity\ChangeAmountRequest $requestBody, string &$idempotencyKey = ''): Entity\OperationResult
1067
    {
1068
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1069
        $url = $this->buildUrl('/no_shows');
×
1070
        $response = $this->invoke('POST', $url, 7, $requestBody, $idempotencyKey);
×
1071
        if ($response->getStatusCode() === 200) {
×
1072
            $data = $this->decodeJsonToObject($response->getBody());
×
1073

1074
            return new Entity\OperationResult($data);
×
1075
        }
1076
        $this->throwErrorResponse($response, [
×
1077
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1078
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1079
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1080
        ]);
1081
    }
×
1082

1083
    /**
1084
     * Create reservation.
1085
     *
1086
     * @see https://developer.nexi.it/en/api/post-reservations
1087
     *
1088
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1089
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1090
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1091
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1092
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1093
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1094
     */
1095
    public function createReservation(Entity\CreateReservation\Request $requestBody): Entity\CreateReservation\Response
1096
    {
1097
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1098
        $url = $this->buildUrl('/reservations');
×
1099
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
1100
        if ($response->getStatusCode() === 200) {
×
1101
            $data = $this->decodeJsonToObject($response->getBody());
×
1102

1103
            return new Entity\CreateReservation\Response($data);
×
1104
        }
1105
        $this->throwErrorResponse($response, [
×
1106
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1107
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1108
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1109
        ]);
1110
    }
×
1111

1112
    /**
1113
     * Find reservations.
1114
     *
1115
     * @see https://developer.nexi.it/en/api/get-reservations
1116
     *
1117
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1118
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1119
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1120
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1121
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1122
     */
1123
    public function findReservations(?Entity\FindReservations\Query $query = null): Entity\FindReservations\Response
1124
    {
1125
        if ($query !== null) {
×
1126
            $query->checkRequiredFields(__FUNCTION__, 'send');
×
1127
        }
1128
        $url = $this->buildUrl('/reservations', [], $query);
×
1129
        $response = $this->invoke('GET', $url, 3);
×
1130
        if ($response->getStatusCode() === 200) {
×
1131
            $data = $this->decodeJsonToObject($response->getBody());
×
1132

1133
            return new Entity\FindReservations\Response($data);
×
1134
        }
1135
        $this->throwErrorResponse($response, [
×
1136
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
1137
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1138
        ]);
1139
    }
×
1140

1141
    /**
1142
     * Generate PayByLink for a specific reservation. In case of the first payment for the reservation, a contractId is created. In case of the following payment the existing reservation contractId is used.
1143
     *
1144
     * @param string $reservationId Merchant reservation id, unique in the merchant domain
1145
     *
1146
     * @see https://developer.nexi.it/en/api/post-reservations-reservationId-paybylink
1147
     *
1148
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1149
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1150
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1151
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1152
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1153
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1154
     */
1155
    public function createPayByLinkForReservation(string $reservationId, Entity\CreatePayByLinkForReservation\Request $requestBody): Entity\PayByLinkResponse
1156
    {
1157
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1158
        $url = $this->buildUrl('/reservations/{reservationId}/paybylink', ['reservationId' => $reservationId]);
×
1159
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
1160
        if ($response->getStatusCode() === 200) {
×
1161
            $data = $this->decodeJsonToObject($response->getBody());
×
1162

1163
            return new Entity\PayByLinkResponse($data);
×
1164
        }
1165
        $this->throwErrorResponse($response, [
×
1166
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1167
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1168
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1169
        ]);
1170
    }
×
1171

1172
    /**
1173
     * Find reservation by ID.
1174
     *
1175
     * @param string $reservationId Merchant reservation id
1176
     *
1177
     * @see https://developer.nexi.it/en/api/get-reservations-reservationId
1178
     *
1179
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1180
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1181
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1182
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1183
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1184
     *
1185
     * @return \MLocati\Nexi\Entity\FindReservationById\Response|null returns NULL if not found
1186
     */
1187
    public function findReservationById(string $reservationId): ?Entity\FindReservationById\Response
1188
    {
1189
        $url = $this->buildUrl('/reservations/{reservationId}', ['reservationId' => $reservationId]);
×
1190
        $response = $this->invoke('GET', $url, 3);
×
1191
        if ($response->getStatusCode() === 200) {
×
1192
            $data = $this->decodeJsonToObject($response->getBody());
×
1193

1194
            return new Entity\FindReservationById\Response($data);
×
1195
        }
1196
        if ($response->getStatusCode() === 404) {
×
1197
            return null;
×
1198
        }
1199
        $this->throwErrorResponse($response, [
×
1200
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
1201
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1202
        ]);
1203
    }
×
1204

1205
    /**
1206
     * Create a structure.
1207
     *
1208
     * @see https://developer.nexi.it/en/api/post-structures
1209
     *
1210
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1211
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1212
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1213
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1214
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1215
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1216
     */
1217
    public function createStructure(Entity\StructureInfo $requestBody): void
1218
    {
1219
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1220
        $url = $this->buildUrl('/structures');
×
1221
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
1222
        if ($response->getStatusCode() === 200) {
×
1223
            return;
×
1224
        }
1225
        $this->throwErrorResponse($response, [
×
1226
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1227
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1228
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1229
        ]);
1230
    }
×
1231

1232
    /**
1233
     * Find structure in reversed chronological order.
1234
     *
1235
     * @see https://developer.nexi.it/en/api/get-structures
1236
     *
1237
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1238
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1239
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1240
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1241
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1242
     *
1243
     * @return \MLocati\Nexi\Entity\StructureInfo|null returns NULL if not found
1244
     */
1245
    public function findStructures(): ?Entity\StructureInfo
1246
    {
1247
        $url = $this->buildUrl('/structures');
×
1248
        $response = $this->invoke('GET', $url, 3);
×
1249
        if ($response->getStatusCode() === 200) {
×
1250
            $data = $this->decodeJsonToObject($response->getBody());
×
1251

1252
            return new Entity\StructureInfo($data);
×
1253
        }
1254
        if ($response->getStatusCode() === 404) {
×
1255
            return null;
×
1256
        }
1257
        $this->throwErrorResponse($response, [
×
1258
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
1259
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1260
        ]);
1261
    }
×
1262

1263
    /**
1264
     * Retrieve information of a specific structure identified by structure id.
1265
     *
1266
     * @param string $structureId Identification code of the structure.
1267
     *
1268
     * @see https://developer.nexi.it/en/api/get-structures-structureId
1269
     *
1270
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1271
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1272
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1273
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1274
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1275
     *
1276
     * @return \MLocati\Nexi\Entity\StructureInfo|null returns NULL if not found
1277
     */
1278
    public function findStructureById(string $structureId): ?Entity\StructureInfo
1279
    {
1280
        $url = $this->buildUrl('/structures/{structureId}', ['structureId' => $structureId]);
×
1281
        $response = $this->invoke('GET', $url, 3);
×
1282
        if ($response->getStatusCode() === 200) {
×
1283
            $data = $this->decodeJsonToObject($response->getBody());
×
1284

1285
            return new Entity\StructureInfo($data);
×
1286
        }
1287
        if ($response->getStatusCode() === 404) {
×
1288
            return null;
×
1289
        }
1290
        $this->throwErrorResponse($response, [
×
1291
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
1292
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1293
        ]);
1294
    }
×
1295

1296
    /**
1297
     * No Show validation.
1298
     *
1299
     * @see https://developer.nexi.it/en/api/post-noshow_validation
1300
     *
1301
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1302
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1303
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1304
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1305
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1306
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1307
     */
1308
    public function noShowValidation(Entity\ReservationValidation $requestBody): void
1309
    {
1310
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1311
        $url = $this->buildUrl('/noshow_validation');
×
1312
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
1313
        if ($response->getStatusCode() === 200) {
×
1314
            return;
×
1315
        }
1316
        $this->throwErrorResponse($response, [
×
1317
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1318
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1319
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1320
        ]);
1321
    }
×
1322

1323
    /**
1324
     * Delay charge validation.
1325
     *
1326
     * @see https://developer.nexi.it/en/api/post-delaycharge_validation
1327
     *
1328
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1329
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1330
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1331
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1332
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1333
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1334
     */
1335
    public function delayedChargeValidation(Entity\ReservationValidation $requestBody): void
1336
    {
1337
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1338
        $url = $this->buildUrl('/delaycharge_validation');
×
1339
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
1340
        if ($response->getStatusCode() === 200) {
×
1341
            return;
×
1342
        }
1343
        $this->throwErrorResponse($response, [
×
1344
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1345
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1346
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1347
        ]);
1348
    }
×
1349

1350
    /**
1351
     * Incremental validation
1352
     *
1353
     * @see https://developer.nexi.it/en/api/post-incremental_validation
1354
     *
1355
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1356
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1357
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1358
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1359
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1360
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1361
     */
1362
    public function incrementOrderValidation(Entity\ReservationValidation $requestBody): void
1363
    {
1364
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1365
        $url = $this->buildUrl('/incremental_validation');
×
1366
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
1367
        if ($response->getStatusCode() === 200) {
×
1368
            return;
×
1369
        }
1370
        $this->throwErrorResponse($response, [
×
1371
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1372
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1373
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1374
        ]);
1375
    }
×
1376

1377
    /**
1378
     * Create terms and conditions defined for a unique structure.
1379
     *
1380
     * @see https://developer.nexi.it/en/api/post-structure_conditions
1381
     *
1382
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1383
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1384
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1385
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1386
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1387
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1388
     */
1389
    public function createStructureTermsAndConditions(Entity\CreateStructureTermsAndConditions\Request $requestBody): Entity\CreateStructureTermsAndConditions\Response
1390
    {
1391
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1392
        $url = $this->buildUrl('/structure_conditions');
×
1393
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
1394
        if ($response->getStatusCode() === 200) {
×
1395
            $data = $this->decodeJsonToObject($response->getBody());
×
1396

1397
            return new Entity\CreateStructureTermsAndConditions\Response($data);
×
1398
        }
1399
        $this->throwErrorResponse($response, [
×
1400
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1401
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1402
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1403
        ]);
1404
    }
×
1405

1406
    /**
1407
     * Retrieve the list of terms and conditions associated to a specific structure.
1408
     *
1409
     * @param string $structureid Unique identifier for the structure.
1410
     *
1411
     * @see https://developer.nexi.it/en/api/get-structure_conditions-structures-structureid
1412
     *
1413
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1414
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1415
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1416
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1417
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1418
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1419
     */
1420
    public function findStructureTermsAndConditionsByStructureId(string $structureid): array
1421
    {
1422
        $url = $this->buildUrl('/structure_conditions/structures/{structureid}', ['structureid' => $structureid]);
×
1423
        $response = $this->invoke('GET', $url, 3);
×
1424
        if ($response->getStatusCode() === 200) {
×
1425
            $data = $this->decodeJsonToArray($response->getBody());
×
1426

1427
            return array_map(static function (array $item) { return new Entity\StructureTermsAndConditions($item); }, $data);
1428
        }
1429
        $this->throwErrorResponse($response, [
×
1430
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1431
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1432
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1433
        ]);
1434
    }
×
1435

1436
    /**
1437
     * Retrieve all the details for a given terms and conditions.
1438
     *
1439
     * @param string $structureConditionId Unique identifier of terms and conditions for the structure.
1440
     *
1441
     * @see https://developer.nexi.it/en/api/get-structure_conditions-structureConditionId
1442
     *
1443
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1444
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1445
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1446
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1447
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1448
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1449
     */
1450
    public function findStructureTermsAndConditionsById(string $structureConditionId): Entity\FindStructureTermsAndConditionsById\Response
1451
    {
1452
        $url = $this->buildUrl('/structure_conditions/{structureConditionId}', ['structureConditionId' => $structureConditionId]);
×
1453
        $response = $this->invoke('GET', $url, 3);
×
1454
        if ($response->getStatusCode() === 200) {
×
1455
            $data = $this->decodeJsonToObject($response->getBody());
×
1456

1457
            return new Entity\FindStructureTermsAndConditionsById\Response($data);
×
1458
        }
1459
        $this->throwErrorResponse($response, [
×
1460
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1461
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1462
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1463
        ]);
1464
    }
×
1465

1466
    /**
1467
     * Cancel terms and condition not associated to any operation.
1468
     *
1469
     * @param string $structureConditionId Unique identifier of terms and conditions for the structure.
1470
     *
1471
     * @see https://developer.nexi.it/en/api/post-structure_conditions-structureConditionId-cancels
1472
     *
1473
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1474
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1475
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Request rejected (HTTP code: 400)
1476
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1477
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1478
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1479
     *
1480
     * @return bool returns FALSE if not found
1481
     */
1482
    public function cancelStructureTermsAndConditions(string $structureConditionId): bool
1483
    {
1484
        $url = $this->buildUrl('/structure_conditions/{structureConditionId}/cancels', ['structureConditionId' => $structureConditionId]);
×
1485
        $response = $this->invoke('POST', $url, 3);
×
1486
        if ($response->getStatusCode() === 200) {
×
1487
            return true;
×
1488
        }
1489
        if ($response->getStatusCode() === 404) {
×
1490
            return false;
×
1491
        }
1492
        $this->throwErrorResponse($response, [
×
1493
            ['from' => 400, 'to' => 400, 'description' => 'Request rejected', 'detailed' => true],
×
1494
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1495
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1496
        ]);
1497
    }
×
1498

1499
    /**
1500
     * Activate or deactivate the service.
1501
     *
1502
     * @see https://developer.nexi.it/en/api/post-services
1503
     *
1504
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1505
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1506
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1507
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1508
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1509
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1510
     */
1511
    public function toggleService(Entity\ServiceRequest $requestBody): void
1512
    {
1513
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1514
        $url = $this->buildUrl('/services');
×
1515
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
1516
        if ($response->getStatusCode() === 200) {
×
1517
            return;
×
1518
        }
1519
        $this->throwErrorResponse($response, [
×
1520
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1521
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1522
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1523
        ]);
1524
    }
×
1525

1526
    /**
1527
     * Retrieve the information service.
1528
     *
1529
     * @see https://developer.nexi.it/en/api/get-services
1530
     *
1531
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1532
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1533
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1534
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1535
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1536
     *
1537
     * @return \MLocati\Nexi\Entity\ServiceRequest|null returns NULL if not found
1538
     */
1539
    public function getService(Entity\GetService\Query $query): ?Entity\ServiceRequest
1540
    {
1541
        $query->checkRequiredFields(__FUNCTION__, 'send');
×
1542
        $url = $this->buildUrl('/services', [], $query);
×
1543
        $response = $this->invoke('GET', $url, 3);
×
1544
        if ($response->getStatusCode() === 200) {
×
1545
            $data = $this->decodeJsonToObject($response->getBody());
×
1546

1547
            return new Entity\ServiceRequest($data);
×
1548
        }
1549
        if ($response->getStatusCode() === 404) {
×
1550
            return null;
×
1551
        }
1552
        $this->throwErrorResponse($response, [
×
1553
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
×
1554
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1555
        ]);
1556
    }
×
1557

1558
    /**
1559
     * Create custom fields.
1560
     *
1561
     * @see https://developer.nexi.it/en/api/post-custom_fields
1562
     *
1563
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1564
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1565
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1566
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1567
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1568
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1569
     */
1570
    public function createCustomField(Entity\CustomFieldDetails $requestBody): Entity\CreateCustomField\Response
1571
    {
1572
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1573
        $url = $this->buildUrl('/custom_fields');
×
1574
        $response = $this->invoke('POST', $url, 3, $requestBody);
×
1575
        if ($response->getStatusCode() === 200) {
×
1576
            $data = $this->decodeJsonToObject($response->getBody());
×
1577

1578
            return new Entity\CreateCustomField\Response($data);
×
1579
        }
1580
        $this->throwErrorResponse($response, [
×
1581
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1582
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1583
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1584
        ]);
1585
    }
×
1586

1587
    /**
1588
     * Retrieve custom fields details
1589
     *
1590
     * @see https://developer.nexi.it/en/api/get-custom_fields-customFieldId
1591
     *
1592
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1593
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1594
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1595
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1596
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1597
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1598
     */
1599
    public function getCustomField(string $customFieldId): Entity\CustomFieldDetails
1600
    {
1601
        $url = $this->buildUrl('/custom_fields/{customFieldId}', ['customFieldId' => $customFieldId]);
×
1602
        $response = $this->invoke('GET', $url, 3);
×
1603
        if ($response->getStatusCode() === 200) {
×
1604
            $data = $this->decodeJsonToObject($response->getBody());
×
1605

1606
            return new Entity\CustomFieldDetails($data);
×
1607
        }
1608
        $this->throwErrorResponse($response, [
×
1609
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1610
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1611
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1612
        ]);
1613
    }
×
1614

1615
    /**
1616
     * Retrieval of the terms and conditions with .pdf extension of the structure.
1617
     *
1618
     * @param string $structureConditionId Terms and condition of the structure unique identifier.
1619
     *
1620
     * @see https://developer.nexi.it/en/api/get-structure_conditions-structureConditionId-pdf
1621
     *
1622
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1623
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1624
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1625
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1626
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1627
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1628
     */
1629
    public function getStructureTermsAndConditionsPdf(string $structureConditionId): void
1630
    {
1631
        $url = $this->buildUrl('/structure_conditions/{structureConditionId}/pdf', ['structureConditionId' => $structureConditionId]);
×
1632
        $response = $this->invoke('GET', $url, 3);
×
1633
        if ($response->getStatusCode() === 200) {
×
1634
            return;
×
1635
        }
1636
        $this->throwErrorResponse($response, [
×
1637
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1638
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1639
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1640
        ]);
1641
    }
×
1642

1643
    /**
1644
     * Recurring Payment (MIT) on a reservation.
1645
     *
1646
     * @param string $reservationId Reservation identification code.
1647
     * @param string $idempotencyKey an identifier of the request (to be used on subsequent retries); if empty, it will be set as output
1648
     *
1649
     * @see https://developer.nexi.it/en/api/post-reservation-reservationId-mit
1650
     *
1651
     * @throws \MLocati\Nexi\Exception\HttpRequestFailed if the HTTP request could not be made
1652
     * @throws \MLocati\Nexi\Exception\InvalidJson if we couldn't decode the response body as JSON
1653
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Invalid request data (HTTP code: 400)
1654
     * @throws \MLocati\Nexi\Exception\ErrorResponse Unauthorized (HTTP code: 401)
1655
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed Internal Server Error (HTTP code: 500)
1656
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1657
     */
1658
    public function payRecurringReservation(string $reservationId, Entity\PayRecurringReservation\Request $requestBody, string &$idempotencyKey = ''): void
1659
    {
1660
        $requestBody->checkRequiredFields(__FUNCTION__, 'send');
×
1661
        $url = $this->buildUrl('/reservation/{reservationId}/mit', ['reservationId' => $reservationId]);
×
1662
        $response = $this->invoke('POST', $url, 7, $requestBody, $idempotencyKey);
×
1663
        if ($response->getStatusCode() === 200) {
×
1664
            return;
×
1665
        }
1666
        $this->throwErrorResponse($response, [
×
1667
            ['from' => 400, 'to' => 400, 'description' => 'Invalid request data', 'detailed' => true],
×
1668
            ['from' => 401, 'to' => 401, 'description' => 'Unauthorized'],
1669
            ['from' => 500, 'to' => 500, 'description' => 'Internal Server Error', 'detailed' => true],
1670
        ]);
1671
    }
×
1672

1673
    /**
1674
     * @throws \MLocati\Nexi\Exception\NoHttpClient
1675
     */
1676
    protected function buildHttpClient(): HttpClient
1677
    {
1678
        if (HttpClient\Curl::isAvailable()) {
×
1679
            return new HttpClient\Curl();
×
1680
        }
1681
        if (HttpClient\StreamWrapper::isAvailable()) {
×
1682
            return new HttpClient\StreamWrapper();
×
1683
        }
1684
        throw new Exception\NoHttpClient();
×
1685
    }
1686

1687
    protected function buildCorrelationProvider(): CorrelationProvider
1688
    {
1689
        if (CorrelationProvider\UUID::isAvailable()) {
×
1690
            return new CorrelationProvider\UUID();
×
1691
        }
1692

1693
        return new CorrelationProvider\Random();
×
1694
    }
1695

1696
    protected function buildUrl(string $path, array $pathParams = [], ?QueryEntityInterface $query = null): string
1697
    {
1698
        $matches = null;
×
1699
        if (preg_match_all('/\\{(?<name>[^\\}]+)\\}/', $path, $matches) !== 0) {
×
1700
            $names = $matches['name'];
×
1701
            while ($names !== []) {
×
1702
                $name = array_shift($names);
×
1703
                if (!array_key_exists($name, $pathParams)) {
×
1704
                    throw new \RuntimeException('Missing required URL parameter: ' . $name);
×
1705
                }
1706
                $path = str_replace('{' . $name . '}', rawurlencode((string) $pathParams[$name]), $path);
×
1707
                unset($pathParams[$name]);
×
1708
            }
1709
        }
1710
        if ($pathParams !== []) {
×
1711
            throw new \RuntimeException("Unexpected URL parameters:\n- " . implode("\n- ", array_keys($pathParams)));
×
1712
        }
1713
        $url = rtrim($this->configuration->getBaseUrl(), '/') . '/' . ltrim($path, '/');
×
1714
        $qs = $query === null ? '' : $query->getQuerystring();
×
1715
        if ($qs !== '') {
×
1716
            $url .= '?' . $qs;
×
1717
        }
1718

1719
        return $url;
×
1720
    }
1721

1722
    /**
1723
     * @param \MLocati\Nexi\Entity|\MLocati\Nexi\Entity[]|null $requestBody
1724
     */
1725
    protected function invoke(string $method, string $url, int $headerFlags, $requestBody = null, string &$idempotencyKey = ''): HttpClient\Response
1726
    {
1727
        if ($requestBody === null) {
×
1728
            $requestBodyJson = '';
×
1729
        } else {
1730
            $requestBodyJson = json_encode($requestBody, JSON_UNESCAPED_SLASHES);
×
1731
            if ($requestBodyJson === false) {
×
1732
                throw new \RuntimeException('Failed to create the JSON data: ' . (json_last_error_msg() ?: 'unknown reason'));
×
1733
            }
1734
        }
1735
        $headers = $this->buildHeaders($method, $url, $requestBodyJson, $headerFlags, $idempotencyKey);
×
1736

1737
        return $this->httpClient->invoke($method, $url, $headers, $requestBodyJson);
×
1738
    }
1739

1740
    protected function buildHeaders(string $method, string $url, string $requestBody, int $flags, string &$idempotencyKey): array
1741
    {
1742
        $headers = [
1743
            'Content-Type' => 'application/json',
×
1744
            'Accept' => 'application/json',
1745
        ];
1746
        if ($flags & 1) {
×
1747
            $headers['X-Api-Key'] = $this->configuration->getApiKey();
×
1748
        }
1749
        if ($flags & 2) {
×
1750
            $headers['Correlation-Id'] = $this->correlationProvider->getCorrelationID($method, $url, $requestBody);
×
1751
        }
1752
        if ($flags & 4) {
×
1753
            if ($idempotencyKey === '') {
×
1754
                $idempotencyKey = $this->generateIdempotencyKey();
×
1755
            }
1756
            $headers['Idempotency-Key'] = $idempotencyKey;
×
1757
        }
1758

1759
        return $headers;
×
1760
    }
1761

1762
    /**
1763
     * @throws \MLocati\Nexi\Exception\InvalidJson
1764
     */
1765
    protected function decodeJsonToArray(string $json): array
1766
    {
1767
        $data = $this->decodeJson($json);
×
1768
        if (is_array($data)) {
×
1769
            return $data;
×
1770
        }
1771
        throw new Exception\InvalidJson($json, 'The JSON does NOT represent an array');
×
1772
    }
1773

1774
    /**
1775
     * @throws \MLocati\Nexi\Exception\InvalidJson
1776
     */
1777
    protected function decodeJsonToObject(string $json): stdClass
1778
    {
1779
        $data = $this->decodeJson($json);
×
1780
        if ($data instanceof stdClass) {
×
1781
            return $data;
×
1782
        }
1783

1784
        throw new Exception\InvalidJson($json, 'The JSON does NOT represent an object');
×
1785
    }
1786

1787
    /**
1788
     * @throws \MLocati\Nexi\Exception\ErrorResponse\Detailed
1789
     * @throws \MLocati\Nexi\Exception\ErrorResponse
1790
     */
1791
    protected function throwErrorResponse(Response $response, array $cases): void
1792
    {
1793
        foreach ($cases as $case) {
×
1794
            if ($case['from'] <= $response->getStatusCode() && $response->getStatusCode() <= $case['from']) {
×
1795
                $message = $case['description'];
×
1796
                if ($message === '') {
×
1797
                    $message = "Request failed with return code {$response->getStatusCode()}";
×
1798
                }
1799
                if (empty($case['detailed'])) {
×
1800
                    throw new Exception\ErrorResponse($response->getStatusCode(), $message);
×
1801
                }
1802
                $data = $this->decodeJsonToArray($response->getBody());
×
1803
                $errors = new Entity\Errors($data);
×
1804

1805
                throw new Exception\ErrorResponse\Detailed($response->getStatusCode(), $message, $errors);
×
1806
            }
1807
        }
1808

1809
        throw new Exception\ErrorResponse($response->getStatusCode(), "Request failed with return code {$response->getStatusCode()}");
×
1810
    }
1811

1812
    /**
1813
     * Maximum length: 63 characters
1814
     */
1815
    protected function generateIdempotencyKey(): string
1816
    {
1817
        return bin2hex(random_bytes(31));
×
1818
    }
1819

1820
    /**
1821
     * @throws \MLocati\Nexi\Exception\InvalidJson
1822
     */
1823
    private function decodeJson(string $json)
1824
    {
1825
        if ($json === 'null') {
×
1826
            return null;
×
1827
        }
1828
        $decoded = json_decode($json);
×
1829
        if ($decoded === null) {
×
1830
            throw new Exception\InvalidJson($json);
×
1831
        }
1832

1833
        return $decoded;
×
1834
    }
1835
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc