Skip to content

Commit

Permalink
Release 0.3.0 (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
shoman4eg authored May 14, 2022
1 parent e11425e commit a296399
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 26 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
All notable changes to this project will be documented in this file.
<!--- END HEADER -->

## [0.3.0](https://github.com/shoman4eg/moy-nalog/compare/v0.2.3...v0.3.0) (2022-05-15)
### Features
* Add new method for income with multiple items #14

### Documentation
* Update README with new income method

---

## [0.2.3](https://github.com/shoman4eg/moy-nalog/compare/v0.2.2...v0.2.3) (2022-04-11)
### Fix
* Change uses for avoid className conflicts
Expand All @@ -23,7 +32,6 @@ All notable changes to this project will be documented in this file.

### Documentation
* Fix cancel income method docs

* Ошибка в документации #9

### Fix
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,22 @@ $apiClient->authenticate($accessToken);
$name = 'Предоставление информационных услуг #970/2495';
$amount = 1800.30;
$quantity = 1;
$amount = 1;
$operationTime = new DateTimeImmutable('2020-12-31 12:12:00');
$createdIncome = $apiClient->income()->create($name, $amount, $quantity, $operationTime);
```

### Create income with multiple items
```php
$name = 'Предоставление информационных услуг #970/2495';
$items = [
new Shoman4eg\Nalog\DTO\IncomeServiceItem($name, $amount = 1800.30, $quantity = 1),
new Shoman4eg\Nalog\DTO\IncomeServiceItem($name, $amount = 900, $quantity = 2),
new Shoman4eg\Nalog\DTO\IncomeServiceItem($name, $amount = '1399.99', $quantity = 3),
];
$operationTime = new DateTimeImmutable('2020-12-31 12:12:00');
$createdIncome = $apiClient->income()->createMultipleItems($items, $operationTime);
```

### Create income with custom client
```php
$name = 'Предоставление информационных услуг #970/2495';
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "shoman4eg/moy-nalog",
"description": "An unofficial wrapper client for lknpd.nalog.ru API",
"license": "MIT",
"version": "0.2.3",
"version": "0.3.0",
"keywords": [
"api",
"nalog.ru"
Expand Down
49 changes: 39 additions & 10 deletions src/Api/Income.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

declare(strict_types=1);

namespace Shoman4eg\Nalog\Api;
Expand Down Expand Up @@ -32,26 +33,54 @@ public function create(
\DateTimeInterface $operationTime = null,
DTO\IncomeClient $client = null
): IncomeType {
Assert::notEmpty($name, 'Name cannot be empty');
Assert::numeric($amount, 'Amount must be int or float');
Assert::greaterThan($amount, 0, 'Amount must be greater than %2$s');
Assert::notEmpty($quantity, 'Quantity cannot be empty');
Assert::numeric($quantity, 'Quantity must be int or float');
Assert::greaterThan($quantity, 0, 'Quantity must be greater than %2$s');
return $this->createMultipleItems(
[new DTO\IncomeServiceItem($name, $amount, $quantity)],
$operationTime,
$client
);
}

/**
* @param DTO\IncomeServiceItem[] $serviceItems
*
* @throws ClientExceptionInterface
* @throws Exception\DomainException
* @throws \JsonException
*/
public function createMultipleItems(
array $serviceItems,
\DateTimeInterface $operationTime = null,
DTO\IncomeClient $client = null
): IncomeType {
Assert::minCount($serviceItems, 1, 'Items cannot be empty');
Assert::allIsInstanceOf($serviceItems, DTO\IncomeServiceItem::class);

foreach ($serviceItems as $key => $serviceItem) {
Assert::notEmpty($serviceItem->getName(), "Name of item[{$key}] cannot be empty");
Assert::numeric($serviceItem->getAmount(), "Amount of item[{$key}] must be int or float");
Assert::greaterThan($serviceItem->getAmount(), 0, "Amount of item[{$key}] must be greater than %2\$s");
Assert::notEmpty($serviceItem->getQuantity(), "Quantity of item[{$key}] cannot be empty");
Assert::numeric($serviceItem->getQuantity(), "Quantity of item[{$key}] must be int or float");
Assert::greaterThan($serviceItem->getQuantity(), 0, "Quantity of item[{$key}] must be greater than %2\$s");
}

$totalAmount = array_reduce(
$serviceItems,
fn ($totalAmount, $serviceItem) => $totalAmount->plus($serviceItem->getTotalAmount()),
BigDecimal::of(0)
);

if ($client !== null && $client->getIncomeType() === Enum\IncomeType::LEGAL_ENTITY) {
Assert::notEmpty($client->getInn(), 'Client INN cannot be empty');
Assert::numeric($client->getInn(), 'Client INN must contain only numbers');
Assert::lengthBetween($client->getInn(), 10, 12, 'Client INN length must been 10 or 12');
Assert::oneOf(mb_strlen($client->getInn()), [10, 12], 'Client INN length must been 10 or 12');
Assert::notEmpty($client->getDisplayName(), 'Client DisplayName cannot be empty');
}

$totalAmount = BigDecimal::of($amount)->multipliedBy($quantity);

$response = $this->httpPost('/income', [
'operationTime' => new DTO\DateTime($operationTime ?: new \DateTimeImmutable()),
'requestTime' => new DTO\DateTime(new \DateTimeImmutable()),
'services' => [new DTO\IncomeServiceItem($name, $amount, $quantity)],
'services' => $serviceItems,
'totalAmount' => (string)$totalAmount,
'client' => $client ?? new DTO\IncomeClient(),
'paymentType' => Enum\PaymentType::CASH,
Expand Down
30 changes: 30 additions & 0 deletions src/DTO/IncomeServiceItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

namespace Shoman4eg\Nalog\DTO;

use Brick\Math\BigDecimal;

/**
* @author Artem Dubinin <artem@dubinin.me>
*/
Expand Down Expand Up @@ -31,4 +33,32 @@ public function jsonSerialize(): array
'quantity' => $this->quantity,
];
}

public function getName(): string
{
return $this->name;
}

/**
* @return float|int|string
*/
public function getAmount()
{
return $this->amount;
}

/**
* @return float|int
*/
public function getQuantity()
{
return $this->quantity;
}

public function getTotalAmount(): BigDecimal
{
return BigDecimal::of($this->amount)
->multipliedBy($this->quantity)
;
}
}
67 changes: 54 additions & 13 deletions tests/Api/IncomeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,19 @@ public function testCreateLegalEntityClient(): void

public function validationCreateDataProvider(): iterable
{
yield ['', 100, 1, null, 'Name cannot be empty'];
yield ['name', '', 1, null, 'Amount must be int or float'];
yield ['name', -1, 1, null, 'Amount must be greater than 0'];
yield ['name', 1, 0, null, 'Quantity cannot be empty'];
yield ['name', 1, 'zero', null, 'Quantity must be int or float'];
yield ['name', 1, 1, new DTO\IncomeClient(null, '', IncomeType::LEGAL_ENTITY, ''), 'Client INN cannot be empty'];
yield ['name', 1, 1, new DTO\IncomeClient(null, '', IncomeType::LEGAL_ENTITY, 'aaaa'), 'Client INN must contain only numbers'];
yield ['name', 1, 1, new DTO\IncomeClient(null, '', IncomeType::LEGAL_ENTITY, '1234'), 'Client INN length must been 10 or 12'];
yield ['name', 1, 1, new DTO\IncomeClient(null, '', IncomeType::LEGAL_ENTITY, '1234567890'), 'Client DisplayName cannot be empty'];
$fakeClientWithInn = static fn ($inn) => new DTO\IncomeClient(null, '', IncomeType::LEGAL_ENTITY, $inn);

yield ['', 100, 1, null, 'Name of item[0] cannot be empty'];
yield ['name', '', 1, null, 'Amount of item[0] must be int or float'];
yield ['name', -1, 1, null, 'Amount of item[0] must be greater than 0'];
yield ['name', 1, 0, null, 'Quantity of item[0] cannot be empty'];
yield ['name', 1, 'zero', null, 'Quantity of item[0] must be int or float'];
yield ['name', 1, 1, $fakeClientWithInn(''), 'Client INN cannot be empty'];
yield ['name', 1, 1, $fakeClientWithInn('aaaa'), 'Client INN must contain only numbers'];
yield ['name', 1, 1, $fakeClientWithInn(str_repeat('1', 9)), 'Client INN length must been 10 or 12'];
yield ['name', 1, 1, $fakeClientWithInn(str_repeat('1', 11)), 'Client INN length must been 10 or 12'];
yield ['name', 1, 1, $fakeClientWithInn(str_repeat('1', 13)), 'Client INN length must been 10 or 12'];
yield ['name', 1, 1, $fakeClientWithInn('1234567890'), 'Client DisplayName cannot be empty'];
}

/**
Expand All @@ -80,8 +84,13 @@ public function validationCreateDataProvider(): iterable
* @throws \Psr\Http\Client\ClientExceptionInterface
* @throws \Shoman4eg\Nalog\Exception\DomainException
*/
public function testCreateValidation(string $name, $amount, $quantity, ?DTO\IncomeClient $client, string $message): void
{
public function testValidationCreate(
string $name,
$amount,
$quantity,
?DTO\IncomeClient $client,
string $message
): void {
$this->expectExceptionMessage($message);
$this->client->income()->create($name, $amount, $quantity, null, $client);
}
Expand Down Expand Up @@ -129,7 +138,11 @@ public function testCancel(string $receiptId, string $comment): void
public function validationCancelDataProvider(): iterable
{
yield ['', CancelCommentType::REFUND, 'ReceiptUuid cannot be empty'];
yield ['ReceiptUuid', 'InvalidCommentType', 'Comment is invalid. Must be one of: "Чек сформирован ошибочно", "Возврат средств"'];
yield [
'ReceiptUuid',
'InvalidCommentType',
'Comment is invalid. Must be one of: "Чек сформирован ошибочно", "Возврат средств"',
];
}

/**
Expand All @@ -139,9 +152,37 @@ public function validationCancelDataProvider(): iterable
* @throws \Psr\Http\Client\ClientExceptionInterface
* @throws \Shoman4eg\Nalog\Exception\DomainException
*/
public function testCancelValidation(string $receiptId, string $comment, string $message): void
public function testValidationCancel(string $receiptId, string $comment, string $message): void
{
$this->expectExceptionMessage($message);
$this->client->income()->cancel($receiptId, $comment);
}

public function calculationItemsDataProvider(): iterable
{
$name = 'randomName';
yield [[[$name, 100, 1], [$name, 200, 2], [$name, 300, 3]], 1400];
yield [[[$name, 30.23, 1], [$name, 12.33, 8], [$name, 32.44, 9]], 420.83];
yield [[[$name, '30.23', 1], [$name, '12.33', 8], [$name, '32.44', 9]], '420.83'];
}

/**
* @dataProvider calculationItemsDataProvider
*
* @param float|int $expected
*
* @throws \JsonException
* @throws \Psr\Http\Client\ClientExceptionInterface
* @throws \Shoman4eg\Nalog\Exception\DomainException
*/
public function testCalculateAmount(array $items, $expected): void
{
$this->appendSuccessJson(['approvedReceiptUuid' => 'randomReceiptId']);

$serviceItems = array_map(fn ($item) => new DTO\IncomeServiceItem(...$item), $items);
$this->client->income()->createMultipleItems($serviceItems);
$request = json_decode($this->mock->getLastRequest()->getBody()->getContents(), true);

self::assertEquals($request['totalAmount'], $expected);
}
}

0 comments on commit a296399

Please sign in to comment.