Issues (7)

src/Api/Income.php (1 issue)

Labels
Severity
1
<?php
2
declare(strict_types=1);
3
4
namespace Shoman4eg\Nalog\Api;
5
6
use Brick\Math\BigDecimal;
7
use Psr\Http\Client\ClientExceptionInterface;
8
use Shoman4eg\Nalog\DTO;
9
use Shoman4eg\Nalog\Enum;
10
use Shoman4eg\Nalog\ErrorHandler;
11
use Shoman4eg\Nalog\Exception;
12
use Shoman4eg\Nalog\Model\Income\IncomeInfoType;
13
use Shoman4eg\Nalog\Model\Income\IncomeType;
14
use Webmozart\Assert\Assert;
15
16
/**
17
 * @author Artem Dubinin <[email protected]>
18
 */
19
final class Income extends BaseHttpApi
20
{
21
    /**
22
     * @param float|int $amount
23
     * @param float|int $quantity
24
     *
25
     * @throws \JsonException
26
     * @throws ClientExceptionInterface
27
     * @throws Exception\DomainException
28
     */
29
    public function create(
30
        string $name,
31
        $amount,
32
        $quantity,
33
        ?\DateTimeInterface $operationTime = null,
34
        ?DTO\IncomeClient $client = null
35
    ): IncomeType {
36
        return $this->createMultipleItems(
37
            [new DTO\IncomeServiceItem($name, $amount, $quantity)],
38
            $operationTime,
39
            $client
40
        );
41
    }
42
43
    /**
44
     * @param DTO\IncomeServiceItem[] $serviceItems
45
     *
46
     * @throws \JsonException
47
     * @throws ClientExceptionInterface
48
     * @throws Exception\DomainException
49
     */
50
    public function createMultipleItems(
51
        array $serviceItems,
52
        ?\DateTimeInterface $operationTime = null,
53
        ?DTO\IncomeClient $client = null
54
    ): IncomeType {
55
        Assert::minCount($serviceItems, 1, 'Items cannot be empty');
56
        Assert::allIsInstanceOf($serviceItems, DTO\IncomeServiceItem::class);
57
58
        foreach ($serviceItems as $key => $serviceItem) {
59
            Assert::notEmpty($serviceItem->getName(), "Name of item[{$key}] cannot be empty");
60
            Assert::numeric($serviceItem->getAmount(), "Amount of item[{$key}] must be int or float");
61
            Assert::greaterThan($serviceItem->getAmount(), 0, "Amount of item[{$key}] must be greater than %2\$s");
62
            Assert::notEmpty($serviceItem->getQuantity(), "Quantity of item[{$key}] cannot be empty");
63
            Assert::numeric($serviceItem->getQuantity(), "Quantity of item[{$key}] must be int or float");
64
            Assert::greaterThan($serviceItem->getQuantity(), 0, "Quantity of item[{$key}] must be greater than %2\$s");
65
        }
66
67
        $totalAmount = array_reduce(
68
            $serviceItems,
69
            fn ($totalAmount, $serviceItem): BigDecimal => $totalAmount->plus($serviceItem->getTotalAmount()),
70
            BigDecimal::of(0)
71
        );
72
73
        if ($client !== null && $client->getIncomeType() === Enum\IncomeType::LEGAL_ENTITY) {
74
            Assert::notEmpty($client->getInn(), 'Client INN cannot be empty');
75
            Assert::numeric($client->getInn(), 'Client INN must contain only numbers');
76
            Assert::oneOf(mb_strlen($client->getInn()), [10, 12], 'Client INN length must been 10 or 12');
0 ignored issues
show
It seems like $client->getInn() can also be of type null; however, parameter $string of mb_strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

76
            Assert::oneOf(mb_strlen(/** @scrutinizer ignore-type */ $client->getInn()), [10, 12], 'Client INN length must been 10 or 12');
Loading history...
77
            Assert::notEmpty($client->getDisplayName(), 'Client DisplayName cannot be empty');
78
        }
79
80
        $response = $this->httpPost('/income', [
81
            'operationTime' => new DTO\DateTime($operationTime ?: new \DateTimeImmutable()),
82
            'requestTime' => new DTO\DateTime(new \DateTimeImmutable()),
83
            'services' => $serviceItems,
84
            'totalAmount' => (string)$totalAmount,
85
            'client' => $client ?? new DTO\IncomeClient(),
86
            'paymentType' => Enum\PaymentType::CASH,
87
            'ignoreMaxTotalIncomeRestriction' => false,
88
        ]);
89
90
        if ($response->getStatusCode() >= 400) {
91
            (new ErrorHandler())->handleResponse($response);
92
        }
93
94
        return $this->hydrator->hydrate($response, IncomeType::class);
95
    }
96
97
    /**
98
     * @throws \JsonException
99
     * @throws ClientExceptionInterface
100
     * @throws Exception\DomainException
101
     */
102
    public function cancel(
103
        string $receiptUuid,
104
        string $comment,
105
        ?\DateTimeImmutable $operationTime = null,
106
        ?\DateTimeImmutable $requestTime = null,
107
        ?string $partnerCode = null
108
    ): IncomeInfoType {
109
        Assert::notEmpty($receiptUuid, 'ReceiptUuid cannot be empty');
110
        Assert::oneOf($comment, Enum\CancelCommentType::all(), 'Comment is invalid. Must be one of: %2$s');
111
112
        $response = $this->httpPost('/cancel', [
113
            'operationTime' => new DTO\DateTime($operationTime ?: new \DateTimeImmutable()),
114
            'requestTime' => new DTO\DateTime($requestTime ?: new \DateTimeImmutable()),
115
            'comment' => $comment,
116
            'receiptUuid' => $receiptUuid,
117
            'partnerCode' => $partnerCode,
118
        ]);
119
120
        if ($response->getStatusCode() >= 400) {
121
            (new ErrorHandler())->handleResponse($response);
122
        }
123
124
        return $this->hydrator->hydrate($response, IncomeInfoType::class);
125
    }
126
}
127