mirror of
https://github.com/anthonyaxenov/atol-online.git
synced 2024-11-24 18:14:17 +00:00
Поддержка nomenclature_code
у предмета расчёта + мелкофиксы
- теперь `getSum()` проверяет по `Constraints::MAX_COUNT_ITEM_SUM` вместо `MAX_COUNT_ITEM_PRICE` (как и должен был изначально) - подправил `TooLongException` - всякие phpdoc-и
This commit is contained in:
parent
1c0d8ba64d
commit
2a66889e46
@ -105,7 +105,7 @@ final class Constraints
|
|||||||
/**
|
/**
|
||||||
* Минимальная длина кода таможенной декларации (1231)
|
* Минимальная длина кода таможенной декларации (1231)
|
||||||
*
|
*
|
||||||
* @see https://online.atol.ru/possystem/v4/schema/sell Схема receipt.items.declaration_number
|
* @see https://online.atol.ru/possystem/v4/schema/sell Схема "#/receipt/items/declaration_number"
|
||||||
*/
|
*/
|
||||||
const MIN_LENGTH_DECLARATION_NUMBER = 1;
|
const MIN_LENGTH_DECLARATION_NUMBER = 1;
|
||||||
|
|
||||||
@ -135,6 +135,13 @@ final class Constraints
|
|||||||
*/
|
*/
|
||||||
const MAX_LENGTH_CASHIER_NAME = 64;
|
const MAX_LENGTH_CASHIER_NAME = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Максимальная длина кода товара в байтах (1162)
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
||||||
|
*/
|
||||||
|
const MAX_LENGTH_ITEM_CODE = 32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Регулярное выражение для валидации строки ИНН
|
* Регулярное выражение для валидации строки ИНН
|
||||||
*
|
*
|
||||||
@ -145,7 +152,6 @@ final class Constraints
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Регулярное выражение для валидации номера телефона
|
* Регулярное выражение для валидации номера телефона
|
||||||
*
|
|
||||||
* @see https://online.atol.ru/possystem/v4/schema/sell Схема "#/definitions/phone_number"
|
* @see https://online.atol.ru/possystem/v4/schema/sell Схема "#/definitions/phone_number"
|
||||||
*/
|
*/
|
||||||
const PATTERN_PHONE = /* @lang PhpRegExp */
|
const PATTERN_PHONE = /* @lang PhpRegExp */
|
||||||
|
@ -26,6 +26,7 @@ use AtolOnline\{
|
|||||||
Exceptions\TooHighItemQuantityException,
|
Exceptions\TooHighItemQuantityException,
|
||||||
Exceptions\TooHighPriceException,
|
Exceptions\TooHighPriceException,
|
||||||
Exceptions\TooHighSumException,
|
Exceptions\TooHighSumException,
|
||||||
|
Exceptions\TooLongItemCodeException,
|
||||||
Exceptions\TooLongItemNameException,
|
Exceptions\TooLongItemNameException,
|
||||||
Exceptions\TooLongMeasurementUnitException,
|
Exceptions\TooLongMeasurementUnitException,
|
||||||
Exceptions\TooLongUserdataException,
|
Exceptions\TooLongUserdataException,
|
||||||
@ -59,6 +60,16 @@ class Item extends Entity
|
|||||||
*/
|
*/
|
||||||
protected ?string $measurement_unit = null;
|
protected ?string $measurement_unit = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null Код товара (1162)
|
||||||
|
*/
|
||||||
|
protected ?string $code = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null Код товара (1162) в форматированной шестнадцатиричной форме
|
||||||
|
*/
|
||||||
|
protected ?string $code_hex = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null Признак способа расчёта (1214)
|
* @var string|null Признак способа расчёта (1214)
|
||||||
*/
|
*/
|
||||||
@ -229,7 +240,7 @@ class Item extends Entity
|
|||||||
public function getSum(): float
|
public function getSum(): float
|
||||||
{
|
{
|
||||||
$sum = $this->getPrice() * $this->getQuantity() + (float)$this->getExcise();
|
$sum = $this->getPrice() * $this->getQuantity() + (float)$this->getExcise();
|
||||||
if ($sum > Constraints::MAX_COUNT_ITEM_PRICE) {
|
if ($sum > Constraints::MAX_COUNT_ITEM_SUM) {
|
||||||
throw new TooHighSumException($this->getName(), $sum);
|
throw new TooHighSumException($this->getName(), $sum);
|
||||||
}
|
}
|
||||||
return $sum;
|
return $sum;
|
||||||
@ -262,6 +273,49 @@ class Item extends Entity
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленный код товара
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCode(): ?string
|
||||||
|
{
|
||||||
|
return $this->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает шестнадцатиричное представление кода товара
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCodeHex(): ?string
|
||||||
|
{
|
||||||
|
return $this->code_hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает код товара
|
||||||
|
*
|
||||||
|
* @param string|null $code
|
||||||
|
* @return Item
|
||||||
|
* @throws TooLongItemCodeException
|
||||||
|
*/
|
||||||
|
public function setCode(?string $code): self
|
||||||
|
{
|
||||||
|
$hex_string = null;
|
||||||
|
$code = trim((string)$code);
|
||||||
|
if (mb_strlen($code) > Constraints::MAX_LENGTH_ITEM_CODE) {
|
||||||
|
throw new TooLongItemCodeException($this->getName(), $code);
|
||||||
|
}
|
||||||
|
if (!empty($code)) {
|
||||||
|
$hex = bin2hex($code);
|
||||||
|
$hex_string = trim(preg_replace('/([\dA-Fa-f]{2})/', '$1 ', $hex));
|
||||||
|
}
|
||||||
|
$this->code = $code ?: null;
|
||||||
|
$this->code_hex = $hex_string ?: null;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает признак способа оплаты
|
* Возвращает признак способа оплаты
|
||||||
*
|
*
|
||||||
@ -536,6 +590,7 @@ class Item extends Entity
|
|||||||
'sum' => $this->getSum(),
|
'sum' => $this->getSum(),
|
||||||
];
|
];
|
||||||
!is_null($this->getMeasurementUnit()) && $json['measurement_unit'] = $this->getMeasurementUnit();
|
!is_null($this->getMeasurementUnit()) && $json['measurement_unit'] = $this->getMeasurementUnit();
|
||||||
|
!is_null($this->getCodeHex()) && $json['nomenclature_code'] = $this->getCodeHex();
|
||||||
!is_null($this->getPaymentMethod()) && $json['payment_method'] = $this->getPaymentMethod();
|
!is_null($this->getPaymentMethod()) && $json['payment_method'] = $this->getPaymentMethod();
|
||||||
!is_null($this->getPaymentObject()) && $json['payment_object'] = $this->getPaymentObject();
|
!is_null($this->getPaymentObject()) && $json['payment_object'] = $this->getPaymentObject();
|
||||||
!is_null($this->getDeclarationNumber()) && $json['declaration_number'] = $this->getDeclarationNumber();
|
!is_null($this->getDeclarationNumber()) && $json['declaration_number'] = $this->getDeclarationNumber();
|
||||||
@ -545,7 +600,6 @@ class Item extends Entity
|
|||||||
!is_null($this->getUserData()) && $json['user_data'] = $this->getUserData();
|
!is_null($this->getUserData()) && $json['user_data'] = $this->getUserData();
|
||||||
!is_null($this->getExcise()) && $json['excise'] = $this->getExcise();
|
!is_null($this->getExcise()) && $json['excise'] = $this->getExcise();
|
||||||
!is_null($this->getCountryCode()) && $json['country_code'] = $this->getCountryCode();
|
!is_null($this->getCountryCode()) && $json['country_code'] = $this->getCountryCode();
|
||||||
//TODO nomenclature_code
|
|
||||||
return $json;
|
return $json;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,14 +31,13 @@ class TooLongException extends AtolException
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
* @param string $message
|
* @param string $message
|
||||||
* @param int $max
|
* @param float $max
|
||||||
*/
|
*/
|
||||||
public function __construct(string $value, string $message = '', int $max = 0)
|
public function __construct(string $value, string $message = '', float $max = 0)
|
||||||
{
|
{
|
||||||
$message = ($message ?: $this->message) . ': '. $value;
|
parent::__construct(
|
||||||
if ($max > 0 || $this->max > 0) {
|
($message ?: $this->message) . ': ' . $value . (((float)$max > 0 || (float)$this->max > 0) ?
|
||||||
$message .= ' (макс. = ' . ($max ?? $this->max) . ', фактически = ' . mb_strlen($value) . ')';
|
' (макс = ' . ($max ?: $this->max) . ', фактически = ' . mb_strlen($value) . ')' : '')
|
||||||
}
|
);
|
||||||
parent::__construct($message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
src/Exceptions/TooLongItemCodeException.php
Normal file
35
src/Exceptions/TooLongItemCodeException.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
|
||||||
|
*
|
||||||
|
* This code is licensed under MIT.
|
||||||
|
* Этот код распространяется по лицензии MIT.
|
||||||
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
|
use AtolOnline\Constants\Constraints;
|
||||||
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать слишком длинный код товара
|
||||||
|
*/
|
||||||
|
class TooLongItemCodeException extends TooLongException
|
||||||
|
{
|
||||||
|
protected float $max = Constraints::MAX_LENGTH_ITEM_CODE;
|
||||||
|
protected array $ffd_tags = [Ffd105Tags::ITEM_NOMENCLATURE_CODE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string $code
|
||||||
|
*/
|
||||||
|
public function __construct(string $name, string $code)
|
||||||
|
{
|
||||||
|
parent::__construct($code, "Слишком длинный код товара '$name'");
|
||||||
|
}
|
||||||
|
}
|
@ -34,13 +34,15 @@ use AtolOnline\{
|
|||||||
Exceptions\TooHighItemQuantityException,
|
Exceptions\TooHighItemQuantityException,
|
||||||
Exceptions\TooHighPriceException,
|
Exceptions\TooHighPriceException,
|
||||||
Exceptions\TooHighSumException,
|
Exceptions\TooHighSumException,
|
||||||
|
Exceptions\TooLongItemCodeException,
|
||||||
Exceptions\TooLongItemNameException,
|
Exceptions\TooLongItemNameException,
|
||||||
Exceptions\TooLongMeasurementUnitException,
|
Exceptions\TooLongMeasurementUnitException,
|
||||||
Exceptions\TooLongPayingAgentOperationException,
|
Exceptions\TooLongPayingAgentOperationException,
|
||||||
Exceptions\TooLongUserdataException,
|
Exceptions\TooLongUserdataException,
|
||||||
Exceptions\TooManyException,
|
Exceptions\TooManyException,
|
||||||
Helpers,
|
Helpers,
|
||||||
Tests\BasicTestCase};
|
Tests\BasicTestCase
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Набор тестов для проверки работы класс продавца
|
* Набор тестов для проверки работы класс продавца
|
||||||
@ -207,12 +209,12 @@ class ItemTest extends BasicTestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует установку пустой единицы измерения
|
* Тестирует обнуление единицы измерения
|
||||||
*
|
*
|
||||||
* @param mixed $param
|
* @param mixed $param
|
||||||
* @dataProvider providerNullableStrings
|
* @dataProvider providerNullableStrings
|
||||||
* @covers \AtolOnline\Entities\Item::setMeasurementUnit
|
* @covers \AtolOnline\Entities\Item::setMeasurementUnit
|
||||||
* @covers \AtolOnline\Entities\Item::getMeasurementUnit
|
* @covers \AtolOnline\Entities\Item::getMeasurementUnit
|
||||||
* @throws EmptyItemNameException
|
* @throws EmptyItemNameException
|
||||||
* @throws NegativeItemPriceException
|
* @throws NegativeItemPriceException
|
||||||
* @throws TooHighPriceException
|
* @throws TooHighPriceException
|
||||||
@ -504,12 +506,12 @@ class ItemTest extends BasicTestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует установку пустых пользовательских данных
|
* Тестирует обнуление пользовательских данных
|
||||||
*
|
*
|
||||||
* @param mixed $param
|
* @param mixed $param
|
||||||
* @dataProvider providerNullableStrings
|
* @dataProvider providerNullableStrings
|
||||||
* @covers \AtolOnline\Entities\Item::setUserData
|
* @covers \AtolOnline\Entities\Item::setUserData
|
||||||
* @covers \AtolOnline\Entities\Item::getUserData
|
* @covers \AtolOnline\Entities\Item::getUserData
|
||||||
* @throws EmptyItemNameException
|
* @throws EmptyItemNameException
|
||||||
* @throws NegativeItemPriceException
|
* @throws NegativeItemPriceException
|
||||||
* @throws TooHighPriceException
|
* @throws TooHighPriceException
|
||||||
@ -689,7 +691,7 @@ class ItemTest extends BasicTestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует установку акциза и расчёт суммы с его учётом
|
* Тестирует выброс исключения при установке слишком отрицательного акциза
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Entities\Item::setExcise
|
* @covers \AtolOnline\Entities\Item::setExcise
|
||||||
* @covers \AtolOnline\Exceptions\NegativeItemExciseException
|
* @covers \AtolOnline\Exceptions\NegativeItemExciseException
|
||||||
@ -706,4 +708,81 @@ class ItemTest extends BasicTestCase
|
|||||||
$this->expectException(NegativeItemExciseException::class);
|
$this->expectException(NegativeItemExciseException::class);
|
||||||
(new Item('test item', 2, 3))->setExcise(-1);
|
(new Item('test item', 2, 3))->setExcise(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует установку валидного кода товара
|
||||||
|
*
|
||||||
|
* @covers \AtolOnline\Entities\Item::setCode
|
||||||
|
* @covers \AtolOnline\Entities\Item::getCode
|
||||||
|
* @covers \AtolOnline\Entities\Item::getCodeHex
|
||||||
|
* @covers \AtolOnline\Entities\Item::jsonSerialize
|
||||||
|
* @throws EmptyItemNameException
|
||||||
|
* @throws NegativeItemPriceException
|
||||||
|
* @throws NegativeItemQuantityException
|
||||||
|
* @throws TooHighPriceException
|
||||||
|
* @throws TooLongItemNameException
|
||||||
|
* @throws TooManyException
|
||||||
|
* @throws TooLongItemCodeException
|
||||||
|
*/
|
||||||
|
public function testValidNomenclatureCode(): void
|
||||||
|
{
|
||||||
|
$code = Helpers::randomStr(Constraints::MAX_LENGTH_ITEM_CODE);
|
||||||
|
$encoded = trim(preg_replace('/([\dA-Fa-f]{2})/', '$1 ', bin2hex($code)));
|
||||||
|
|
||||||
|
$item = (new Item('test item', 2, 3))->setCode($code);
|
||||||
|
$this->assertEquals($code, $item->getCode());
|
||||||
|
$this->assertEquals($encoded, $item->getCodeHex());
|
||||||
|
|
||||||
|
$decoded = hex2bin(str_replace(' ', '', $item->getCodeHex()));
|
||||||
|
$this->assertEquals($decoded, $item->getCode());
|
||||||
|
|
||||||
|
$this->assertAtolable($item, [
|
||||||
|
'name' => 'test item',
|
||||||
|
'price' => 2,
|
||||||
|
'quantity' => 3,
|
||||||
|
'sum' => 6,
|
||||||
|
'nomenclature_code' => $item->getCodeHex(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует обнуление кода товара
|
||||||
|
*
|
||||||
|
* @param mixed $param
|
||||||
|
* @dataProvider providerNullableStrings
|
||||||
|
* @covers \AtolOnline\Entities\Item::setCode
|
||||||
|
* @covers \AtolOnline\Entities\Item::getCode
|
||||||
|
* @covers \AtolOnline\Entities\Item::getCodeHex
|
||||||
|
* @throws EmptyItemNameException
|
||||||
|
* @throws NegativeItemPriceException
|
||||||
|
* @throws NegativeItemQuantityException
|
||||||
|
* @throws TooHighPriceException
|
||||||
|
* @throws TooLongItemCodeException
|
||||||
|
* @throws TooLongItemNameException
|
||||||
|
* @throws TooManyException
|
||||||
|
*/
|
||||||
|
public function testNullableCode(mixed $param): void
|
||||||
|
{
|
||||||
|
$item = (new Item('test item', 2, 3))->setCode($param);
|
||||||
|
$this->assertNull($item->getCode());
|
||||||
|
$this->assertNull($item->getCodeHex());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует выброс исключения при установке слишком отрицательного акциза
|
||||||
|
*
|
||||||
|
* @covers \AtolOnline\Entities\Item::setCode
|
||||||
|
* @covers \AtolOnline\Exceptions\TooLongItemCodeException
|
||||||
|
* @throws TooLongItemNameException
|
||||||
|
* @throws TooHighPriceException
|
||||||
|
* @throws TooManyException
|
||||||
|
* @throws NegativeItemPriceException
|
||||||
|
* @throws EmptyItemNameException
|
||||||
|
* @throws NegativeItemQuantityException
|
||||||
|
*/
|
||||||
|
public function testTooLongItemCodeException(): void
|
||||||
|
{
|
||||||
|
$this->expectException(TooLongItemCodeException::class);
|
||||||
|
(new Item('test item', 2, 3))->setCode(Helpers::randomStr(Constraints::MAX_LENGTH_ITEM_CODE + 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user