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