ApiClient::tax()   A
last analyzed

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