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
Bug
introduced
by
![]() |
|||
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 |