Completed
Push — master ( 2a953d...5971d3 )
by
unknown
27s queued 10s
created

Bankly::paymentConfirm()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
namespace WeDevBr\Bankly;
4
5
use Illuminate\Http\Client\RequestException;
6
use Illuminate\Support\Facades\Http;
7
use Ramsey\Uuid\Uuid;
8
use TypeError;
9
use WeDevBr\Bankly\Inputs\Customer;
10
use WeDevBr\Bankly\Inputs\DocumentAnalysis;
11
use WeDevBr\Bankly\Support\Contracts\CustomerInterface;
12
use WeDevBr\Bankly\Support\Contracts\DocumentInterface;
13
use WeDevBr\Bankly\Types\VirtualCard\VirtualCard;
14
15
/**
16
 * Class Bankly
17
 * @author Adeildo Amorim <[email protected]>
18
 * @package WeDevBr\Bankly
19
 */
20
class Bankly
21
{
22
    public $api_url;
23
    public $login_url;
24
    private $client_id;
25
    private $client_secret;
26
    private $token_expiry = 0;
27
    private $token = null;
28
    private $api_version = '1.0';
29
30
    /**
31
     * Bankly constructor.
32
     * @param null|string $client_secret provided by Bankly Staff
33
     * @param null|string $client_id provided by Bankly Staff
34
     */
35
    public function __construct($client_secret = null, $client_id = null)
36
    {
37
        $this->api_url = config('bankly')['api_url'];
38
        $this->login_url = config('bankly')['login_url'];
39
        $this->setClientCredentials(['client_secret' => $client_secret, 'client_id' => $client_id]);
40
    }
41
42
    /**
43
     * @param array|null $credentials
44
     * @return $this
45
     */
46
    public function setClientCredentials(array $credentials = null)
47
    {
48
        $this->client_secret = $credentials['client_secret'] ?? config('bankly')['client_secret'];
49
        $this->client_id = $credentials['client_id'] ?? config('bankly')['client_id'];
50
        return $this;
51
    }
52
53
    /**
54
     * @return array|mixed
55
     * @throws RequestException
56
     */
57
    public function getBankList()
58
    {
59
        return $this->get('/banklist');
60
    }
61
62
    /**
63
     * Retrieve your balance account
64
     * @param string $branch
65
     * @param string $account
66
     * @return array|mixed
67
     * @throws RequestException
68
     * @note If you have a RequestException on this endpoint in staging environment, please use getAccount() method instead.
69
     */
70
    public function getBalance(string $branch, string $account)
71
72
    {
73
        return $this->get('/account/balance', [
74
            'branch' => $branch,
75
            'account' => $account
76
        ]);
77
    }
78
79
    /**
80
     * @param string $account
81
     * @param string $includeBalance
82
     * @return array|mixed
83
     * @throws RequestException
84
     * @note This method on this date (2020-10-21) works only on staging environment. Contact Bankly/Acesso for more details
85
     */
86
    public function getAccount(string $account, string $includeBalance = 'true')
87
    {
88
        return $this->get('/accounts/' . $account, [
89
            'includeBalance' => $includeBalance,
90
        ]);
91
    }
92
93
    /**
94
     * @param $branch
95
     * @param $account
96
     * @param int $offset
97
     * @param int $limit
98
     * @param string $details
99
     * @param string $detailsLevelBasic
100
     * @return array|mixed
101
     * @throws RequestException
102
     */
103
    public function getStatement(
104
        $branch,
105
        $account,
106
        $offset = 1,
107
        $limit = 20,
108
        string $details = 'true',
109
        string $detailsLevelBasic = 'true'
110
    ) {
111
        return $this->get('/account/statement', array(
112
            'branch' => $branch,
113
            'account' => $account,
114
            'offset' => $offset,
115
            'limit' => $limit,
116
            'details' => $details,
117
            'detailsLevelBasic' => $detailsLevelBasic
118
        ));
119
    }
120
121
    /**
122
     * @param string $branch
123
     * @param string $account
124
     * @param int $page
125
     * @param int $pagesize
126
     * @param string $include_details
127
     * @return array|mixed
128
     * @throws RequestException
129
     * @note This endpoint has been deprecated for some clients.
130
     * You need to check with Acesso/Bankly if your environment has different parameters also.
131
     * The response of this request does not have a default interface between environments.
132
     * Pay attention when use this in your project.
133
     */
134
    public function getEvents(
135
        string $branch,
136
        string $account,
137
        int $page = 1,
138
        int $pagesize = 20,
139
        string $include_details = 'true'
140
    ) {
141
        return $this->get(
142
            '/events',
143
            [
144
                'branch' => $branch,
145
                'account' => $account,
146
                'page' => $page,
147
                'pageSize' => $pagesize,
148
                'includeDetails' => $include_details
149
150
            ]
151
        );
152
    }
153
154
    /**
155
     * @param int $amount
156
     * @param string $description
157
     * @param array $sender
158
     * @param array $recipient
159
     * @param string|null $correlation_id
160
     * @return array|mixed
161
     * @throws RequestException
162
     */
163
    public function transfer(
164
        int $amount,
165
        string $description,
166
        array $sender,
167
        array $recipient,
168
        string $correlation_id = null
169
    ) {
170
        if ($sender['bankCode']) {
171
            unset($sender['bankCode']);
172
        }
173
174
        return $this->post(
175
            '/fund-transfers',
176
            [
177
                'amount' => $amount,
178
                'description' => $description,
179
                'sender' => $sender,
180
                'recipient' => $recipient
181
            ],
182
            $correlation_id,
183
            true
184
        );
185
    }
186
187
    /**
188
     * Get transfer funds from an account
189
     * @param string $branch
190
     * @param string $account
191
     * @param int $pageSize
192
     * @param string|null $nextPage
193
     * @return array|mixed
194
     * @throws RequestException
195
     */
196
    public function getTransferFunds(string $branch, string $account, int $pageSize = 10, string $nextPage = null)
197
    {
198
        $queryParams = [
199
            'branch' => $branch,
200
            'account' => $account,
201
            'pageSize' => $pageSize
202
        ];
203
        if ($nextPage) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nextPage of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
204
            $queryParams['nextPage'] = $nextPage;
205
        }
206
        return $this->get('/fund-transfers', $queryParams);
207
    }
208
209
    /**
210
     * Get Transfer Funds By Authentication Code
211
     * @param string $branch
212
     * @param string $account
213
     * @param string $authenticationCode
214
     * @return array|mixed
215
     * @throws RequestException
216
     */
217
    public function findTransferFundByAuthCode(string $branch, string $account, string $authenticationCode)
218
    {
219
        $queryParams = [
220
            'branch' => $branch,
221
            'account' => $account
222
        ];
223
        return $this->get('/fund-transfers/' . $authenticationCode, $queryParams);
224
    }
225
226
    /**
227
     * @param string $branch
228
     * @param string $account
229
     * @param string $authentication_id
230
     * @return array|mixed
231
     * @throws RequestException
232
     */
233
    public function getTransferStatus(string $branch, string $account, string $authentication_id)
234
    {
235
        return $this->get('/fund-transfers/' . $authentication_id . '/status', [
236
            'branch' => $branch,
237
            'account' => $account
238
        ]);
239
    }
240
241
    /**
242
     * @param string $documentNumber
243
     * @param DocumentAnalysis $document
244
     * @param string $correlationId
245
     * @return array|mixed
246
     * @throws RequestException
247
     */
248
    public function documentAnalysis(
249
        string $documentNumber,
250
        $document,
251
        string $correlationId = null
252
    ) {
253
        if (!$document instanceof DocumentInterface) {
254
            throw new TypeError('The document must be an instance of DocumentInterface');
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'The document must be an...e of DocumentInterface'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
255
        }
256
257
        return $this->put(
258
            "/document-analysis/{$documentNumber}",
259
            [
260
                'documentType' => $document->getDocumentType(),
261
                'documentSide' => $document->getDocumentSide(),
262
            ],
263
            $correlationId,
264
            true,
265
            true,
266
            $document
267
        );
268
    }
269
270
    /**
271
     * @param string $documentNumber
272
     * @param array $tokens
273
     * @param string $resultLevel
274
     * @param string $correlationId
275
     * @return array|mixed
276
     */
277
    public function getDocumentAnalysis(
278
        string $documentNumber,
279
        array $tokens = [],
280
        string $resultLevel = 'ONLY_STATUS',
281
        string $correlationId = null
282
    ) {
283
        $query = ['resultLevel' => $resultLevel];
284
285
        if (!empty($tokens)) {
286
            $query['token'] = $tokens;
287
        }
288
289
        return $this->get(
290
            "/document-analysis/{$documentNumber}",
291
            $query,
292
            $correlationId
0 ignored issues
show
Bug introduced by
It seems like $correlationId defined by parameter $correlationId on line 281 can also be of type string; however, WeDevBr\Bankly\Bankly::get() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
293
        );
294
    }
295
296
    /**
297
     * @param string $documentNumber
298
     * @param Customer $customer
299
     * @param string $correlationId
300
     * @return array|mixed
301
     * @throws RequestException
302
     */
303
    public function customer(
304
        string $documentNumber,
305
        $customer,
306
        string $correlationId = null
307
    ) {
308
        if (!$customer instanceof CustomerInterface) {
309
            throw new TypeError('The customer must be an instance of CustomerInterface');
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'The customer must be an...e of CustomerInterface'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
310
        }
311
312
        return $this->put("/customers/{$documentNumber}", $customer->toArray(), $correlationId);
313
    }
314
315
    /**
316
     * Validate of boleto or dealership
317
     *
318
     * @param string $code - Digitable line
319
     * @param string $correlationId
320
     * @return array|mixed
321
     * @throws RequestException
322
     */
323
    public function paymentValidate(string $code, string $correlationId)
324
    {
325
        return $this->post('/bill-payment/validate', ['code' => $code], $correlationId, true);
326
    }
327
328
    /**
329
     * Confirmation of payment of boleto or dealership
330
     *
331
     * @param BillPayment $billPayment
332
     * @param string $correlationId
333
     * @return array|mixed
334
     */
335
    public function paymentConfirm(
336
        BillPayment $billPayment,
337
        string $correlationId
338
    ) {
339
        return $this->post('/bill-payment/confirm', $billPayment->toArray(), $correlationId, true);
340
    }
341
342
    /**
343
     * @param string $endpoint
344
     * @param array|null $query
345
     * @param null $correlation_id
346
     * @return array|mixed
347
     * @throws RequestException
348
     */
349
    private function get(string $endpoint, array $query = null, $correlation_id = null)
350
    {
351
        if (now()->unix() > $this->token_expiry || !$this->token) {
352
            $this->auth();
353
        }
354
355
        if (is_null($correlation_id) && $this->requireCorrelationId($endpoint)) {
356
            $correlation_id = Uuid::uuid4()->toString();
357
        }
358
359
        return Http::withToken($this->token)
360
            ->withHeaders($this->getHeaders(['x-correlation-id' => $correlation_id]))
361
            ->get($this->getFinalUrl($endpoint), $query)
362
            ->throw()
363
            ->json();
364
    }
365
366
    /**
367
     * Create a new virtual card
368
     *
369
     * @param VirtualCard $virtualCard
370
     * @return array|mixed
371
     * @throws RequestException
372
     */
373
    public function virtualCard(VirtualCard $virtualCard)
374
    {
375
        return $this->post('/cards/virtual', $virtualCard->toArray(), null, true);
376
    }
377
378
    /**
379
     * @param string $endpoint
380
     * @param array|null $body
381
     * @param string|null $correlation_id
382
     * @param bool $asJson
383
     * @return array|mixed
384
     * @throws RequestException
385
     */
386
    private function post(string $endpoint, array $body = null, string $correlation_id = null, bool $asJson = false)
387
    {
388
        if (now()->unix() > $this->token_expiry || !$this->token) {
389
            $this->auth();
390
        }
391
392
        if (is_null($correlation_id) && $this->requireCorrelationId($endpoint)) {
393
            $correlation_id = Uuid::uuid4()->toString();
394
        }
395
396
        $body_format = $asJson ? 'json' : 'form_params';
397
398
        return Http
399
            ::withToken($this->token)
400
            ->withHeaders($this->getHeaders(['x-correlation-id' => $correlation_id]))
401
            ->bodyFormat($body_format)
402
            ->post($this->getFinalUrl($endpoint), $body)
0 ignored issues
show
Bug introduced by
It seems like $body defined by parameter $body on line 386 can also be of type null; however, Illuminate\Http\Client\PendingRequest::post() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
403
            ->throw()
404
            ->json();
405
    }
406
407
    /**
408
     * @param string $endpoint
409
     * @param array|null $body
410
     * @param string|null $correlation_id
411
     * @param bool $asJson
412
     * @param bool $attachment
413
     * @param DocumentAnalysis $document
414
     * @param string $fieldName
0 ignored issues
show
Bug introduced by
There is no parameter named $fieldName. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
415
     * @return array|mixed
416
     * @throws RequestException
417
     */
418
    private function put(
419
        string $endpoint,
420
        array $body = [],
421
        string $correlation_id = null,
422
        bool $asJson = false,
423
        bool $attachment = false,
424
        DocumentAnalysis $document = null
425
    ) {
426
        if (now()->unix() > $this->token_expiry || !$this->token) {
427
            $this->auth();
428
        }
429
430
        if (is_null($correlation_id) && $this->requireCorrelationId($endpoint)) {
431
            $correlation_id = Uuid::uuid4()->toString();
432
        }
433
434
        $body_format = $asJson ? 'json' : 'form_params';
435
436
        $request = Http
437
            ::withToken($this->token)
438
            ->withHeaders($this->getHeaders(['x-correlation-id' => $correlation_id]))
439
            ->bodyFormat($body_format);
440
441
        if ($attachment) {
442
            $request->attach($document->getFieldName(), $document->getFileContents(), $document->getFileName());
0 ignored issues
show
Bug introduced by
It seems like $document is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
443
        }
444
445
        return $request->put($this->getFinalUrl($endpoint), $body)
446
            ->throw()
447
            ->json();
448
    }
449
450
    /**
451
     * @param string $version API version
452
     * @return $this
453
     */
454
    private function setApiVersion($version = '1.0')
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
455
    {
456
        $this->api_version = $version;
457
        return $this;
458
    }
459
460
    /**
461
     * @param array $headers
462
     * @return array|string[]
463
     */
464
    private function getHeaders($headers = [])
465
    {
466
        $default_headers = [
467
            'API-Version' => $this->api_version
468
        ];
469
470
        if (count($headers) > 0) {
471
            $default_headers = array_merge($headers, $default_headers);
472
        }
473
474
        return $default_headers;
475
    }
476
477
    /**
478
     * @param string $endpoint
479
     * @return bool
480
     */
481
    private function requireCorrelationId(string $endpoint)
482
    {
483
        $not_required_endpoints = [
484
            '/banklist',
485
            '/connect/token'
486
        ];
487
488
        return !in_array($endpoint, $not_required_endpoints);
489
    }
490
491
    /**
492
     * @param string $endpoint
493
     * @return string
494
     */
495
    private function getFinalUrl(string $endpoint)
496
    {
497
        return $this->api_url . $endpoint;
498
    }
499
500
    /**
501
     * Do authentication
502
     * @param string $grant_type Default sets to 'client_credentials'
503
     * @throws RequestException
504
     */
505
    private function auth($grant_type = 'client_credentials'): void
506
    {
507
        //TODO: Add auth for username and password
508
        $body = [
509
            'grant_type' => $grant_type,
510
            'client_secret' => $this->client_secret,
511
            'client_id' => $this->client_id
512
        ];
513
514
        $response = Http::asForm()->post($this->login_url, $body)->throw()->json();
515
        $this->token = $response['access_token'];
516
        $this->token_expiry = now()->addSeconds($response['expires_in'])->unix();
517
    }
518
}
519