Passed
Push — master ( 049c4c...7327a7 )
by Artem
01:51
created

ApiClient::tax()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace Shoman4eg\Nalog;
5
6
use Psr\Http\Client\ClientExceptionInterface;
7
use Psr\Http\Client\ClientInterface;
8
use Shoman4eg\Nalog\Http\AuthenticationPlugin;
9
use Shoman4eg\Nalog\Http\Authenticator;
10
use Shoman4eg\Nalog\Http\ClientConfigurator;
11
use Shoman4eg\Nalog\Model\User\UserType;
12
use Shoman4eg\Nalog\Service\Generator\DeviceIdGenerator;
13
use Shoman4eg\Nalog\Util\JSON;
14
15
/**
16
 * @author Artem Dubinin <[email protected]>
17
 */
18
final class ApiClient
19
{
20
    private RequestBuilder $requestBuilder;
21
    private ClientConfigurator $clientConfigurator;
22
    private Authenticator $authenticator;
23
    private ?UserType $profile;
24
25
    /**
26
     * The constructor accepts already configured HTTP clients.
27
     * Use the configure method to pass a configuration to the Client and create an HTTP Client.
28
     */
29
    public function __construct(
30
        ClientConfigurator $clientConfigurator,
31
        ?RequestBuilder $requestBuilder = null,
32
        ?DeviceIdGenerator $deviceIdGenerator = null
33
    ) {
34
        $this->clientConfigurator = $clientConfigurator;
35
        $this->requestBuilder = $requestBuilder ?: new RequestBuilder();
36
        $deviceIdGenerator ??= new DeviceIdGenerator();
37
        $this->authenticator = new Authenticator(
38
            $this->requestBuilder,
39
            $this->clientConfigurator->createConfiguredClient(),
40
            $deviceIdGenerator->generate()
41
        );
42
    }
43
44
    public static function create(): self
45
    {
46
        $clientConfigurator = new ClientConfigurator();
47
48
        return new self($clientConfigurator);
49
    }
50
51
    public static function createWithEndpoint(string $endpoint): self
52
    {
53
        $clientConfigurator = new ClientConfigurator();
54
        $clientConfigurator->setEndpoint($endpoint);
55
56
        return new self($clientConfigurator);
57
    }
58
59
    public static function createWithCustomClient(ClientInterface $client): self
60
    {
61
        return new self(new ClientConfigurator($client));
62
    }
63
64
    /**
65
     * Warning, this will remove the current access token.
66
     *
67
     * @throws \JsonException
68
     * @throws ClientExceptionInterface
69
     * @throws Exception\DomainException
70
     */
71
    public function createNewAccessToken(string $username, string $password): ?string
72
    {
73
        $this->clientConfigurator->removePlugin(AuthenticationPlugin::class);
74
75
        return $this->authenticator->createAccessToken($username, $password);
76
    }
77
78
    /**
79
     * Used as the first step, before createPhoneChallenge().
80
     *
81
     * Request the verification code in the SMS-message for authorization by phone number.
82
     * Returns the call token and its lifetime.
83
     *
84
     * Save the phone number and call token. When the user specifies the code from the SMS,
85
     * pass them to createNewAccessTokenByPhone() along with the code from the SMS
86
     *
87
     * Remember that there are restrictions on sending SMS. The value seems to be dynamic,
88
     * approximately 1 message every 1-2 minutes.
89
     * The restriction is removed after a successful createNewAccessTokenByPhone()
90
     *
91
     * @return array{challengeToken: string, expireDate: string, expireIn: int}
92
     *
93
     * @throws \JsonException
94
     * @throws ClientExceptionInterface
95
     * @throws Exception\DomainException
96
     */
97
    public static function createPhoneChallenge(string $phone): array
98
    {
99
        $client = self::create();
100
        $client->clientConfigurator->setVersion('v2');
101
        $client->clientConfigurator->removePlugin(AuthenticationPlugin::class);
102
103
        return $client->authenticator->createPhoneChallenge($phone);
104
    }
105
106
    /**
107
     * Used as the second step, after createPhoneChallenge()
108
     * Warning, this will remove the current access token.
109
     *
110
     * @throws \JsonException
111
     * @throws ClientExceptionInterface
112
     * @throws Exception\DomainException
113
     */
114
    public function createNewAccessTokenByPhone(string $phone, string $challengeToken, string $verificationCode): ?string
115
    {
116
        $this->clientConfigurator->removePlugin(AuthenticationPlugin::class);
117
118
        return $this->authenticator->createAccessTokenByPhone($phone, $challengeToken, $verificationCode);
119
    }
120
121
    /**
122
     * Authenticate the client with an access token. This should be the full access token object with
123
     * refresh token and expire timestamps.
124
     *
125
     * ```php
126
     *   $accessToken = $client->createNewAccessToken('inn', 'password');
127
     *   $client->authenticate($accessToken);
128
     *```
129
     *
130
     * @throws \JsonException
131
     */
132
    public function authenticate(string $accessToken): void
133
    {
134
        $this->clientConfigurator->removePlugin(AuthenticationPlugin::class);
135
        $this->clientConfigurator->appendPlugin(new AuthenticationPlugin($this->authenticator, $accessToken));
136
        if (($token = JSON::decode($accessToken)) && array_key_exists('profile', $token)) {
137
            $this->profile = UserType::createFromArray($token['profile']);
138
        }
139
        $this->authenticator->setAccessToken($accessToken);
140
    }
141
142
    /**
143
     * The access token may have been refreshed during the requests. Use this function to
144
     * get back the (possibly) refreshed access token.
145
     */
146
    public function getAccessToken(): ?string
147
    {
148
        return $this->authenticator->getAccessToken();
149
    }
150
151
    public function income(): Api\Income
152
    {
153
        return new Api\Income($this->getHttpClient(), $this->requestBuilder);
154
    }
155
156
    public function receipt(): Api\Receipt
157
    {
158
        return new Api\Receipt(
159
            $this->getHttpClient(),
160
            $this->requestBuilder,
161
            $this->profile ?? $this->user()->get(),
162
            (string)$this->clientConfigurator->getEndpoint()
163
        );
164
    }
165
166
    public function user(): Api\User
167
    {
168
        return new Api\User($this->getHttpClient(), $this->requestBuilder);
169
    }
170
171
    public function paymentType(): Api\PaymentType
172
    {
173
        return new Api\PaymentType($this->getHttpClient(), $this->requestBuilder);
174
    }
175
176
    public function tax(): Api\Tax
177
    {
178
        return new Api\Tax($this->getHttpClient(), $this->requestBuilder);
179
    }
180
181
    private function getHttpClient(): ClientInterface
182
    {
183
        return $this->clientConfigurator->createConfiguredClient();
184
    }
185
}
186