Completed
Push — master ( 77cb3d...eaae4c )
by
unknown
24s queued 11s
created

Bankly::getTransferFunds()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
cc 2
nc 2
nop 4
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\Billet\DepositBillet;
14
use WeDevBr\Bankly\Types\Pix\PixEntries;
15
use WeDevBr\Bankly\Types\Card\Card;
16
use WeDevBr\Bankly\Contracts\Pix\PixCashoutInterface;
17
18
/**
19
 * Class Bankly
20
 * @author Adeildo Amorim <[email protected]>
21
 * @package WeDevBr\Bankly
22
 */
23
class Bankly
24
{
25
    public $api_url;
26
    public $login_url;
27
    private $client_id;
28
    private $client_secret;
29
    private $token_expiry = 0;
30
    private $token = null;
31
    private $api_version = '1.0';
32
    private $headers;
33
34
    /**
35
     * Bankly constructor.
36
     * @param null|string $client_secret provided by Bankly Staff
37
     * @param null|string $client_id provided by Bankly Staff
38
     */
39
    public function __construct($client_secret = null, $client_id = null)
40
    {
41
        $this->api_url = config('bankly')['api_url'];
42
        $this->login_url = config('bankly')['login_url'];
43
        $this->setClientCredentials(['client_secret' => $client_secret, 'client_id' => $client_id]);
44
        $this->headers = ['API-Version' => $this->api_version];
45
    }
46
47
    /**
48
     * @param array|null $credentials
49
     * @return $this
50
     */
51
    public function setClientCredentials(array $credentials = null)
52
    {
53
        $this->client_secret = $credentials['client_secret'] ?? config('bankly')['client_secret'];
54
        $this->client_id = $credentials['client_id'] ?? config('bankly')['client_id'];
55
        return $this;
56
    }
57
58
    /**
59
     * @return array|mixed
60
     * @throws RequestException
61
     */
62
    public function getBankList()
63
    {
64
        return $this->get('/banklist');
65
    }
66
67
    /**
68
     * Retrieve your balance account
69
     * @param string $branch
70
     * @param string $account
71
     * @return array|mixed
72
     * @throws RequestException
73
     * @note If you have a RequestException on this endpoint in staging environment, please use getAccount() method instead.
74
     */
75
    public function getBalance(string $branch, string $account)
76
77
    {
78
        return $this->get('/account/balance', [
79
            'branch' => $branch,
80
            'account' => $account
81
        ]);
82
    }
83
84
    /**
85
     * @param string $account
86
     * @param string $includeBalance
87
     * @return array|mixed
88
     * @throws RequestException
89
     * @note This method on this date (2020-10-21) works only on staging environment. Contact Bankly/Acesso for more details
90
     */
91
    public function getAccount(string $account, string $includeBalance = 'true')
92
    {
93
        return $this->get('/accounts/' . $account, [
94
            'includeBalance' => $includeBalance,
95
        ]);
96
    }
97
98
    /**
99
     * @param $branch
100
     * @param $account
101
     * @param int $offset
102
     * @param int $limit
103
     * @param string $details
104
     * @param string $detailsLevelBasic
105
     * @return array|mixed
106
     * @throws RequestException
107
     */
108
    public function getStatement(
109
        $branch,
110
        $account,
111
        $offset = 1,
112
        $limit = 20,
113
        string $details = 'true',
114
        string $detailsLevelBasic = 'true'
115
    ) {
116
        return $this->get('/account/statement', array(
117
            'branch' => $branch,
118
            'account' => $account,
119
            'offset' => $offset,
120
            'limit' => $limit,
121
            'details' => $details,
122
            'detailsLevelBasic' => $detailsLevelBasic
123
        ));
124
    }
125
126
    /**
127
     * @param string $branch
128
     * @param string $account
129
     * @param int $page
130
     * @param int $pagesize
131
     * @param string $include_details
132
     * @param string[] $cardProxy
133
     * @param string|null $begin_date
134
     * @param string|null $end_date
135
     * @return array|mixed
136
     * @throws RequestException
137
     * @note This endpoint has been deprecated for some clients.
138
     * You need to check with Acesso/Bankly if your environment has different parameters also.
139
     * The response of this request does not have a default interface between environments.
140
     * Pay attention when use this in your project.
141
     */
142
    public function getEvents(
143
        string $branch,
144
        string $account,
145
        int $page = 1,
146
        int $pagesize = 20,
147
        string $include_details = 'true',
148
        array $cardProxy = [],
149
        string $begin_date = null,
150
        string $end_date = null
151
    ) {
152
        $query = [
153
            'branch' => $branch,
154
            'account' => $account,
155
            'page' => $page,
156
            'pageSize' => $pagesize,
157
            'includeDetails' => $include_details
158
        ];
159
160
        if (!empty($cardProxy)) {
161
            $query['cardProxy'] = $cardProxy;
162
        }
163
164
        if ($begin_date) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $begin_date 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...
165
            $query['beginDateTime'] = $begin_date;
166
        }
167
168
        if ($end_date) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $end_date 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...
169
            $query['endDateTime'] = $end_date;
170
        }
171
172
        return $this->get(
173
            '/events',
174
            $query
175
        );
176
    }
177
178
    /**
179
     * @param int $amount
180
     * @param string $description
181
     * @param array $sender
182
     * @param array $recipient
183
     * @param string|null $correlation_id
184
     * @return array|mixed
185
     * @throws RequestException
186
     */
187
    public function transfer(
188
        int $amount,
189
        string $description,
190
        array $sender,
191
        array $recipient,
192
        string $correlation_id = null
193
    ) {
194
        if ($sender['bankCode']) {
195
            unset($sender['bankCode']);
196
        }
197
198
        return $this->post(
199
            '/fund-transfers',
200
            [
201
                'amount' => $amount,
202
                'description' => $description,
203
                'sender' => $sender,
204
                'recipient' => $recipient
205
            ],
206
            $correlation_id,
207
            true
208
        );
209
    }
210
211
    /**
212
     * Get transfer funds from an account
213
     * @param string $branch
214
     * @param string $account
215
     * @param int $pageSize
216
     * @param string|null $nextPage
217
     * @return array|mixed
218
     * @throws RequestException
219
     */
220
    public function getTransferFunds(string $branch, string $account, int $pageSize = 10, string $nextPage = null)
221
    {
222
        $queryParams = [
223
            'branch' => $branch,
224
            'account' => $account,
225
            'pageSize' => $pageSize
226
        ];
227
        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...
228
            $queryParams['nextPage'] = $nextPage;
229
        }
230
        return $this->get('/fund-transfers', $queryParams);
231
    }
232
233
    /**
234
     * Get Transfer Funds By Authentication Code
235
     * @param string $branch
236
     * @param string $account
237
     * @param string $authenticationCode
238
     * @return array|mixed
239
     * @throws RequestException
240
     */
241
    public function findTransferFundByAuthCode(string $branch, string $account, string $authenticationCode)
242
    {
243
        $queryParams = [
244
            'branch' => $branch,
245
            'account' => $account
246
        ];
247
        return $this->get('/fund-transfers/' . $authenticationCode, $queryParams);
248
    }
249
250
    /**
251
     * @param string $branch
252
     * @param string $account
253
     * @param string $authentication_id
254
     * @return array|mixed
255
     * @throws RequestException
256
     */
257
    public function getTransferStatus(string $branch, string $account, string $authentication_id)
258
    {
259
        return $this->get('/fund-transfers/' . $authentication_id . '/status', [
260
            'branch' => $branch,
261
            'account' => $account
262
        ]);
263
    }
264
265
    /**
266
     * @param string $documentNumber
267
     * @param DocumentAnalysis $document
268
     * @param string $correlationId
269
     * @return array|mixed
270
     * @throws RequestException
271
     */
272
    public function documentAnalysis(
273
        string $documentNumber,
274
        $document,
275
        string $correlationId = null
276
    ) {
277
        if (!$document instanceof DocumentInterface) {
278
            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...
279
        }
280
281
        return $this->put(
282
            "/document-analysis/{$documentNumber}",
283
            [
284
                'documentType' => $document->getDocumentType(),
285
                'documentSide' => $document->getDocumentSide(),
286
            ],
287
            $correlationId,
288
            true,
289
            true,
290
            $document
291
        );
292
    }
293
294
    /**
295
     * @param string $documentNumber
296
     * @param array $tokens
297
     * @param string $resultLevel
298
     * @param string $correlationId
299
     * @return array|mixed
300
     */
301
    public function getDocumentAnalysis(
302
        string $documentNumber,
303
        array $tokens = [],
304
        string $resultLevel = 'ONLY_STATUS',
305
        string $correlationId = null
306
    ) {
307
        $query = collect($tokens)
308
            ->map(function ($token) {
309
                return "token={$token}";
310
            })
311
            ->concat(["resultLevel={$resultLevel}"])
312
            ->implode('&');
313
314
        return $this->get(
315
            "/document-analysis/{$documentNumber}",
316
            $query,
317
            $correlationId
0 ignored issues
show
Bug introduced by
It seems like $correlationId defined by parameter $correlationId on line 305 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...
318
        );
319
    }
320
321
    /**
322
     * @param string $documentNumber
323
     * @param Customer $customer
324
     * @param string $correlationId
325
     * @return array|mixed
326
     * @throws RequestException
327
     */
328
    public function customer(
329
        string $documentNumber,
330
        $customer,
331
        string $correlationId = null
332
    ) {
333
        if (!$customer instanceof CustomerInterface) {
334
            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...
335
        }
336
337
        return $this->put("/customers/{$documentNumber}", $customer->toArray(), $correlationId);
338
    }
339
340
    /**
341
     * Validate of boleto or dealership
342
     *
343
     * @param string $code - Digitable line
344
     * @param string $correlationId
345
     * @return array|mixed
346
     * @throws RequestException
347
     */
348
    public function paymentValidate(string $code, string $correlationId)
349
    {
350
        return $this->post('/bill-payment/validate', ['code' => $code], $correlationId, true);
351
    }
352
353
    /**
354
     * Confirmation of payment of boleto or dealership
355
     *
356
     * @param BillPayment $billPayment
357
     * @param string $correlationId
358
     * @return array|mixed
359
     */
360
    public function paymentConfirm(
361
        BillPayment $billPayment,
362
        string $correlationId
363
    ) {
364
        return $this->post('/bill-payment/confirm', $billPayment->toArray(), $correlationId, true);
365
    }
366
367
    /**
368
     * @param DepositBillet $depositBillet
369
     * @return array|mixed
370
     */
371
    public function depositBillet(DepositBillet $depositBillet)
372
    {
373
        return $this->post('/bankslip', $depositBillet->toArray(), null, true);
374
    }
375
376
    /**
377
     * @param string $authenticationCode
378
     * @return mixed
379
     */
380
    public function printBillet(string $authenticationCode)
381
    {
382
        return $this->get("/bankslip/{$authenticationCode}/pdf");
383
    }
384
385
    /**
386
     * @param string $branch
387
     * @param string $accountNumber
388
     * @param string $authenticationCode
389
     * @return array|mixed
390
     */
391
    public function getBillet(string $branch, string $accountNumber, string $authenticationCode)
392
    {
393
        return $this->get("/bankslip/branch/{$branch}/number/{$accountNumber}/{$authenticationCode}");
394
    }
395
396
    /**
397
     * @param string $datetime
398
     * @return array|mixed
399
     */
400
    public function getBilletByDate(string $datetime)
401
    {
402
        return $this->get("/bankslip/searchstatus/{$datetime}");
403
    }
404
405
    /**
406
     * @param string $barcode
407
     * @return array|mixed
408
     */
409
    public function getBilletByBarcode(string $barcode)
410
    {
411
        return $this->get("/bankslip/{$barcode}");
412
    }
413
414
    /**
415
     * Create a new PIX key link with account.
416
     *
417
     * @param PixEntries $pixEntries
418
     * @return array|mixed
419
     */
420
    public function registerPixKey(PixEntries $pixEntries)
421
    {
422
        return $this->post('/pix/entries', [
423
            'addressingKey' => $pixEntries->addressingKey->toArray(),
424
            'account' => $pixEntries->account->toArray(),
425
        ], null, true);
426
    }
427
428
    /**
429
     * Gets the list of address keys linked to an account.
430
     *
431
     * @param string $accountNumber
432
     * @return array|mixed
433
     */
434
    public function getPixAddressingKeys(string $accountNumber)
435
    {
436
        return $this->get("/accounts/$accountNumber/addressing-keys");
437
    }
438
439
    /**
440
     * Gets details of the account linked to an addressing key.
441
     *
442
     * @param string $documentNumber
443
     * @param string $addressinKeyValue
444
     * @return array|mixed
445
     */
446
    public function getPixAddressingKeyValue(string $documentNumber, string $addressinKeyValue)
447
    {
448
        $this->setHeaders(['x-bkly-pix-user-id' => $documentNumber]);
449
        return $this->get("/pix/entries/$addressinKeyValue");
450
    }
451
452
    /**
453
     * Delete a key link with account.
454
     *
455
     * @param string $addressingKeyValue
456
     * @return array|mixed
457
     */
458
    public function deletePixAddressingKeyValue(string $addressingKeyValue)
459
    {
460
        return $this->delete("/pix/entries/$addressingKeyValue");
461
    }
462
463
    /**
464
     * @param PixCashoutInterface $pixCashout
465
     * @param string $correlationId
466
     * @return array|mixed
467
     */
468
    public function pixCashout(PixCashoutInterface $pixCashout, string $correlationId)
469
    {
470
        return $this->post('/pix/cash-out', $pixCashout->toArray(), $correlationId, true);
471
    }
472
473
    /**
474
     * @param string $endpoint
475
     * @param array|string|null $query
476
     * @param null $correlation_id
477
     * @return array|mixed
478
     * @throws RequestException
479
     */
480
    private function get(string $endpoint, $query = null, $correlation_id = null)
481
    {
482
        if (now()->unix() > $this->token_expiry || !$this->token) {
483
            $this->auth();
484
        }
485
486
        if (is_null($correlation_id) && $this->requireCorrelationId($endpoint)) {
487
            $correlation_id = Uuid::uuid4()->toString();
488
        }
489
490
        return Http::withToken($this->token)
491
            ->withHeaders($this->getHeaders(['x-correlation-id' => $correlation_id]))
492
            ->get($this->getFinalUrl($endpoint), $query)
493
            ->throw()
494
            ->json();
495
    }
496
497
    /**
498
     * Create a new virtual card
499
     *
500
     * @param Card $virtualCard
501
     * @return array|mixed
502
     * @throws RequestException
503
     */
504
    public function virtualCard(Card $virtualCard)
505
    {
506
        return $this->post('/cards/virtual', $virtualCard->toArray(), null, true);
507
    }
508
509
    /**
510
     * Create a new virtual card
511
     *
512
     * @param Card $virtualCard
0 ignored issues
show
Bug introduced by
There is no parameter named $virtualCard. 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...
513
     * @return array|mixed
514
     * @throws RequestException
515
     */
516
    public function phisicalCard(Card $phisicalCard)
517
    {
518
        return $this->post('/cards/phisical', $phisicalCard->toArray(), null, true);
519
    }
520
521
    /**
522
     * @param string $endpoint
523
     * @param array|null $body
524
     * @param string|null $correlation_id
525
     * @param bool $asJson
526
     * @return array|mixed
527
     * @throws RequestException
528
     */
529
    private function post(string $endpoint, array $body = null, string $correlation_id = null, bool $asJson = false)
530
    {
531
        if (now()->unix() > $this->token_expiry || !$this->token) {
532
            $this->auth();
533
        }
534
535
        if (is_null($correlation_id) && $this->requireCorrelationId($endpoint)) {
536
            $correlation_id = Uuid::uuid4()->toString();
537
        }
538
539
        $body_format = $asJson ? 'json' : 'form_params';
540
541
        return Http
542
            ::withToken($this->token)
543
            ->withHeaders($this->getHeaders(['x-correlation-id' => $correlation_id]))
544
            ->bodyFormat($body_format)
545
            ->post($this->getFinalUrl($endpoint), $body)
0 ignored issues
show
Bug introduced by
It seems like $body defined by parameter $body on line 529 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...
546
            ->throw()
547
            ->json();
548
    }
549
550
    /**
551
     * @param string $endpoint
552
     * @param array|null $body
553
     * @param string|null $correlation_id
554
     * @param bool $asJson
555
     * @param bool $attachment
556
     * @param DocumentAnalysis $document
557
     * @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...
558
     * @return array|mixed
559
     * @throws RequestException
560
     */
561
    private function put(
562
        string $endpoint,
563
        array $body = [],
564
        string $correlation_id = null,
565
        bool $asJson = false,
566
        bool $attachment = false,
567
        DocumentAnalysis $document = null
568
    ) {
569
        if (now()->unix() > $this->token_expiry || !$this->token) {
570
            $this->auth();
571
        }
572
573
        if (is_null($correlation_id) && $this->requireCorrelationId($endpoint)) {
574
            $correlation_id = Uuid::uuid4()->toString();
575
        }
576
577
        $body_format = $asJson ? 'json' : 'form_params';
578
579
        $request = Http
580
            ::withToken($this->token)
581
            ->withHeaders($this->getHeaders(['x-correlation-id' => $correlation_id]))
582
            ->bodyFormat($body_format);
583
584
        if ($attachment) {
585
            $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...
586
        }
587
588
        return $request->put($this->getFinalUrl($endpoint), $body)
589
            ->throw()
590
            ->json();
591
    }
592
593
    /**
594
     * Http delete method.
595
     *
596
     * @param string $endpoint
597
     * @return array|mixed
598
     * @throws RequestException
599
     */
600
    private function delete(string $endpoint)
601
    {
602
        if (now()->unix() > $this->token_expiry || !$this->token) {
603
            $this->auth();
604
        }
605
606
        $request = Http::withToken($this->token)
607
            ->withHeaders($this->getHeaders($this->headers));
608
609
        return $request->delete($this->getFinalUrl($endpoint))
610
            ->throw()
611
            ->json();
612
    }
613
614
    /**
615
     * @param string $version API version
616
     * @return $this
617
     */
618
    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...
619
    {
620
        $this->api_version = $version;
621
        return $this;
622
    }
623
624
    /**
625
     * @param array $headers
626
     * @return array|string[]
627
     */
628
    private function getHeaders($headers = [])
629
    {
630
        $default_headers = $this->headers;
631
632
        if (count($headers) > 0) {
633
            $default_headers = array_merge($headers, $default_headers);
634
        }
635
636
        return $default_headers;
637
    }
638
639
    /**
640
     * @param array $header
641
     * @return void
642
     */
643
    private function setHeaders($header)
644
    {
645
        $this->headers = array_merge($this->headers, $header);
646
    }
647
648
    /**
649
     * @param string $endpoint
650
     * @return bool
651
     */
652
    private function requireCorrelationId(string $endpoint)
653
    {
654
        $not_required_endpoints = [
655
            '/banklist',
656
            '/connect/token'
657
        ];
658
659
        return !in_array($endpoint, $not_required_endpoints);
660
    }
661
662
    /**
663
     * @param string $endpoint
664
     * @return string
665
     */
666
    private function getFinalUrl(string $endpoint)
667
    {
668
        return $this->api_url . $endpoint;
669
    }
670
671
    /**
672
     * Do authentication
673
     * @param string $grant_type Default sets to 'client_credentials'
674
     * @throws RequestException
675
     */
676
    private function auth($grant_type = 'client_credentials'): void
677
    {
678
        //TODO: Add auth for username and password
679
        $body = [
680
            'grant_type' => $grant_type,
681
            'client_secret' => $this->client_secret,
682
            'client_id' => $this->client_id
683
        ];
684
685
        $response = Http::asForm()->post($this->login_url, $body)->throw()->json();
686
        $this->token = $response['access_token'];
687
        $this->token_expiry = now()->addSeconds($response['expires_in'])->unix();
688
    }
689
}
690