Compare commits
45 Commits
1c0d8ba64d
...
v1.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 4bc92ac0ad | |||
| 9fa55e7c5f | |||
| baf97cad20 | |||
| 2e8099e0a4 | |||
| d7f3c81fac | |||
| e22c1cb091 | |||
| 58bc344a86 | |||
| fdc5ab112a | |||
| 71d1f2900c | |||
| b4cc0fec53 | |||
| 573af15bac | |||
| 19653776c5 | |||
| c7d07a18f1 | |||
| 464a8f0706 | |||
| 294a3ef2f3 | |||
| b4af189292 | |||
| 6787ce3ad7 | |||
| 1d6abfd475 | |||
| 058ce5ed3d | |||
| 16d1146826 | |||
| 703c5178f5 | |||
| fdc64954f9 | |||
| 793549aaac | |||
| b57acf8b05 | |||
| b39e76f312 | |||
| a34a6927d1 | |||
| 1f3d5d2f3d | |||
| 359264db64 | |||
| 557c76fefa | |||
| bf09641c8b | |||
| 6b5a025051 | |||
| 3d3eba5b4e | |||
| a5c88cd7d3 | |||
| b451c7dc68 | |||
| 7d0c526663 | |||
| 65ec639014 | |||
| d533164d1b | |||
| 05fd25e810 | |||
| 3e03fdca61 | |||
| c077f98cf9 | |||
| 2260233e3f | |||
| c30c7d069f | |||
| 8f235d4730 | |||
| 85750cd211 | |||
| 2a66889e46 |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,3 +1,3 @@
|
|||||||
github: anthonyaxenov
|
#github: anthonyaxenov
|
||||||
patreon: anthonyaxenov
|
patreon: anthonyaxenov
|
||||||
custom: [ 'https://yoomoney.ru/to/41001685237530' ]
|
custom: [ 'https://yoomoney.ru/to/41001685237530' ]
|
||||||
|
|||||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -6,7 +6,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [ master, dev ]
|
branches: [ master, dev ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master, dev ]
|
branches: [ dev ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Tests:
|
Tests:
|
||||||
|
|||||||
44
README.md
44
README.md
@@ -2,30 +2,26 @@
|
|||||||
|
|
||||||
[](https://packagist.org/packages/axenov/atol-online)
|
[](https://packagist.org/packages/axenov/atol-online)
|
||||||
[](https://packagist.org/packages/axenov/atol-online)
|
[](https://packagist.org/packages/axenov/atol-online)
|
||||||
[](https://packagist.org/packages/axenov/atol-online)
|
[](https://packagist.org/packages/axenov/atol-online)
|
||||||
[](https://packagist.org/packages/axenov/atol-online)
|
[](https://packagist.org/packages/axenov/atol-online)
|
||||||
|
[](LICENSE)
|
||||||
|
|
||||||
Библиотека для фискализации чеков по 54-ФЗ через [облачную ККТ АТОЛ](https://online.atol.ru/).
|
Библиотека для фискализации чеков по 54-ФЗ через [облачные ККТ АТОЛ](https://online.atol.ru/).
|
||||||
|
|
||||||
**[Документация](/docs/readme.md)**
|
**[Документация](/docs/readme.md)**
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**В ветке `dev` проводится глубокий рефакторинг, стабилизация и активная подготовка к `v1.0.0`.
|
|
||||||
Документация актуализируется постепенно.**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
| master | [](https://github.com/anthonyaxenov/atol-online/actions/workflows/ci.yml) | [](https://codecov.io/gh/anthonyaxenov/atol-online) |
|
|
||||||
|---|---|---|
|
|
||||||
| dev | [](https://github.com/anthonyaxenov/atol-online/actions/workflows/ci.yml) | [](https://codecov.io/gh/anthonyaxenov/atol-online) |
|
|
||||||
|
|
||||||
Текущие поддерживаемые версии АТОЛ Онлайн:
|
Текущие поддерживаемые версии АТОЛ Онлайн:
|
||||||
|
|
||||||
| Протокол | API | ФФД | Статус |
|
| Протокол | API | ФФД | Статус |
|
||||||
|----------|-----|------|-------------|
|
|----------|-----|------|----------------|
|
||||||
| v4 | 5.7 | 1.05 | Рефакторинг |
|
| v4 | 5.8 | 1.05 | Поддерживается |
|
||||||
| v5 | 2.0 | 1.2 | В планах |
|
| v5 | 2.0 | 1.2 | В планах |
|
||||||
|
|
||||||
|
Состояние веток:
|
||||||
|
|
||||||
|
| master | [](https://github.com/anthonyaxenov/atol-online/actions/workflows/ci.yml) | [](https://codecov.io/gh/anthonyaxenov/atol-online) |
|
||||||
|
|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| dev | [](https://github.com/anthonyaxenov/atol-online/actions/workflows/ci.yml) | [](https://codecov.io/gh/anthonyaxenov/atol-online) |
|
||||||
|
|
||||||
## Плюшечки
|
## Плюшечки
|
||||||
|
|
||||||
@@ -33,8 +29,7 @@
|
|||||||
* Фискализация докумнетов на облачной ККТ
|
* Фискализация докумнетов на облачной ККТ
|
||||||
* Валидация данных до отправки документа на ККТ (насколько это возможно, согласно схеме)
|
* Валидация данных до отправки документа на ККТ (насколько это возможно, согласно схеме)
|
||||||
* Расчёты денег в копейках
|
* Расчёты денег в копейках
|
||||||
* PSR-4 автозагрузка
|
* PSR-4 автозагрузка, покрытие настоящими тестами, fluent-setters
|
||||||
<!--* Фактически полное покрытие тестами-->
|
|
||||||
|
|
||||||
## Системные требования
|
## Системные требования
|
||||||
|
|
||||||
@@ -50,7 +45,7 @@
|
|||||||
|
|
||||||
### Подключение библиотеки
|
### Подключение библиотеки
|
||||||
|
|
||||||
1. Установить библиотеку пакет к проекту:
|
1. Подключить пакет к проекту:
|
||||||
```bash
|
```bash
|
||||||
composer require axenov/atol-online
|
composer require axenov/atol-online
|
||||||
```
|
```
|
||||||
@@ -69,10 +64,10 @@
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
composer test # обычное тестирование
|
composer test # обычное тестирование
|
||||||
composer test-cov # тестирование с покрытием
|
composer coverage # тестирование с покрытием
|
||||||
```
|
```
|
||||||
|
|
||||||
После тестирования с покрытием создаётся отчёт в директории `.coverage-report` в корне репозитория.
|
После тестирования с покрытием создаётся отчёт в директории `.coverage` в корне репозитория.
|
||||||
|
|
||||||
## Использование библиотеки
|
## Использование библиотеки
|
||||||
|
|
||||||
@@ -89,10 +84,7 @@ composer test-cov # тестирование с покрытием
|
|||||||
|
|
||||||
## Дополнительные ресурсы
|
## Дополнительные ресурсы
|
||||||
|
|
||||||
* **[Документация к библиотеке](/docs/readme.md)**
|
|
||||||
* Telegram-канал: [@atolonline_php](https://t.me/atolonline_php)
|
|
||||||
* [Документация АТОЛ Онлайн](https://online.atol.ru/lib/)
|
* [Документация АТОЛ Онлайн](https://online.atol.ru/lib/)
|
||||||
* Функционал, находящийся в разработке: [ROADMAP.md](ROADMAP.md)
|
|
||||||
|
|
||||||
## Лицензия
|
## Лицензия
|
||||||
|
|
||||||
|
|||||||
66
ROADMAP.md
66
ROADMAP.md
@@ -1,66 +0,0 @@
|
|||||||
# Roadmap
|
|
||||||
|
|
||||||
Здесь перечислены реализованные функции и находящиеся в разработке.
|
|
||||||
|
|
||||||
Порядок их упоминания здесь может не совпадать с порядком реализации.
|
|
||||||
|
|
||||||
Эталонная реализация подразумевает полную поддержку всех методов API и обеих схем документов:
|
|
||||||
* [Документы прихода, возврата прихода, расхода, возврата расхода](https://online.atol.ru/possystem/v4/schema/sell)
|
|
||||||
* [Документы коррекции прихода, коррекции расхода](https://online.atol.ru/possystem/v4/schema/correction)
|
|
||||||
|
|
||||||
## Общий функционал библиотеки
|
|
||||||
|
|
||||||
- [x] Переключение настроек доступа к ККТ при переключении тестового режима
|
|
||||||
- [x] Тесты для класса налоговой ставки (+ массив)
|
|
||||||
- [ ] Тесты для класса оплаты (+ массив)
|
|
||||||
- [x] Тесты для класса предмета расчёта (+ массив)
|
|
||||||
- [x] Тесты для класса клиента
|
|
||||||
- [x] Тесты для класса компании
|
|
||||||
- [ ] Тесты для класса данных коррекций
|
|
||||||
- [ ] Тесты для класса документа
|
|
||||||
- [ ] Тесты для класса ответа ККТ
|
|
||||||
- [ ] Тесты для регистрации документа прихода
|
|
||||||
- [ ] Тесты для регистрации документа возврата прихода
|
|
||||||
- [ ] Тесты для регистрации документа коррекции прихода
|
|
||||||
- [ ] Тесты для регистрации документа расхода
|
|
||||||
- [ ] Тесты для регистрации документа возврата расхода
|
|
||||||
- [ ] Тесты для регистрации документа коррекции расхода
|
|
||||||
- [ ] Вообще все расчёты вообще везде должны быть строго в копейках.
|
|
||||||
Рубли (дроби) должны быть только в JSON-представлениях
|
|
||||||
|
|
||||||
## Поддержка методов API (регистрация документов)
|
|
||||||
|
|
||||||
- [x] приход
|
|
||||||
- [x] расход
|
|
||||||
- [x] возврат прихода
|
|
||||||
- [x] возврат расхода
|
|
||||||
- [x] коррекция прихода
|
|
||||||
- [x] коррекция расхода
|
|
||||||
- [x] проверка статуса документа
|
|
||||||
|
|
||||||
## Документы прихода, возврата прихода, расхода, возврата расхода
|
|
||||||
|
|
||||||
- [x] Пoддержка `receipt.client` (обязательный)
|
|
||||||
- [x] Пoддержка `receipt.company` (обязательный)
|
|
||||||
- [x] Пoддержка `receipt.items` (обязательный)
|
|
||||||
- [x] Пoддержка `receipt.total` (обязательный)
|
|
||||||
- [x] Пoддержка `receipt.payments` (обязательный)
|
|
||||||
- [x] Пoддержка `receipt.vats`
|
|
||||||
- [ ] Пoддержка `receipt.additional_check_props`
|
|
||||||
- [x] Пoддержка `receipt.cashier`
|
|
||||||
- [ ] Пoддержка `receipt.additional_user_props`
|
|
||||||
- [ ] Пoддержка `receipt.agent_info`
|
|
||||||
- [ ] Пoддержка `receipt.supplier_info`
|
|
||||||
- [ ] Пoддержка `receipt.items.agent_info`
|
|
||||||
- [ ] Пoддержка `receipt.items.supplier_info`
|
|
||||||
- [ ] Пoддержка `receipt.items.nomenclature_code`
|
|
||||||
- [ ] Пoддержка `receipt.items.excise`
|
|
||||||
- [ ] Пoддержка `receipt.items.country_code`
|
|
||||||
- [ ] Пoддержка `receipt.items.declaration_number`
|
|
||||||
|
|
||||||
## Документы коррекции прихода, коррекции расхода
|
|
||||||
|
|
||||||
- [x] Пoддержка `correction.company` (обязательный)
|
|
||||||
- [x] Пoддержка `correction.vats` (обязательный)
|
|
||||||
- [x] Пoддержка `correction.correction_info` (обязательный)
|
|
||||||
- [x] Пoддержка `correction.cashier`
|
|
||||||
@@ -32,8 +32,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"rss": "https://t.me/atolonline_php",
|
"rss": "https://github.com/anthonyaxenov/atol-online/discussions/categories/announcements",
|
||||||
"chat": "https://t.me/+Rky7ia68fctjZmUy",
|
"chat": "https://github.com/anthonyaxenov/atol-online/discussions",
|
||||||
"source": "https://github.com/anthonyaxenov/atol-online",
|
"source": "https://github.com/anthonyaxenov/atol-online",
|
||||||
"issues": "https://github.com/anthonyaxenov/atol-online/issues",
|
"issues": "https://github.com/anthonyaxenov/atol-online/issues",
|
||||||
"docs": "https://github.com/anthonyaxenov/atol-online/blob/master/docs/readme.md"
|
"docs": "https://github.com/anthonyaxenov/atol-online/blob/master/docs/readme.md"
|
||||||
@@ -56,7 +56,8 @@
|
|||||||
"psr/log": "^3",
|
"psr/log": "^3",
|
||||||
"ramsey/uuid": "^4.2",
|
"ramsey/uuid": "^4.2",
|
||||||
"myclabs/php-enum": "^1.8",
|
"myclabs/php-enum": "^1.8",
|
||||||
"illuminate/collections": "^8.70"
|
"illuminate/collections": "^8.70",
|
||||||
|
"jetbrains/phpstorm-attributes": "^1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9.5"
|
"phpunit/phpunit": "^9.5"
|
||||||
@@ -73,6 +74,10 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vendor/bin/phpunit --colors=always",
|
"test": "vendor/bin/phpunit --colors=always",
|
||||||
"test-cov": "php -dxdebug.mode=coverage vendor/bin/phpunit --coverage-html .coverage-report"
|
"coverage": "php -dxdebug.mode=coverage vendor/bin/phpunit --coverage-html .coverage"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"optimize-autoloader": true,
|
||||||
|
"sort-packages": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
324
composer.lock
generated
324
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "b03e06fba2a861f7ce366484ec6421c3",
|
"content-hash": "4877f27cd59b6558eea01644e2d520ef",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
@@ -50,6 +50,10 @@
|
|||||||
"brick",
|
"brick",
|
||||||
"math"
|
"math"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/brick/math/issues",
|
||||||
|
"source": "https://github.com/brick/math/tree/0.9.3"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/BenMorel",
|
"url": "https://github.com/BenMorel",
|
||||||
@@ -64,16 +68,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/guzzle",
|
"name": "guzzlehttp/guzzle",
|
||||||
"version": "7.4.0",
|
"version": "7.4.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/guzzle.git",
|
"url": "https://github.com/guzzle/guzzle.git",
|
||||||
"reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94"
|
"reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/868b3571a039f0ebc11ac8f344f4080babe2cb94",
|
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/ee0a041b1760e6a53d2a39c8c34115adc2af2c79",
|
||||||
"reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94",
|
"reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -82,7 +86,7 @@
|
|||||||
"guzzlehttp/psr7": "^1.8.3 || ^2.1",
|
"guzzlehttp/psr7": "^1.8.3 || ^2.1",
|
||||||
"php": "^7.2.5 || ^8.0",
|
"php": "^7.2.5 || ^8.0",
|
||||||
"psr/http-client": "^1.0",
|
"psr/http-client": "^1.0",
|
||||||
"symfony/deprecation-contracts": "^2.2"
|
"symfony/deprecation-contracts": "^2.2 || ^3.0"
|
||||||
},
|
},
|
||||||
"provide": {
|
"provide": {
|
||||||
"psr/http-client-implementation": "1.0"
|
"psr/http-client-implementation": "1.0"
|
||||||
@@ -166,6 +170,10 @@
|
|||||||
"rest",
|
"rest",
|
||||||
"web service"
|
"web service"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||||
|
"source": "https://github.com/guzzle/guzzle/tree/7.4.1"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/GrahamCampbell",
|
"url": "https://github.com/GrahamCampbell",
|
||||||
@@ -180,7 +188,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-10-18T09:52:00+00:00"
|
"time": "2021-12-06T18:43:05+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/promises",
|
"name": "guzzlehttp/promises",
|
||||||
@@ -246,6 +254,10 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"promise"
|
"promise"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/guzzle/promises/issues",
|
||||||
|
"source": "https://github.com/guzzle/promises/tree/1.5.1"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/GrahamCampbell",
|
"url": "https://github.com/GrahamCampbell",
|
||||||
@@ -357,6 +369,10 @@
|
|||||||
"uri",
|
"uri",
|
||||||
"url"
|
"url"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/guzzle/psr7/issues",
|
||||||
|
"source": "https://github.com/guzzle/psr7/tree/2.1.0"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/GrahamCampbell",
|
"url": "https://github.com/GrahamCampbell",
|
||||||
@@ -375,16 +391,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "illuminate/collections",
|
"name": "illuminate/collections",
|
||||||
"version": "v8.70.2",
|
"version": "v8.75.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/illuminate/collections.git",
|
"url": "https://github.com/illuminate/collections.git",
|
||||||
"reference": "05f286ec5fd2dd286e8384577047efc375c8954c"
|
"reference": "5a018387352afa2af30fd2be0a78c31e93295720"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/illuminate/collections/zipball/05f286ec5fd2dd286e8384577047efc375c8954c",
|
"url": "https://api.github.com/repos/illuminate/collections/zipball/5a018387352afa2af30fd2be0a78c31e93295720",
|
||||||
"reference": "05f286ec5fd2dd286e8384577047efc375c8954c",
|
"reference": "5a018387352afa2af30fd2be0a78c31e93295720",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -393,7 +409,7 @@
|
|||||||
"php": "^7.3|^8.0"
|
"php": "^7.3|^8.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"symfony/var-dumper": "Required to use the dump method (^5.1.4)."
|
"symfony/var-dumper": "Required to use the dump method (^5.4)."
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
@@ -421,20 +437,24 @@
|
|||||||
],
|
],
|
||||||
"description": "The Illuminate Collections package.",
|
"description": "The Illuminate Collections package.",
|
||||||
"homepage": "https://laravel.com",
|
"homepage": "https://laravel.com",
|
||||||
"time": "2021-10-22T18:01:46+00:00"
|
"support": {
|
||||||
|
"issues": "https://github.com/laravel/framework/issues",
|
||||||
|
"source": "https://github.com/laravel/framework"
|
||||||
|
},
|
||||||
|
"time": "2021-12-07T14:48:29+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "illuminate/contracts",
|
"name": "illuminate/contracts",
|
||||||
"version": "v8.70.2",
|
"version": "v8.75.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/illuminate/contracts.git",
|
"url": "https://github.com/illuminate/contracts.git",
|
||||||
"reference": "e76f4bce73a2a1656add24bd5210ebc4b8af49c0"
|
"reference": "b07755f7c456cf587dfbfd6f0854f9f7c1a34b2f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/illuminate/contracts/zipball/e76f4bce73a2a1656add24bd5210ebc4b8af49c0",
|
"url": "https://api.github.com/repos/illuminate/contracts/zipball/b07755f7c456cf587dfbfd6f0854f9f7c1a34b2f",
|
||||||
"reference": "e76f4bce73a2a1656add24bd5210ebc4b8af49c0",
|
"reference": "b07755f7c456cf587dfbfd6f0854f9f7c1a34b2f",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -465,20 +485,24 @@
|
|||||||
],
|
],
|
||||||
"description": "The Illuminate Contracts package.",
|
"description": "The Illuminate Contracts package.",
|
||||||
"homepage": "https://laravel.com",
|
"homepage": "https://laravel.com",
|
||||||
"time": "2021-10-22T18:01:46+00:00"
|
"support": {
|
||||||
|
"issues": "https://github.com/laravel/framework/issues",
|
||||||
|
"source": "https://github.com/laravel/framework"
|
||||||
|
},
|
||||||
|
"time": "2021-12-07T08:18:44+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "illuminate/macroable",
|
"name": "illuminate/macroable",
|
||||||
"version": "v8.70.2",
|
"version": "v8.75.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/illuminate/macroable.git",
|
"url": "https://github.com/illuminate/macroable.git",
|
||||||
"reference": "300aa13c086f25116b5f3cde3ca54ff5c822fb05"
|
"reference": "aed81891a6e046fdee72edd497f822190f61c162"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/illuminate/macroable/zipball/300aa13c086f25116b5f3cde3ca54ff5c822fb05",
|
"url": "https://api.github.com/repos/illuminate/macroable/zipball/aed81891a6e046fdee72edd497f822190f61c162",
|
||||||
"reference": "300aa13c086f25116b5f3cde3ca54ff5c822fb05",
|
"reference": "aed81891a6e046fdee72edd497f822190f61c162",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -507,7 +531,53 @@
|
|||||||
],
|
],
|
||||||
"description": "The Illuminate Macroable package.",
|
"description": "The Illuminate Macroable package.",
|
||||||
"homepage": "https://laravel.com",
|
"homepage": "https://laravel.com",
|
||||||
"time": "2020-10-27T15:20:30+00:00"
|
"support": {
|
||||||
|
"issues": "https://github.com/laravel/framework/issues",
|
||||||
|
"source": "https://github.com/laravel/framework"
|
||||||
|
},
|
||||||
|
"time": "2021-11-16T13:57:03+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jetbrains/phpstorm-attributes",
|
||||||
|
"version": "1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/JetBrains/phpstorm-attributes.git",
|
||||||
|
"reference": "a7a83ae5df4dd3c0875484483de19de8edf60a9f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/JetBrains/phpstorm-attributes/zipball/a7a83ae5df4dd3c0875484483de19de8edf60a9f",
|
||||||
|
"reference": "a7a83ae5df4dd3c0875484483de19de8edf60a9f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"JetBrains\\PhpStorm\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "JetBrains",
|
||||||
|
"homepage": "https://www.jetbrains.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PhpStorm specific attributes",
|
||||||
|
"keywords": [
|
||||||
|
"attributes",
|
||||||
|
"jetbrains",
|
||||||
|
"phpstorm"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://youtrack.jetbrains.com/newIssue?project=WI",
|
||||||
|
"source": "https://github.com/JetBrains/phpstorm-attributes/tree/1.0"
|
||||||
|
},
|
||||||
|
"time": "2020-11-17T11:09:47+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "myclabs/php-enum",
|
"name": "myclabs/php-enum",
|
||||||
@@ -553,6 +623,10 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"enum"
|
"enum"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/myclabs/php-enum/issues",
|
||||||
|
"source": "https://github.com/myclabs/php-enum/tree/1.8.3"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/mnapoli",
|
"url": "https://github.com/mnapoli",
|
||||||
@@ -607,6 +681,10 @@
|
|||||||
"container-interop",
|
"container-interop",
|
||||||
"psr"
|
"psr"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/php-fig/container/issues",
|
||||||
|
"source": "https://github.com/php-fig/container/tree/1.1.2"
|
||||||
|
},
|
||||||
"time": "2021-11-05T16:50:12+00:00"
|
"time": "2021-11-05T16:50:12+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -656,6 +734,9 @@
|
|||||||
"psr",
|
"psr",
|
||||||
"psr-18"
|
"psr-18"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/http-client/tree/master"
|
||||||
|
},
|
||||||
"time": "2020-06-29T06:28:15+00:00"
|
"time": "2020-06-29T06:28:15+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -708,6 +789,9 @@
|
|||||||
"request",
|
"request",
|
||||||
"response"
|
"response"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/http-factory/tree/master"
|
||||||
|
},
|
||||||
"time": "2019-04-30T12:38:16+00:00"
|
"time": "2019-04-30T12:38:16+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -808,6 +892,9 @@
|
|||||||
"psr",
|
"psr",
|
||||||
"psr-3"
|
"psr-3"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/log/tree/3.0.0"
|
||||||
|
},
|
||||||
"time": "2021-07-14T16:46:02+00:00"
|
"time": "2021-07-14T16:46:02+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -856,6 +943,9 @@
|
|||||||
"psr-16",
|
"psr-16",
|
||||||
"simple-cache"
|
"simple-cache"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/simple-cache/tree/master"
|
||||||
|
},
|
||||||
"time": "2017-10-23T01:57:42+00:00"
|
"time": "2017-10-23T01:57:42+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -965,6 +1055,10 @@
|
|||||||
"queue",
|
"queue",
|
||||||
"set"
|
"set"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/ramsey/collection/issues",
|
||||||
|
"source": "https://github.com/ramsey/collection/tree/1.2.2"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/ramsey",
|
"url": "https://github.com/ramsey",
|
||||||
@@ -1059,6 +1153,10 @@
|
|||||||
"identifier",
|
"identifier",
|
||||||
"uuid"
|
"uuid"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/ramsey/uuid/issues",
|
||||||
|
"source": "https://github.com/ramsey/uuid/tree/4.2.3"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/ramsey",
|
"url": "https://github.com/ramsey",
|
||||||
@@ -1073,25 +1171,25 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/deprecation-contracts",
|
"name": "symfony/deprecation-contracts",
|
||||||
"version": "v2.4.0",
|
"version": "v3.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||||
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627"
|
"reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627",
|
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/c726b64c1ccfe2896cb7df2e1331c357ad1c8ced",
|
||||||
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627",
|
"reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1"
|
"php": ">=8.0.2"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-main": "2.4-dev"
|
"dev-main": "3.0-dev"
|
||||||
},
|
},
|
||||||
"thanks": {
|
"thanks": {
|
||||||
"name": "symfony/contracts",
|
"name": "symfony/contracts",
|
||||||
@@ -1119,6 +1217,9 @@
|
|||||||
],
|
],
|
||||||
"description": "A generic function and convention to trigger deprecation notices",
|
"description": "A generic function and convention to trigger deprecation notices",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.0"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://symfony.com/sponsor",
|
"url": "https://symfony.com/sponsor",
|
||||||
@@ -1133,7 +1234,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-03-23T23:28:01+00:00"
|
"time": "2021-11-01T23:48:49+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-ctype",
|
"name": "symfony/polyfill-ctype",
|
||||||
@@ -1195,6 +1296,9 @@
|
|||||||
"polyfill",
|
"polyfill",
|
||||||
"portable"
|
"portable"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://symfony.com/sponsor",
|
"url": "https://symfony.com/sponsor",
|
||||||
@@ -1275,6 +1379,9 @@
|
|||||||
"portable",
|
"portable",
|
||||||
"shim"
|
"shim"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://symfony.com/sponsor",
|
"url": "https://symfony.com/sponsor",
|
||||||
@@ -1351,6 +1458,9 @@
|
|||||||
"portable",
|
"portable",
|
||||||
"shim"
|
"shim"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://symfony.com/sponsor",
|
"url": "https://symfony.com/sponsor",
|
||||||
@@ -1498,16 +1608,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/php-parser",
|
"name": "nikic/php-parser",
|
||||||
"version": "v4.13.1",
|
"version": "v4.13.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||||
"reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd"
|
"reference": "210577fe3cf7badcc5814d99455df46564f3c077"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd",
|
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077",
|
||||||
"reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd",
|
"reference": "210577fe3cf7badcc5814d99455df46564f3c077",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1546,7 +1656,11 @@
|
|||||||
"parser",
|
"parser",
|
||||||
"php"
|
"php"
|
||||||
],
|
],
|
||||||
"time": "2021-11-03T20:52:16+00:00"
|
"support": {
|
||||||
|
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||||
|
"source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2"
|
||||||
|
},
|
||||||
|
"time": "2021-11-30T19:35:32+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/manifest",
|
"name": "phar-io/manifest",
|
||||||
@@ -1602,6 +1716,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
|
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/phar-io/manifest/issues",
|
||||||
|
"source": "https://github.com/phar-io/manifest/tree/2.0.3"
|
||||||
|
},
|
||||||
"time": "2021-07-20T11:28:43+00:00"
|
"time": "2021-07-20T11:28:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1759,6 +1877,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
|
||||||
|
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0"
|
||||||
|
},
|
||||||
"time": "2021-10-19T17:43:47+00:00"
|
"time": "2021-10-19T17:43:47+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1805,20 +1927,24 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
|
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
|
||||||
|
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1"
|
||||||
|
},
|
||||||
"time": "2021-10-02T14:08:47+00:00"
|
"time": "2021-10-02T14:08:47+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpspec/prophecy",
|
"name": "phpspec/prophecy",
|
||||||
"version": "1.14.0",
|
"version": "v1.15.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpspec/prophecy.git",
|
"url": "https://github.com/phpspec/prophecy.git",
|
||||||
"reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e"
|
"reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
|
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
|
||||||
"reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
|
"reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1868,20 +1994,24 @@
|
|||||||
"spy",
|
"spy",
|
||||||
"stub"
|
"stub"
|
||||||
],
|
],
|
||||||
"time": "2021-09-10T09:02:12+00:00"
|
"support": {
|
||||||
|
"issues": "https://github.com/phpspec/prophecy/issues",
|
||||||
|
"source": "https://github.com/phpspec/prophecy/tree/v1.15.0"
|
||||||
|
},
|
||||||
|
"time": "2021-12-08T12:19:24+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "9.2.8",
|
"version": "9.2.10",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||||
"reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e"
|
"reference": "d5850aaf931743067f4bfc1ae4cbd06468400687"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cf04e88a2e3c56fc1a65488afd493325b4c1bc3e",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d5850aaf931743067f4bfc1ae4cbd06468400687",
|
||||||
"reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e",
|
"reference": "d5850aaf931743067f4bfc1ae4cbd06468400687",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1935,26 +2065,30 @@
|
|||||||
"testing",
|
"testing",
|
||||||
"xunit"
|
"xunit"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.10"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-10-30T08:01:38+00:00"
|
"time": "2021-12-05T09:12:13+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-file-iterator",
|
"name": "phpunit/php-file-iterator",
|
||||||
"version": "3.0.5",
|
"version": "3.0.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||||
"reference": "aa4be8575f26070b100fccb67faabb28f21f66f8"
|
"reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
|
||||||
"reference": "aa4be8575f26070b100fccb67faabb28f21f66f8",
|
"reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1991,13 +2125,17 @@
|
|||||||
"filesystem",
|
"filesystem",
|
||||||
"iterator"
|
"iterator"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-09-28T05:57:25+00:00"
|
"time": "2021-12-02T12:48:52+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-invoker",
|
"name": "phpunit/php-invoker",
|
||||||
@@ -2050,6 +2188,10 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"process"
|
"process"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/php-invoker/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2105,6 +2247,10 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"template"
|
"template"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2160,6 +2306,10 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"timer"
|
"timer"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2255,6 +2405,10 @@
|
|||||||
"testing",
|
"testing",
|
||||||
"xunit"
|
"xunit"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://phpunit.de/donate.html",
|
"url": "https://phpunit.de/donate.html",
|
||||||
@@ -2311,6 +2465,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Library for parsing CLI options",
|
"description": "Library for parsing CLI options",
|
||||||
"homepage": "https://github.com/sebastianbergmann/cli-parser",
|
"homepage": "https://github.com/sebastianbergmann/cli-parser",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2363,6 +2521,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Collection of value objects that represent the PHP code units",
|
"description": "Collection of value objects that represent the PHP code units",
|
||||||
"homepage": "https://github.com/sebastianbergmann/code-unit",
|
"homepage": "https://github.com/sebastianbergmann/code-unit",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/code-unit/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2414,6 +2576,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Looks up which function or method a line of code belongs to",
|
"description": "Looks up which function or method a line of code belongs to",
|
||||||
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
|
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2484,6 +2650,10 @@
|
|||||||
"compare",
|
"compare",
|
||||||
"equality"
|
"equality"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/comparator/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2537,6 +2707,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Library for calculating the complexity of PHP code units",
|
"description": "Library for calculating the complexity of PHP code units",
|
||||||
"homepage": "https://github.com/sebastianbergmann/complexity",
|
"homepage": "https://github.com/sebastianbergmann/complexity",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2599,6 +2773,10 @@
|
|||||||
"unidiff",
|
"unidiff",
|
||||||
"unified diff"
|
"unified diff"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2658,6 +2836,10 @@
|
|||||||
"environment",
|
"environment",
|
||||||
"hhvm"
|
"hhvm"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/environment/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.3"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2731,6 +2913,10 @@
|
|||||||
"export",
|
"export",
|
||||||
"exporter"
|
"exporter"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2791,6 +2977,10 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"global state"
|
"global state"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2844,6 +3034,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Library for counting the lines of code in PHP source code",
|
"description": "Library for counting the lines of code in PHP source code",
|
||||||
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
|
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2897,6 +3091,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
|
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
|
||||||
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
|
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -2948,6 +3146,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Allows reflection of object attributes, including inherited and non-public ones",
|
"description": "Allows reflection of object attributes, including inherited and non-public ones",
|
||||||
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
|
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/object-reflector/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -3007,6 +3209,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Provides functionality to recursively process PHP variables",
|
"description": "Provides functionality to recursively process PHP variables",
|
||||||
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
|
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -3058,6 +3264,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Provides a list of PHP built-in functions that operate on resources",
|
"description": "Provides a list of PHP built-in functions that operate on resources",
|
||||||
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
|
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -3110,6 +3320,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Collection of value objects that represent the types of the PHP type system",
|
"description": "Collection of value objects that represent the types of the PHP type system",
|
||||||
"homepage": "https://github.com/sebastianbergmann/type",
|
"homepage": "https://github.com/sebastianbergmann/type",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/type/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/type/tree/2.3.4"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -3159,6 +3373,10 @@
|
|||||||
],
|
],
|
||||||
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
|
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
|
||||||
"homepage": "https://github.com/sebastianbergmann/version",
|
"homepage": "https://github.com/sebastianbergmann/version",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/sebastianbergmann/version/issues",
|
||||||
|
"source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/sebastianbergmann",
|
"url": "https://github.com/sebastianbergmann",
|
||||||
@@ -3205,6 +3423,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||||
|
"source": "https://github.com/theseer/tokenizer/tree/1.2.1"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/theseer",
|
"url": "https://github.com/theseer",
|
||||||
@@ -3283,5 +3505,5 @@
|
|||||||
"ext-mbstring": "*"
|
"ext-mbstring": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": [],
|
||||||
"plugin-api-version": "1.1.0"
|
"plugin-api-version": "2.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
# Работа с клиентами (покупателями)
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Объект покупателя инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$customer = new AtolOnline\Entities\Client();
|
|
||||||
```
|
|
||||||
|
|
||||||
У объекта покупателя могут быть указаны любые из следующих атрибутов:
|
|
||||||
* email (тег ФФД 1008);
|
|
||||||
* ИНН (тег ФФД 1128);
|
|
||||||
* наименование (тег ФФД 1127);
|
|
||||||
* номер телефона (тег ФФД 1008).
|
|
||||||
|
|
||||||
> Все эти атрибуты являются **необязательными**.
|
|
||||||
> Если указаны одновременно и email, и номер телефона, то ОФД отправит чек только на email.
|
|
||||||
|
|
||||||
Указать эти атрибуты можно двумя способами:
|
|
||||||
|
|
||||||
```php
|
|
||||||
// 1 способ - через конструктор
|
|
||||||
$customer = new AtolOnline\Entities\Client(
|
|
||||||
'John Doe', // наименование
|
|
||||||
'john@example.com', // email
|
|
||||||
'+1/22/99*73s dsdas654 5s6', // номер телефона +122997365456
|
|
||||||
'+fasd3\qe3fs_=nac990139928czc' // номер ИНН 3399013928
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2 способ - через сеттеры
|
|
||||||
$customer = (new AtolOnline\Entities\Client())
|
|
||||||
->setEmail('john@example.com')
|
|
||||||
->setInn('+fasd3\q3fs_=nac9901 3928c-c')
|
|
||||||
->setName('John Doe')
|
|
||||||
->setPhone('+1/22/99*73s dsdas654 5s6');
|
|
||||||
|
|
||||||
// либо комбинация этих способов
|
|
||||||
```
|
|
||||||
|
|
||||||
Получить установленные значения атрибутов можно через геттеры:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$customer->getInn();
|
|
||||||
$customer->getEmail();
|
|
||||||
$customer->getName();
|
|
||||||
$customer->getPhone();
|
|
||||||
```
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительно:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $customer;
|
|
||||||
$json_string = (string)$customer;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $customer->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
19
docs/collection.md
Normal file
19
docs/collection.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Коллекция сущностей
|
||||||
|
|
||||||
|
[Вернуться к содержанию](readme.md#toc)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Коллекциями являются объекты, способные хранить в себе [сущности](entity.md). Они унаследованы
|
||||||
|
от `Illuminate/Support/Collection` и полностью поддерживают все
|
||||||
|
[стандартные методы коллекций Laravel](https://laravel.com/docs/master/collections).
|
||||||
|
|
||||||
|
Помимо этого, они валидируют количество и вид сущностей, которые могут хранить в себе, согласно схеме АТОЛ Онлайн API.
|
||||||
|
|
||||||
|
Коллекции ведут себя аналогично самим сущностям в части приведения к массивам и json-ификации.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Читай также: [Сущность](entity.md)
|
||||||
|
|
||||||
|
[Вернуться к содержанию](readme.md#toc)
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
# Работа с компанией (продавцом)
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Объект компании инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$customer = new AtolOnline\Entities\Company();
|
|
||||||
```
|
|
||||||
|
|
||||||
У объекта компании должны быть указаны все следующие атрибуты:
|
|
||||||
* email (тег ФФД 1117);
|
|
||||||
* ИНН (тег ФФД 1018);
|
|
||||||
* тип системы налогообложения (тег ФФД 1055) - все типы перечислены в классе `AtolOnline\Constants\SnoTypes`;
|
|
||||||
* адрес места расчётов (тег ФФД 1187) - для интернет-сервисов указывается URL с протоколом.
|
|
||||||
|
|
||||||
> Все эти атрибуты являются **обязательными**.
|
|
||||||
> Для тестового режима используйте значения ИНН и адреса места расчётов, [указанные здесь](https://online.atol.ru/files/ffd/test_sreda.txt).
|
|
||||||
|
|
||||||
Указать эти атрибуты можно двумя способами:
|
|
||||||
|
|
||||||
```php
|
|
||||||
// 1 способ - через конструктор (все аргументы обязательны)
|
|
||||||
$company = new AtolOnline\Entities\Company(
|
|
||||||
'company@example.com' // email
|
|
||||||
AtolOnline\Constants\SnoTypes::OSN, // тип СНО
|
|
||||||
'5544332219', // номер ИНН
|
|
||||||
'https://v4.online.atol.ru', // адрес места расчётов
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2 способ - через сеттеры
|
|
||||||
$company
|
|
||||||
->setEmail('company@example.com')
|
|
||||||
->setInn('5544332219')
|
|
||||||
->setSno(AtolOnline\Constants\SnoTypes::USN_INCOME)
|
|
||||||
->setPaymentAddress('https://v4.online.atol.ru');
|
|
||||||
|
|
||||||
// либо комбинация этих способов
|
|
||||||
```
|
|
||||||
|
|
||||||
Получить установленные значения параметров можно через геттеры:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$company->getInn();
|
|
||||||
$company->getEmail();
|
|
||||||
$company->getPaymentAddress();
|
|
||||||
$company->getSno();
|
|
||||||
```
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительно:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $company;
|
|
||||||
$json_string = (string)$company;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $company->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
# Работа с данными коррекции
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Объект для данных коррекции инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$info = new AtolOnline\Entities\CorrectionInfo();
|
|
||||||
```
|
|
||||||
|
|
||||||
У объекта должны быть указаны все следующие обязательные атрибуты:
|
|
||||||
* тип коррекции (тег ФФД 1173) - все типы перечислены в классе `AtolOnline\Constants\CorrectionTypes`;
|
|
||||||
* дата документа основания для коррекции в формате `d.m.Y` (тег ФФД 1178);
|
|
||||||
* номер документа основания для коррекции (тег ФФД 1179).
|
|
||||||
|
|
||||||
Указать эти атрибуты можно двумя способами:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use AtolOnline\{Entities\CorrectionInfo, Constants\CorrectionTypes};
|
|
||||||
|
|
||||||
// 1 способ - через конструктор
|
|
||||||
$info = new CorrectionInfo(
|
|
||||||
CorrectionTypes::SELF, // тип коррекции
|
|
||||||
'01.01.2019', // дата документа коррекции
|
|
||||||
'12345', // номер документа коррекции
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2 способ - через сеттеры
|
|
||||||
$info = (new CorrectionInfo())
|
|
||||||
->setType(CorrectionTypes::INSTRUCTION)
|
|
||||||
->setDate('01.01.2019')
|
|
||||||
->setNumber('9999');
|
|
||||||
|
|
||||||
// либо комбинация этих способов
|
|
||||||
```
|
|
||||||
|
|
||||||
Получить установленные значения атрибутов можно через геттеры:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$info->getType();
|
|
||||||
$info->getDate();
|
|
||||||
$info->getNumber();
|
|
||||||
```
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительным приведением к `string`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $customer;
|
|
||||||
$json_string = (string)$customer;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $customer->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
# Работа с документами
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Объект документа инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$doc = new AtolOnline\Entities\Document();
|
|
||||||
```
|
|
||||||
|
|
||||||
Для документов **прихода, возврата прихода, расхода и возврата расхода** должны быть указаны все следующие обязательные атрибуты:
|
|
||||||
* [клиент](/docs/client.md);
|
|
||||||
* [компания](/docs/company.md);
|
|
||||||
* [предметы расчёта](/docs/items.md);
|
|
||||||
* [оплаты](/docs/payments.md).
|
|
||||||
|
|
||||||
Для документов **коррекции прихода и коррекции расхода** должны быть указаны все следующие обязательные атрибуты:
|
|
||||||
* [компания](/docs/company.md);
|
|
||||||
* [оплаты](/docs/payments.md);
|
|
||||||
* [ставки НДС](/docs/vats.md);
|
|
||||||
* [данные коррекции](/docs/correction_info.md).
|
|
||||||
|
|
||||||
Для любых документов также могут быть указаны следующие необязательные атрибуты:
|
|
||||||
* ФИО кассира (тег ФФД - 1021).
|
|
||||||
|
|
||||||
Установка атрибутов документа происходит через сеттеры.
|
|
||||||
|
|
||||||
## Работа с клиентом
|
|
||||||
|
|
||||||
Для этого существуют следующие методы:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$doc->setClient($client);
|
|
||||||
$doc->getClient();
|
|
||||||
```
|
|
||||||
|
|
||||||
> О работе с клиентами более подробно читайте [здесь](/docs/client.md).
|
|
||||||
|
|
||||||
## Работа с компанией
|
|
||||||
|
|
||||||
Для этого существуют следующие методы:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$doc->setCompany($company);
|
|
||||||
$doc->getCompany();
|
|
||||||
```
|
|
||||||
|
|
||||||
> О работе с компаниями более подробно читайте [здесь](/docs/company.md).
|
|
||||||
|
|
||||||
## Работа с предметами расчёта
|
|
||||||
|
|
||||||
Внутри документа существует [массив предметов расчёта](/docs/items.md#array).
|
|
||||||
По умолчанию он пуст.
|
|
||||||
Напрямую для манипуляций объект массива недоступен.
|
|
||||||
Работа с ним происходит через методы документа:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$doc->setItems([$item1, $item2]);
|
|
||||||
$doc->addItem($item3);
|
|
||||||
$doc->getItems();
|
|
||||||
```
|
|
||||||
|
|
||||||
Соответственно, эти методы выбрасывают те же исключения, что методы самого массива.
|
|
||||||
|
|
||||||
## Работа с оплатами
|
|
||||||
|
|
||||||
Внутри документа существует [массив оплат](/docs/payments.md#array).
|
|
||||||
По умолчанию он пуст.
|
|
||||||
Напрямую для манипуляций объект массива недоступен.
|
|
||||||
Работа с ним происходит через методы документа:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$doc->setPayments([$payment1, $payment2]);
|
|
||||||
$doc->addPayment($payment3);
|
|
||||||
$doc->getPayments();
|
|
||||||
```
|
|
||||||
|
|
||||||
Соответственно, эти методы выбрасывают те же исключения, что методы самого массива.
|
|
||||||
|
|
||||||
Следует отметить, что если при выполнении метода `addPayment()` выполняются следующие условия:
|
|
||||||
* аргументом передан объект оплаты, у которого не задана сумма,
|
|
||||||
* ранее документу не задавались оплаты,
|
|
||||||
то автоматически этому объекту оплаты задаётся полная сумма чека.
|
|
||||||
|
|
||||||
## Работа со ставками НДС
|
|
||||||
|
|
||||||
Внутри документа существует [массив ставок НДС](/docs/vats.md#array).
|
|
||||||
По умолчанию он пуст.
|
|
||||||
Напрямую для манипуляций объект массива недоступен.
|
|
||||||
Работа с ним происходит через методы документа:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$doc->setVats([$vat1, $vat2]);
|
|
||||||
$doc->addVat($vat3);
|
|
||||||
$doc->getVats();
|
|
||||||
```
|
|
||||||
|
|
||||||
Соответственно, эти методы выбрасывают те же исключения, что методы самого массива.
|
|
||||||
|
|
||||||
Также существует метод `clearVats()`, который удаляет все вложенные объекты ставок НДС - из предметов расчёта и самого документа.
|
|
||||||
|
|
||||||
Следует отметить, что если при выполнении метода `addVat()` выполняются следующие условия:
|
|
||||||
* аргументом передан объект ставки, у которого не задана сумма,
|
|
||||||
* ранее документу не задавались ставки,
|
|
||||||
то автоматически этому объекту налога задаётся полная сумма чека, от которой расчитывается итоговый размер налога.
|
|
||||||
|
|
||||||
## Общая сумма документа
|
|
||||||
|
|
||||||
Расчёт происходит автоматически в следующих случаях:
|
|
||||||
* изменение предметов расчёта (`setItems()`, `addItem()`);
|
|
||||||
* добавление оплат (`addPayment()` в случае, когда оплата передана без суммы);
|
|
||||||
* изменение ставок НДС (`setVats()`, `clearVats()`, `addVat()` в случае, когда ставка передана без суммы);
|
|
||||||
* приведение объекта документа к строке.
|
|
||||||
|
|
||||||
Также можно вызвать вручную метод `calcTotal()`.
|
|
||||||
Он расчитывает полную сумму чека по предметам расчёта и пересчитывает **все** налоговые ставки.
|
|
||||||
|
|
||||||
Получить итог можно с помощью метода `getTotal()`.
|
|
||||||
|
|
||||||
Всё в рублях.
|
|
||||||
|
|
||||||
<a name='correction'></a>
|
|
||||||
## Работа с данными коррекции
|
|
||||||
|
|
||||||
Если документ создаётся с целью коррекции прихода или расхода, то он обязательно должен содержать [данные коррекции](/docs/correction_info.md).
|
|
||||||
|
|
||||||
Задать и получить эти данные очень просто:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$doc->setCorrectionInfo(new AtolOnline\Entities\CorrectionInfo(
|
|
||||||
AtolOnline\Constants\CorrectionTypes::SELF, // тип коррекции
|
|
||||||
'01.01.2019', // дата документа коррекции
|
|
||||||
'12345', // номер документа коррекции
|
|
||||||
'test' // описание коррекции
|
|
||||||
));
|
|
||||||
$doc->getCorrectionInfo();
|
|
||||||
```
|
|
||||||
|
|
||||||
## Работа с кассиром
|
|
||||||
|
|
||||||
Для этого существуют следующие методы:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$doc->setCashier('Иванова Лариса Васильевна');
|
|
||||||
$doc->getCashier();
|
|
||||||
```
|
|
||||||
|
|
||||||
## Прочее
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительным приведением к `string`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $doc;
|
|
||||||
$json_string = (string)$doc;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $doc->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
52
docs/entity.md
Normal file
52
docs/entity.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# Сущность
|
||||||
|
|
||||||
|
[Вернуться к содержанию](readme.md#toc)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Сущностями являются все классы, которые необходимы для взаимодействия с API. Они находятся в директори `src/Entities` и
|
||||||
|
расширяют абстрактный класс `AtolOnline\Entities\Entity`.
|
||||||
|
|
||||||
|
Каждая сущность содержит в себе только те данные, которые необходимы согласно схемы АТОЛ Онлайн API.
|
||||||
|
|
||||||
|
Ниже перечислены возможности сущностей.
|
||||||
|
|
||||||
|
## Приведение к строке JSON
|
||||||
|
|
||||||
|
```php
|
||||||
|
echo $entity;
|
||||||
|
$json_string = (string)$entity;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Приведение к массиву
|
||||||
|
|
||||||
|
```php
|
||||||
|
// результат идентичен
|
||||||
|
$json_array1 = $entity->jsonSerialize();
|
||||||
|
$json_array2 = $entity->toArray();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Чтение из массива
|
||||||
|
|
||||||
|
```php
|
||||||
|
$var = new \AtolOnline\Entities\Client('Иванов Иван');
|
||||||
|
echo $var['name']; // 'Иванов Иван'
|
||||||
|
$var['name'] = 'Петров Пётр'; // BadMethodCallException
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fluent-сеттеры
|
||||||
|
|
||||||
|
Реализованы на уровне конкретных классов сущностей, но у некоторых могут полностью отсуствовать.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$entity->setFoo($value)->setBar('bar')->...
|
||||||
|
```
|
||||||
|
|
||||||
|
Сеттеры валидируют и фильтруют данные согласно схеме АТОЛ Онлайн API, а в случае ошибочных значений -- выбрасывают
|
||||||
|
исключения.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Читай также: [Коллекция сущностей](collection.md)
|
||||||
|
|
||||||
|
[Вернуться к содержанию](readme.md#toc)
|
||||||
237
docs/fiscalizing.md
Normal file
237
docs/fiscalizing.md
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
# Фискализация документов
|
||||||
|
|
||||||
|
[Вернуться к содержанию](readme.md#toc)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Доступ к ККТ
|
||||||
|
|
||||||
|
Для работы с облачной ККТ необходимы следующие параметры:
|
||||||
|
|
||||||
|
* логин;
|
||||||
|
* пароль;
|
||||||
|
* код группы.
|
||||||
|
|
||||||
|
Чтоы получить их, нужно:
|
||||||
|
|
||||||
|
1. авторизоваться в личном кабинете [online.atol.ru](https://online.atol.ru/lk/Account/Login);
|
||||||
|
2. на странице [Мои компании](https://online.atol.ru/lk/Company/List) нажать кнопку **Настройки интегратора**.
|
||||||
|
Скачается XML-файл с нужными настройками.
|
||||||
|
|
||||||
|
Также для работы потребуются:
|
||||||
|
|
||||||
|
* ИНН продавца;
|
||||||
|
* URL места расчёта (ссылка на ваш интернет-сервис).
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
Объект ККТ инициализируется следующим образом:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$kkt = new AtolOnline\Api\Fiscalizer();
|
||||||
|
```
|
||||||
|
|
||||||
|
Установить параметры подключения можно двумя путями:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use AtolOnline\Api\Fiscalizer;
|
||||||
|
|
||||||
|
// 1 способ - через конструктор
|
||||||
|
$kkt = new Fiscalizer(group: 'mygroup', login: 'mylogin', password: 'mypassword');
|
||||||
|
|
||||||
|
// 2 способ - через сеттеры
|
||||||
|
$kkt = (new Fiscalizer())
|
||||||
|
->setLogin($login)
|
||||||
|
->setGroup($group)
|
||||||
|
->setPassword($password);
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="testmode"></a>
|
||||||
|
|
||||||
|
## Тестовый режим
|
||||||
|
|
||||||
|
По умолчанию фискализатор создаётся для работы в тестовом режиме. Это означает, что работа с АТОЛ Онлайн API будет
|
||||||
|
происходить [в тестовой среде](https://online.atol.ru/files/ffd/test_sreda.txt).
|
||||||
|
|
||||||
|
> Под тестовым режимом работы подразумевается использование тестовых ККТ, которые принадлежат компании АТОЛ.
|
||||||
|
|
||||||
|
Управление тестовым режимом происходит следующим образом:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$kkt = new Fiscalizer(); // включен по умолчанию
|
||||||
|
$kkt = new Fiscalizer(false); // выключен явно
|
||||||
|
$kkt->setTestMode(); // включен явно
|
||||||
|
$kkt->setTestMode(true); // включен явно
|
||||||
|
$kkt->setTestMode(false); // выключен явно
|
||||||
|
```
|
||||||
|
|
||||||
|
**При включенном тестовом режиме используются тестовые ККТ**, т.к. перед отправкой запроса подменяются:
|
||||||
|
|
||||||
|
* логин;
|
||||||
|
* пароль;
|
||||||
|
* группа ККТ;
|
||||||
|
* ИНН клиента (покупателя);
|
||||||
|
* ИНН и адрес места расчётов компании (продавца).
|
||||||
|
|
||||||
|
Таким образом:
|
||||||
|
|
||||||
|
* использовать тестовый режим -- безопасно;
|
||||||
|
* при переключении тестового режима устанавливать заново свои параметры подключения не требуется.
|
||||||
|
|
||||||
|
**При выключенном тестовом режиме используются ваши ККТ.**
|
||||||
|
|
||||||
|
Если по каким-то причинам у вас не получится использовать тестовый режим, вы можете проводить свои тесты в боевом
|
||||||
|
режиме (на собственной ККТ). В этом случае важно понимать следующее:
|
||||||
|
|
||||||
|
1. сразу после оформления документа **прихода** необходимо оформлять точно такой же документ **возврата прихода**;
|
||||||
|
2. [вы обязательно забудете о пункте 1](http://murphy-law.net.ru/basics.html);
|
||||||
|
3. пп. 1 и 2 в любом случае скажутся на ваших финансовых отчётах;
|
||||||
|
4. вся ответственность за пп. 1-3 и последствия ложится только на вас.
|
||||||
|
|
||||||
|
## Авторизация на ККТ
|
||||||
|
|
||||||
|
Перед первым запросом на ККТ происходит аутентификация на сервере по логину и паролю. В ответ приходит авторизационный
|
||||||
|
токен, срок жизни коего равен **24 часам**. После первой успешной операции возможно получить этот токен следующим
|
||||||
|
образом:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$kkt->getToken(); // вернёт строку длиной 128 символа
|
||||||
|
```
|
||||||
|
|
||||||
|
Этот токен можно сохранить и переиспользовать в течение всего срока его жизни, но далее следует получить новый токен.
|
||||||
|
|
||||||
|
Ранее полученный токен следует указывать до отправки запросов следующим образом:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$kkt->setToken($token_string);
|
||||||
|
```
|
||||||
|
|
||||||
|
Если токен был установлен перед выполнением операции, то при выполнении операции будет использоваться именно он. Если
|
||||||
|
операция завершится ошибочно из-за истёкшего токена, следует повторить операцию без использования метода `setToken()`,
|
||||||
|
либо обнулив его следующим образом:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$kkt->setToken(null);
|
||||||
|
```
|
||||||
|
|
||||||
|
Тогда будет получен новый токен.
|
||||||
|
|
||||||
|
## Регистрация документа
|
||||||
|
|
||||||
|
Для регистрации документа **прихода** необходимо вызвать метод `sell()`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$result = $kkt->sell($document);
|
||||||
|
$result2 = $receipt->sell($kkt);
|
||||||
|
```
|
||||||
|
|
||||||
|
Для регистрации документа **возврата прихода** необходимо вызвать метод `sellRefund()`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$result = $kkt->sellRefund($document);
|
||||||
|
$result2 = $receipt->sellRefund($kkt);
|
||||||
|
```
|
||||||
|
|
||||||
|
Для регистрации документа **расхода** необходимо вызвать метод `buy()`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$result = $kkt->buy($document);
|
||||||
|
$result2 = $receipt->buy($kkt);
|
||||||
|
```
|
||||||
|
|
||||||
|
Для регистрации документа **возврата расхода** необходимо вызвать метод `buyRefund()`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$result = $kkt->buyRefund($document);
|
||||||
|
$result2 = $receipt->buyRefund($kkt);
|
||||||
|
```
|
||||||
|
|
||||||
|
Для регистрации документа **коррекции прихода** необходимо вызвать метод `sellCorrection()`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$result = $kkt->sellCorrect($document);
|
||||||
|
$result2 = $correction->sellCorrect($kkt);
|
||||||
|
```
|
||||||
|
|
||||||
|
Для регистрации документа **коррекции расхода** необходимо вызвать метод `buyCorrection()`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$result = $kkt->buyCorrect($document);
|
||||||
|
$result2 = $correction->buyCorrect($kkt);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Собственный идентификатор документа (`external_id`)
|
||||||
|
|
||||||
|
Каждый документ, переданный на ККТ для регистрации, всегда имеет свой идентификатор, абсолютно уникальный среди всех
|
||||||
|
документов когда-либо регистрировавшихся на ККТ, даже если при регистрации были ошибки. По умолчанию это UUID версии 4.
|
||||||
|
|
||||||
|
Чтобы использовать собственный идентификатор, следует передать нужное строковое значение вторым параметром в любой из
|
||||||
|
шести описанных выше методов, например:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$result = $kkt->sellRefund($document, 'order_' . $order->id);
|
||||||
|
```
|
||||||
|
|
||||||
|
Если `external_id` не указан явно или имеет пустое значение, то будет сгенерирован новый UUID. Узнать его можно будет
|
||||||
|
только в ответе от ККТ после регистрации документа в очереди на фискализацию.
|
||||||
|
|
||||||
|
### Передача `callback_url`
|
||||||
|
|
||||||
|
Перед регистрацией документа можно указать `callback_url`. АТОЛ отправит на указанный URL результат регистрации. По
|
||||||
|
этому адресу должен располагаться ваш собственный обработчик статуса фискализации.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$kkt->setCallbackUrl('http://example.com/process-kkt-result');
|
||||||
|
$kkt->getCallbackUrl();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Проверка статуса документа
|
||||||
|
|
||||||
|
Если перед отправкой документа на регистрацию был задан `callback_url` через метод `setCallbackUrl()`, то ответ придёт
|
||||||
|
на указанный адрес автоматически, как только документ обработается на стороне ККТ. Ответ может быть как об успешной
|
||||||
|
регистрации, так и ошибочной.
|
||||||
|
|
||||||
|
В любом случае, вам доступны два метода, с помощью которых вы можете проверять статус документа самостоятельно:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$kkt->getDocumentStatus(); // делает единичный запрос
|
||||||
|
$kkt->pollDocumentStatus(); // делает запросы до получения конечного статуса (не-wait)
|
||||||
|
```
|
||||||
|
|
||||||
|
Эти методы принимают на вход `uuid` кода регистрации. Этот UUID нужно взять из ответа, полученного при отправке
|
||||||
|
документа на регистрацию:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$sell_result = $kkt->sell($document);
|
||||||
|
$status = $kkt->pollDocumentStatus($sell_result->uuid);
|
||||||
|
```
|
||||||
|
|
||||||
|
Метод `pollDocumentStatus()` многократно опрашивает ККТ на предмет состояния документа. Метод может принимать до трёх
|
||||||
|
параметров:
|
||||||
|
|
||||||
|
* uuid;
|
||||||
|
* количество попыток (по умолчанию — 5);
|
||||||
|
* время между попытками в секундах (по умолчанию — 1).
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Проверять статус 10 раз на протяжении 20 секунд — каждые две секунды
|
||||||
|
$kkt->pollDocumentStatus($sell_result->uuid, 10, 20);
|
||||||
|
```
|
||||||
|
|
||||||
|
Учитывайте, что метод вернёт результат как только сменится статус регистрации на успешный `done` или ошибочный `error`.
|
||||||
|
|
||||||
|
Использовать его лучше сразу после отправки документа на регистрацию (как в примере выше).
|
||||||
|
|
||||||
|
> Как правило, фискализация одного документа занимает 4-6 секунд с учётом регистрации.
|
||||||
|
|
||||||
|
Метод `getDocumentStatus()` принимает на вход только `uuid` и запрашивает состояние документа лишь единожды.
|
||||||
|
Использовать его целесообразнее в те моменты, когда нет необходимости знать успех регистрации сразу после отправки
|
||||||
|
документа.
|
||||||
|
|
||||||
|
> Обратите внимание, что АТОЛ позволяет получать статус документа в течение 32 суток с момента его регистрации.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Читай также: [Обработка ответа API](response.md)
|
||||||
|
|
||||||
|
[Вернуться к содержанию](readme.md#toc)
|
||||||
202
docs/items.md
202
docs/items.md
@@ -1,202 +0,0 @@
|
|||||||
# Работа с предметами расчёта
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Один объект
|
|
||||||
|
|
||||||
Объект предмета расчёта инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$vat = new AtolOnline\Entities\Item();
|
|
||||||
```
|
|
||||||
|
|
||||||
У объекта предмета расчёта должны быть указаны все следующие обязательные атрибуты:
|
|
||||||
* наименование (тег ФФД - 1030);
|
|
||||||
* цена (тег ФФД - 1079);
|
|
||||||
* количество, вес (тег ФФД - 1023).
|
|
||||||
|
|
||||||
У объекта предмета расчёта также могут быть указаны следующие необязательные атрибуты:
|
|
||||||
* единица измерения количества (тег ФФД - 1197);
|
|
||||||
* признак способа оплаты (тег ФФД - 1214) - перечислены в классе `AtolOnline\Constants\PaymentMethods`;
|
|
||||||
* признак предмета расчёта (тег ФФД - 1212) - перечислены в классе `AtolOnline\Constants\PaymentObjects`;
|
|
||||||
* [ставка НДС](/docs/vats.md);
|
|
||||||
* дополнительный реквизит (тег ФФД - 1191).
|
|
||||||
|
|
||||||
Установить многие (но не все) атрибуты можно следующими способами:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use AtolOnline\{
|
|
||||||
Constants\PaymentMethods,
|
|
||||||
Constants\PaymentObjects,
|
|
||||||
Constants\VatTypes,
|
|
||||||
Entities\Item
|
|
||||||
};
|
|
||||||
|
|
||||||
// 1 способ - через конструктор
|
|
||||||
$item = new Item(
|
|
||||||
'Банан', // наименование
|
|
||||||
100, // цена
|
|
||||||
1, // количество, вес
|
|
||||||
'кг', // единица измерения
|
|
||||||
VatTypes::VAT20, // ставка НДС
|
|
||||||
PaymentObjects::SERVICE, // признак предмета расчёта
|
|
||||||
PaymentMethods::FULL_PAYMENT // признак способа расчёта
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2 способ - через сеттеры
|
|
||||||
$item = new Item();
|
|
||||||
$item->setName('Банан');
|
|
||||||
$item->setPrice(100);
|
|
||||||
$item->setQuantity(2.41);
|
|
||||||
//$item->setQuantity(2.41, 'кг');
|
|
||||||
$item->setMeasurementUnit('кг');
|
|
||||||
$item->setVatType(VatTypes::VAT20);
|
|
||||||
$item->setPaymentObject(PaymentObjects::COMMODITY);
|
|
||||||
$item->setPaymentMethod(PaymentMethods::FULL_PAYMENT);
|
|
||||||
```
|
|
||||||
|
|
||||||
Метод `setName()` проверяет входную строку на длину (до 128 символов).
|
|
||||||
Выбрасывает исключение `AtolNameTooLongException` (если слишком длинное наименование).
|
|
||||||
|
|
||||||
Метод `setPrice()` проверяет аргумент на величину (до 42949672.95) и пересчитывает общую стоимость.
|
|
||||||
Выбрасывает исключение `AtolPriceTooHighException` (если цена слишком высока).
|
|
||||||
|
|
||||||
Метод `setMeasurementUnit()` проверяет входную строку на длину (до 16 символов).
|
|
||||||
Выбрасывает исключение `AtolUnitTooLongException` (если слишком длинная строка единицы измерения).
|
|
||||||
|
|
||||||
Метод `setQuantity()` проверяет первый аргумент на величину (до 99999.999) и пересчитывает общую стоимость.
|
|
||||||
Выбрасывает исключения:
|
|
||||||
* `AtolQuantityTooHighException` (если количество слишком велико);
|
|
||||||
* `AtolPriceTooHighException` (если общая стоимость слишком велика).
|
|
||||||
|
|
||||||
Также вторым аргументом может принимать единицу измерения количества.
|
|
||||||
В этом случае дополнительно работает сеттер `setMeasurementUnit()`.
|
|
||||||
|
|
||||||
Метод `setVatType()` задаёт тип ставки НДС, пересчитывает размер налога и общую стоимость.
|
|
||||||
Выбрасывает исключение `AtolPriceTooHighException` (если цена слишком высока).
|
|
||||||
Может принимать `null` для удаления налога.
|
|
||||||
|
|
||||||
Дополнительный реквизит устанавливается отдельным методом `setUserData()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item->setUserData('some data');
|
|
||||||
```
|
|
||||||
|
|
||||||
Он проверяет строку на длину (до 64 символов).
|
|
||||||
Выбрасывает исключение `AtolUserdataTooLongException` (если слишком длинный дополнительный реквизит).
|
|
||||||
|
|
||||||
Для установки признака предмета расчёта существует метод `setPaymentObject()`.
|
|
||||||
На вход следует передавать одной из значений, перечисленных в классе `AtolOnline\Constants\PaymentObjects`.
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item->setPaymentObject(AtolOnline\Constants\PaymentObjects::JOB);
|
|
||||||
```
|
|
||||||
|
|
||||||
Для установки признака способа оплаты существует метод `setPaymentMethod()`.
|
|
||||||
На вход следует передавать одной из значений, перечисленных в классе `AtolOnline\Constants\PaymentMethods`.
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item->setPaymentMethod(AtolOnline\Constants\PaymentMethods::FULL_PAYMENT);
|
|
||||||
```
|
|
||||||
|
|
||||||
Для получения заданных значений атрибутов реализованы соответствующие геттеры:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item->getName();
|
|
||||||
$item->getPrice();
|
|
||||||
$item->getQuantity();
|
|
||||||
$item->getMeasurementUnit();
|
|
||||||
$item->getPaymentMethod();
|
|
||||||
$item->getPaymentObject();
|
|
||||||
$item->getVat(); // возвращает объект ставки НДС либо null
|
|
||||||
$item->getUserData();
|
|
||||||
```
|
|
||||||
|
|
||||||
Для пересчёта общей стоимости и размера налога существует метод `calcSum()`.
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item->calcSum();
|
|
||||||
```
|
|
||||||
|
|
||||||
Этот метод отрабатывает при вызове `setPrice()`, `setQuantity()` и `setVatType()`.
|
|
||||||
Выбрасывает исключение `AtolPriceTooHighException` (если общая сумма слишком высока).
|
|
||||||
|
|
||||||
Получить уже расчитанную общую сумму можно простым геттером:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item->getSum();
|
|
||||||
```
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительным приведением к `string`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $item;
|
|
||||||
$json_string = (string)$item;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $item->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
<a name="array"></a>
|
|
||||||
## Массив объектов предметов расчёта
|
|
||||||
|
|
||||||
> Максимальное количество объектов в массиве - 100.
|
|
||||||
|
|
||||||
Массив инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item_array = new AtolOnline\Entities\ItemArray();
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы задать содержимое массива, используйте метод `set()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item_array->set([
|
|
||||||
$item_object1,
|
|
||||||
$item_object2
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
Очистить его можно передачей в сеттер пустого массива:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item_array->set([]);
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы добавить объект к существующим элементам массива, используйте метод `add()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item = new AtolOnline\Entities\Item('Банан', 100, 1);
|
|
||||||
$item_array->add($item);
|
|
||||||
```
|
|
||||||
|
|
||||||
Методы `set()` и `add()` проверяют количество элементов в массиве перед его обновлением.
|
|
||||||
Выбрасывают исключение `AtolTooManyItemsException` (если в массиве уже максимальное количество объектов).
|
|
||||||
|
|
||||||
Чтобы получить содержимое массива, используйте метод `get()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$item_array->get();
|
|
||||||
```
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительным приведением к `string`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $item_array;
|
|
||||||
$json_string = (string)$item_array;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $item_array->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
317
docs/kkt.md
317
docs/kkt.md
@@ -1,317 +0,0 @@
|
|||||||
# Работа с ККТ
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Доступ к ККТ
|
|
||||||
|
|
||||||
Для работы с облачной ККТ необходимы следующие параметры:
|
|
||||||
|
|
||||||
* логин;
|
|
||||||
* пароль;
|
|
||||||
* код группы.
|
|
||||||
|
|
||||||
Чтоы получить их, нужно:
|
|
||||||
|
|
||||||
1. авторизоваться в личном кабинете [online.atol.ru](https://online.atol.ru/lk/Account/Login);
|
|
||||||
2. на странице [Мои компании](https://online.atol.ru/lk/Company/List) нажать кнопку **Настройки интегратора**.
|
|
||||||
Скачается XML-файл с нужными настройками.
|
|
||||||
|
|
||||||
Также для работы потребуются:
|
|
||||||
|
|
||||||
* ИНН продавца;
|
|
||||||
* URL места расчёта (ссылка на ваш интернет-сервис).
|
|
||||||
|
|
||||||
## Использование
|
|
||||||
|
|
||||||
Объект ККТ инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$kkt = new AtolOnline\Api\Kkt();
|
|
||||||
```
|
|
||||||
|
|
||||||
## Настройка ККТ
|
|
||||||
|
|
||||||
Для работы с облачной ККТ необходимы следующие параметры:
|
|
||||||
* логин кассы;
|
|
||||||
* пароль кассы;
|
|
||||||
* код группы кассы;
|
|
||||||
|
|
||||||
Чтоб получить их, нужно:
|
|
||||||
1. авторизоваться на [online.atol.ru](https://online.atol.ru/lk/Account/Login);
|
|
||||||
2. на странице [Мои компании](https://online.atol.ru/lk/Company/List) нажать кнопку **Настройки интегратора**.
|
|
||||||
Скачается XML-файл с нужными настройками.
|
|
||||||
|
|
||||||
Установить эти параметры можно двумя путями:
|
|
||||||
|
|
||||||
```php
|
|
||||||
// 1 способ - через конструктор
|
|
||||||
$kkt = new AtolOnline\Api\Kkt($group, $login, $password);
|
|
||||||
|
|
||||||
// 2 способ - через сеттеры
|
|
||||||
$kkt = (new AtolOnline\Api\Kkt())
|
|
||||||
->setLogin($login)
|
|
||||||
->setGroup($group)
|
|
||||||
->setPassword($password);
|
|
||||||
```
|
|
||||||
|
|
||||||
Получить заданные параметры можно через соответствующие геттеры:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$kkt->getLogin();
|
|
||||||
$kkt->getPassword();
|
|
||||||
$kkt->getGroup();
|
|
||||||
```
|
|
||||||
|
|
||||||
Также для работы потребуются:
|
|
||||||
* ИНН продавца;
|
|
||||||
* URL места расчёта (ссылка на ваш интернет-сервис).
|
|
||||||
|
|
||||||
Эти параметры нужно задать [объекту компании](/docs/company.md), который будет передаваться в документах через эту ККТ.
|
|
||||||
|
|
||||||
<a name='testmode'></a>
|
|
||||||
## Тестовый режим
|
|
||||||
|
|
||||||
На самом деле, в АТОЛ Онлайн нет понятия *тестовая операция* или чего-то в этом духе.
|
|
||||||
АТОЛ предоставляет нам отдельную тестовую среду (ККТ).
|
|
||||||
[Её настройки](https://online.atol.ru/files/ffd/test_sreda.txt) уже указаны в коде библиотеки.
|
|
||||||
*Под тестовым режимом работы подразумевается использование другой (тестовой) ККТ.*
|
|
||||||
|
|
||||||
При включенном тестовом режиме:
|
|
||||||
* меняется логин, пароль и группа (для обращения на тестовую ККТ)
|
|
||||||
* между авторизацией и операцией над документом, в `Company` документа переопределяется ИНН, СНО и адрес места
|
|
||||||
расчётов на те, что указаны в [параметрах тестовой среды](https://online.atol.ru/files/ffd/test_sreda.txt).
|
|
||||||
|
|
||||||
В библиотеке есть переключатель настроек ККТ.
|
|
||||||
С его помощью можете поменять вашу боевую ККТ на тестовую и наоборот.
|
|
||||||
Это можно сделать одним из следующих способов:
|
|
||||||
|
|
||||||
```php
|
|
||||||
// включить в любом месте кода:
|
|
||||||
$kkt->setTestMode();
|
|
||||||
$kkt->setTestMode(true);
|
|
||||||
$kkt->setTestMode(false); // выключить
|
|
||||||
```
|
|
||||||
|
|
||||||
> Если вы включили тестовый режим (как показано выше), то используются именно эта ККТ, а не ваша.
|
|
||||||
> После выключения тестового режима настройки доступа к ККТ меняются на ваши (используется уже ваша ККТ).
|
|
||||||
|
|
||||||
Для включения тестового режима необязательно задавать параметры боевой ККТ.
|
|
||||||
|
|
||||||
Если по каким-то причинам у вас не получится использовать тестовый режим, вы можете проводить свои тесты в боевом
|
|
||||||
режиме (на собственной ККТ).
|
|
||||||
В этом случае важно понимать следующее:
|
|
||||||
1. сразу после оформления документа **прихода** необходимо оформлять точно такой же документ **возврата прихода**;
|
|
||||||
2. [вы обязательно забудете о пункте 1](http://murphy-law.net.ru/basics.html);
|
|
||||||
3. пп. 1 и 2 в любом случае скажутся на ваших финансовых отчётах;
|
|
||||||
4. вся ответственность за пп. 1-3 и последствия ложится только на вас.
|
|
||||||
|
|
||||||
## Авторизация на ККТ
|
|
||||||
|
|
||||||
Перед первым запросом на ККТ происходит аутентификация на сервере по логину и паролю.
|
|
||||||
В ответ приходит авторизационный токен, срок жизни коего равен **24 часам**.
|
|
||||||
После первой успешной операции возможно получить этот токен следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$kkt->getAuthToken(); // вернёт строку длиной 128 символа
|
|
||||||
```
|
|
||||||
|
|
||||||
Этот токен можно сохранить и переиспользовать в течение всего срока его жизни.
|
|
||||||
Спустя это время следует получить новый токен.
|
|
||||||
|
|
||||||
Для дальнейшего использования однажды полученный токен следует указывать следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$kkt->setAuthToken($token_string);
|
|
||||||
```
|
|
||||||
|
|
||||||
Если токен был установлен перед выполнением операции, то при выполнении операции будет использоваться именно он, а новый
|
|
||||||
запрашиваться не будет. Если операция завершится ошибочно из-за истёкшего токена, следует повторить операцию без
|
|
||||||
использования метода `setAuthToken()`, либо обнулив его следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$kkt->setAuthToken(null);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Регистрация документа
|
|
||||||
|
|
||||||
Для регистрации документа **прихода** необходимо вызвать метод `sell()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$result = $kkt->sell($document);
|
|
||||||
```
|
|
||||||
|
|
||||||
Для регистрации документа **возврата прихода** необходимо вызвать метод `sellRefund()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$result = $kkt->sellRefund($document);
|
|
||||||
```
|
|
||||||
|
|
||||||
Для регистрации документа **расхода** необходимо вызвать метод `buy()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$result = $kkt->buy($document);
|
|
||||||
```
|
|
||||||
|
|
||||||
Для регистрации документа **возврата расхода** необходимо вызвать метод `buyRefund()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$result = $kkt->buyRefund($document);
|
|
||||||
```
|
|
||||||
|
|
||||||
Для операций, перечисленных выше, документы не должны содержать [данных коррекции](/docs/documents.md#correction).
|
|
||||||
Тогда как для операций коррекции, которые описаны ниже, эти данные должны присутствовать.
|
|
||||||
|
|
||||||
Для регистрации документа **коррекции прихода** необходимо вызвать метод `sellCorrection()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$result = $kkt->sellCorrection($document);
|
|
||||||
```
|
|
||||||
|
|
||||||
Для регистрации документа **коррекции расхода** необходимо вызвать метод `buyCorrection()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$result = $kkt->buyCorrection($document);
|
|
||||||
```
|
|
||||||
|
|
||||||
Любой из перечисленных выше шести методов может выбросить исключение `AtolAuthFailedException` при ошибке
|
|
||||||
аутентификации или авторизации.
|
|
||||||
|
|
||||||
### Собственный идентификатор документа
|
|
||||||
|
|
||||||
Каждый документ, переданный на ККТ для регистрации, всегда имеет свой идентификатор, абсолютно уникальный среди всех
|
|
||||||
документов когда-либо регистрировавшихся на ККТ, даже если при регистрации были ошибки.
|
|
||||||
По умолчанию это UUID версии 4.
|
|
||||||
|
|
||||||
Чтобы использовать собственный идентификатор, следует передать нужное строковое значение вторым параметром в любой из
|
|
||||||
шести описанных выше методов, например:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$kkt->sell($document, $my_unique_id);
|
|
||||||
$kkt->sellRefund($document, $my_unique_id);
|
|
||||||
$kkt->buy($document, $my_unique_id);
|
|
||||||
$kkt->buyRefund($document, $my_unique_id);
|
|
||||||
$kkt->sellCorrection($document, $my_unique_id);
|
|
||||||
$kkt->buyCorrection($document, $my_unique_id);
|
|
||||||
```
|
|
||||||
|
|
||||||
Если `$my_unique_id` равен `null` или пустой строке, то будет сгенерирован новый UUID.
|
|
||||||
Узнать его можно будет только в ответе от ККТ.
|
|
||||||
|
|
||||||
### Передача callback_url
|
|
||||||
|
|
||||||
Перед регистрацией документа можно указать `callback_url`.
|
|
||||||
АТОЛ отправит на указанный URL результат регистрации.
|
|
||||||
По этому адресу должен располагаться код, который будет обрабатывать этот результат.
|
|
||||||
|
|
||||||
```php
|
|
||||||
$kkt->setCallbackUrl('http://example.com/process-kkt-result');
|
|
||||||
$kkt->getCallbackUrl();
|
|
||||||
```
|
|
||||||
|
|
||||||
Метод `setCallbackUrl()` проверяет входную строку на длину (до 256 символов) и валидность формата url по
|
|
||||||
регулярному выражению:
|
|
||||||
|
|
||||||
```
|
|
||||||
^http(s?)\:\/\/[0-9a-zA-Zа-яА-Я]([-.\w]*[0-9a-zA-Zа-яА-Я])*(:(0-9)*)*(\/?)([a-zAZ0-9а-яА-Я\-\.\?\,\'\/\\\+&=%$#_]*)?$
|
|
||||||
```
|
|
||||||
|
|
||||||
Выбрасывает исключения:
|
|
||||||
* `AtolCallbackUrlTooLongException` (если слишком длинный url);
|
|
||||||
* `AtolInvalidCallbackUrlException` (если url невалиден).
|
|
||||||
|
|
||||||
## Обработка результата регистрации
|
|
||||||
|
|
||||||
Методы `sell()`, `sellRefund()`, `sellCorrection()`, `buy()`, `buyRefund()` и `buyCorrection()` возвращают объект `AtolOnline\Api\KktResponse`.
|
|
||||||
|
|
||||||
Этот же объект можно получить через геттер `getLastResponse()`.
|
|
||||||
|
|
||||||
Этот объект содержит в себе HTTP-код ответа, массив заголовков и JSON-декодированные данные тела ответа.
|
|
||||||
|
|
||||||
```php
|
|
||||||
$result = $kkt->getLastResponse(); // вернёт последний ответ от API
|
|
||||||
$headers = $result->getHeaders(); // вернёт заголовки
|
|
||||||
$code = $result->getCode(); // вернёт код ответа
|
|
||||||
$body = $result->getContent(); // вернёт JSON-декодированное тело ответа
|
|
||||||
```
|
|
||||||
|
|
||||||
Обращаться к полям JSON-декодированного объекта можно опуская вызов метода `getContent()` таким образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
// вернёт значение поля uuid
|
|
||||||
$uuid = $result->getContent()->uuid;
|
|
||||||
$uuid = $result->uuid;
|
|
||||||
// вернёт текст ошибки
|
|
||||||
$err_text = $result->getContent()->error->text;
|
|
||||||
$err_text = $result->error->text;
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверка корректности ответа (отсутствия ошибок) работает через метод `isValid()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$kkt->getLastResponse()->isValid(); // вернёт true, если ошибок нет
|
|
||||||
```
|
|
||||||
|
|
||||||
## Проверка статуса документа
|
|
||||||
|
|
||||||
Если перед отправкой документа на регистрацию был задан callback_url через метод `setCallbackUrl()`, то ответ придёт на указанный адрес автоматически, как только документ обработается на стороне ККТ.
|
|
||||||
Ответ может быть как об успешной регистрации, так и ошибочной.
|
|
||||||
|
|
||||||
В любом случае, вам доступны два метода, с помощью которых вы можете проверять статус документа самостоятельно:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$kkt->getDocumentStatus();
|
|
||||||
$kkt->pollDocumentStatus();
|
|
||||||
```
|
|
||||||
|
|
||||||
Эти методы принимают на вход `uuid` кода регистрации.
|
|
||||||
Этот UUID можно получить из ответа, полученного при отправке документа на регистрацию:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$sell_result = $kkt->sell($document);
|
|
||||||
$kkt->pollDocumentStatus($sell_result->uuid);
|
|
||||||
$kkt->getDocumentStatus($sell_result->uuid);
|
|
||||||
```
|
|
||||||
|
|
||||||
Метод `pollDocumentStatus()` многократно опрашивает ККТ на предмет состояния документа.
|
|
||||||
Метод может принимать до трёх параметров:
|
|
||||||
* uuid;
|
|
||||||
* количество попыток (по умолчанию — 5);
|
|
||||||
* время между попытками в секундах (по умолчанию — 1).
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Проверять статус 10 раз на протяжении 20 секунд — каждые две секунды
|
|
||||||
$kkt->pollDocumentStatus($sell_result->uuid, 10, 20);
|
|
||||||
```
|
|
||||||
|
|
||||||
Учитывайте, что метод вернёт результат как только сменится статус регистрации на успешный или ошибочный.
|
|
||||||
|
|
||||||
Использовать его лучше сразу после отправки документа на регистрацию (как в примере выше).
|
|
||||||
|
|
||||||
> Как правило, полная регистрация одного документа занимает 4-5 секунд.
|
|
||||||
|
|
||||||
Метод `getDocumentStatus()` принимает на вход только `uuid` и запрашивает состояние документа лишь единожды.
|
|
||||||
Использовать его целесообразнее в те моменты, когда нет необходимости знать успех регистрации сразу после отправки документа.
|
|
||||||
|
|
||||||
> Обратите внимание, что АТОЛ позволяет получать статус документа в течение 32 суток с момента его регистрации.
|
|
||||||
|
|
||||||
Методы `pollDocumentStatus()` и `getDocumentStatus()` возвращают объект `AtolOnline\Api\KktResponse`.
|
|
||||||
Оба выбрасывают исключение `AtolUuidValidateException` (если переданная строка UUID невалидна).
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительным приведением к `string`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $item;
|
|
||||||
$json_string = (string)$item;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $item->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Мониторинг ККТ
|
# Мониторинг ККТ
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
[Вернуться к содержанию](readme.md#toc)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -12,13 +12,13 @@
|
|||||||
|
|
||||||
```php
|
```php
|
||||||
// можно передать параметры подключения в конструктор
|
// можно передать параметры подключения в конструктор
|
||||||
$monitor = new AtolOnline\Api\KktMonitor(
|
$monitor = new AtolOnline\Api\Monitor(
|
||||||
login: 'mylogin',
|
login: 'mylogin',
|
||||||
password: 'qwerty'
|
password: 'qwerty'
|
||||||
);
|
);
|
||||||
|
|
||||||
// можно - отдельными сеттерами
|
// можно - отдельными сеттерами
|
||||||
$monitor = new AtolOnline\Api\KktMonitor();
|
$monitor = new AtolOnline\Api\Monitor();
|
||||||
->setLogin($credentials['login'])
|
->setLogin($credentials['login'])
|
||||||
->setPassword($credentials['password']);
|
->setPassword($credentials['password']);
|
||||||
```
|
```
|
||||||
@@ -30,7 +30,7 @@ $monitor = new AtolOnline\Api\KktMonitor();
|
|||||||
|
|
||||||
```php
|
```php
|
||||||
// передачей в конструктор `false` первым параметром:
|
// передачей в конструктор `false` первым параметром:
|
||||||
$monitor = new AtolOnline\Api\KktMonitor(false, /*...*/);
|
$monitor = new AtolOnline\Api\Monitor(false, /*...*/);
|
||||||
|
|
||||||
// или отдельным сеттером
|
// или отдельным сеттером
|
||||||
$monitor->setTestMode(false);
|
$monitor->setTestMode(false);
|
||||||
@@ -107,10 +107,12 @@ $kkt = $monitor->getOne($kkts->first()->serialNumber);
|
|||||||
|
|
||||||
Класс `AtolOnline\Api\KktMonitor` расширяет абстрактный класс `AtolOnline\Api\AtolClient`.
|
Класс `AtolOnline\Api\KktMonitor` расширяет абстрактный класс `AtolOnline\Api\AtolClient`.
|
||||||
|
|
||||||
Это значит, что последний ответ от API АТОЛ всегда сохраняется объектом класса `AtolOnline\Api\KktResponse`. К нему
|
Это значит, что последний ответ от API АТОЛ всегда сохраняется объектом класса `AtolOnline\Api\AtolReponse`. К нему
|
||||||
можно обратиться через метод `AtolOnline\Api\KktMonitor::getResponse()`, независимо от того, что возвращают другие
|
можно обратиться через метод `AtolOnline\Api\KktMonitor::getResponse()`, независимо от того, что возвращают другие
|
||||||
методы монитора.
|
методы монитора.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
Читай также: [Обработка ответа API](response.md)
|
||||||
|
|
||||||
|
[Вернуться к содержанию](readme.md#toc)
|
||||||
|
|||||||
134
docs/payments.md
134
docs/payments.md
@@ -1,134 +0,0 @@
|
|||||||
# Работа с оплатами
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Один объект
|
|
||||||
|
|
||||||
Объект оплаты инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$payment = new AtolOnline\Entities\Payment();
|
|
||||||
```
|
|
||||||
|
|
||||||
У объекта оплаты должны быть указаны все следующие атрибуты:
|
|
||||||
* тип оплаты (теги ФФД: 1031, 1081, 1215, 1216, 1217) - все типы перечислены в классе `AtolOnline\Constants\PaymentTypes` (по умолчанию `ELECTRON`)
|
|
||||||
* сумма оплаты (теги ФФД: 1031, 1081, 1215, 1216, 1217; по умолчанию 0)
|
|
||||||
|
|
||||||
> Все эти атрибуты являются **обязательными**.
|
|
||||||
|
|
||||||
Установить атрибуты можно следующими способами:
|
|
||||||
|
|
||||||
```php
|
|
||||||
// 1 способ - через конструктор
|
|
||||||
$payment = new AtolOnline\Entities\Payment(
|
|
||||||
AtolOnline\Constants\PaymentTypes::OTHER, // тип оплаты
|
|
||||||
123.45 // сумма оплаты
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2 способ - через сеттер
|
|
||||||
$payment = (new AtolOnline\Entities\Payment())
|
|
||||||
->setType(AtolOnline\Constants\PaymentTypes::OTHER) // тип оплаты
|
|
||||||
->setSum(123.45); // сумма оплаты
|
|
||||||
```
|
|
||||||
|
|
||||||
Размер налога высчитывается автоматически из общей суммы.
|
|
||||||
Сумму, от которой нужно расчитать размер налога, можно передать следующими способами:
|
|
||||||
|
|
||||||
```php
|
|
||||||
// 1 способ - через конструктор
|
|
||||||
$payment = new AtolOnline\Entities\Payment(
|
|
||||||
AtolOnline\Constants\PaymentTypes::CASH, // тип оплаты
|
|
||||||
1234.56 // сумма оплаты в рублях
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2 способ - через сеттер
|
|
||||||
$payment = (new AtolOnline\Entities\Payment())
|
|
||||||
->setType(AtolOnline\Constants\PaymentTypes::CASH) // тип оплаты
|
|
||||||
->setSum(1234.56); // сумма оплаты в рублях
|
|
||||||
```
|
|
||||||
|
|
||||||
Получить установленную сумму оплаты в рублях можно через геттер `getSum()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
var_dump($payment->getSum());
|
|
||||||
```
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительным приведением к `string`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $payment;
|
|
||||||
$json_string = (string)$payment;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $payment->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
<a name="array"></a>
|
|
||||||
## Массив объектов оплат
|
|
||||||
|
|
||||||
> Максимальное количество объектов в массиве - 10.
|
|
||||||
|
|
||||||
Массив инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$payment_array = new AtolOnline\Entities\PaymentArray();
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы задать содержимое массива, используйте метод `set()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use AtolOnline\{Constants\PaymentTypes, Entities\Payment};
|
|
||||||
|
|
||||||
$payment_array->set([
|
|
||||||
new Payment(PaymentTypes::ELECTRON, 123),
|
|
||||||
new Payment(PaymentTypes::ELECTRON, 53.2),
|
|
||||||
new Payment(PaymentTypes::ELECTRON, 23.99),
|
|
||||||
new Payment(PaymentTypes::ELECTRON, 11.43)
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
Очистить его можно передачей в сеттер пустого массива:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$payment_array->set([]);
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы добавить объект к существующим элементам массива, используйте метод `add()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use AtolOnline\{Constants\PaymentTypes, Entities\Payment};
|
|
||||||
|
|
||||||
$payment = new Payment(PaymentTypes::PRE_PAID, 20);
|
|
||||||
$payment_array->add($payment);
|
|
||||||
```
|
|
||||||
|
|
||||||
Методы `set()` и `add()` проверяют количество элементов в массиве перед его обновлением.
|
|
||||||
Выбрасывают исключение `AtolTooManyPaymentsException` (если в массиве уже максимальное количество объектов).
|
|
||||||
|
|
||||||
Чтобы получить содержимое массива, используйте метод `get()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$payment_array->get();
|
|
||||||
```
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительным приведением к `string`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $payment_array;
|
|
||||||
$json_string = (string)$payment_array;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $payment_array->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
@@ -1,26 +1,42 @@
|
|||||||
# Документация к библиотеке
|
# Документация к библиотеке
|
||||||
|
|
||||||
|
<a id="toc"></a>
|
||||||
|
|
||||||
|
## Содержание
|
||||||
|
|
||||||
|
* [Общий алгоритм](#getstarted)
|
||||||
|
* [Сущность](entity.md)
|
||||||
|
* [Коллекция сущностей](collection.md)
|
||||||
|
* [Мониторинг ККТ](monitoring.md)
|
||||||
|
* [Фискализация документа](fiscalizing.md)
|
||||||
|
* [Обработка ответа API](response.md)
|
||||||
|
|
||||||
|
Если вы нашли опечатку или какое-то несоответствие — делайте pull-request.
|
||||||
|
|
||||||
|
<a id="getstarted"></a>
|
||||||
|
|
||||||
## Общий алгоритм
|
## Общий алгоритм
|
||||||
|
|
||||||
1. Задать настройки ККТ
|
1. Создать документ `AtolOnline\Entities\Receipt` или `AtolOnline\Entities\Correction`, добавив в него все необходимые
|
||||||
2. Собрать данные о покупателе
|
данные
|
||||||
3. Собрать данные о продавце
|
2. Отправить документ на регистрацию:
|
||||||
4. Собрать данные о предметах расчёта (товары, услуги и пр.)
|
2.1. *Необязательно:* при отправке задать `callback_url`, на который АТОЛ отправит HTTP POST о состоянии документа;
|
||||||
5. Создать документ, добавив в него покупателя, продавца и предметы расчёта
|
2.2. *Необязательно:* при отправке задать `external_id`, чтобы присвоить свой уникальный идентификатор документа;
|
||||||
6. Отправить документ на регистрацию:
|
3. Запомнить `uuid` из пришедшего ответа, поскольку он пригодится для последующей проверки статуса фискализации.
|
||||||
6.1. *Необязательно:* задать `callback_url`, на который АТОЛ отправит HTTP POST о состоянии документа.
|
> Если с документом был передан `callback_url`, то ответ придёт на этот самый URL.
|
||||||
7. Запомнить `uuid` из пришедшего ответа, поскольку он пригодится для последующей проверки статуса фискализации.
|
> Он должен быть обработан вашим сервисом в соответствии с бизнес-процессом.
|
||||||
> Если с документом был передан `callback_url`, то ответ придёт на этот самый URL.
|
|
||||||
Если с документом **НЕ** был передан `callback_url` **либо** callback от АТОЛа не пришёл в течение 300 секунд (5 минут), нужно запрашивать вручную по `uuid`, пришедшему от АТОЛа в ответ на регистрацию документа.
|
> Если с документом **не был** передан `callback_url` **либо** callback от АТОЛа не пришёл в течение 300 секунд
|
||||||
8. Проверить состояние документа:
|
> (5 минут), нужно запрашивать вручную по `uuid`, пришедшему от АТОЛа в ответ на регистрацию документа.
|
||||||
8.1. взять `uuid` ответа, полученного на запрос фискализации;
|
4. Проверить состояние документа:
|
||||||
8.2. отправить его в запросе состояния документа.
|
4.1. взять `uuid` ответа, полученного на запрос фискализации;
|
||||||
|
4.2. отправить его в запросе состояния документа.
|
||||||
> Данные о документе можно получить только в течение 32 суток после успешной фискализации.
|
> Данные о документе можно получить только в течение 32 суток после успешной фискализации.
|
||||||
|
|
||||||
В зависимости от специфики бизнеса, в документах можно/нужно передавать также и другую информацию. Подробности в
|
В зависимости от специфики бизнеса, в документах можно/нужно передавать разную информацию. Подробности в документации
|
||||||
документациях и исходниках.
|
АТОЛ Онлайн и исходниках библиотеки.
|
||||||
|
|
||||||
### Об отправке электронного чека покупателю
|
## Об отправке электронного чека покупателю
|
||||||
|
|
||||||
После успешной фискализации документа покупатель автоматически получит уведомление **от ОФД**, который используется в
|
После успешной фискализации документа покупатель автоматически получит уведомление **от ОФД**, который используется в
|
||||||
связке с вашей ККТ:
|
связке с вашей ККТ:
|
||||||
@@ -31,19 +47,3 @@
|
|||||||
* если на стороне ОФД необходима и подключена услуга СМС-информирования (уточняйте подробности о своего ОФД).
|
* если на стороне ОФД необходима и подключена услуга СМС-информирования (уточняйте подробности о своего ОФД).
|
||||||
|
|
||||||
> Если заданы email и телефон, то ОФД отдаёт приоритет email.
|
> Если заданы email и телефон, то ОФД отдаёт приоритет email.
|
||||||
|
|
||||||
## Подготовка документа
|
|
||||||
|
|
||||||
1. [Работа с клиентами (покупателями)](client.md)
|
|
||||||
2. [Работа с компанией (продавцом)](company.md)
|
|
||||||
3. [Работа с оплатами](payments.md)
|
|
||||||
4. [Работа со ставками НДС](vats.md)
|
|
||||||
5. [Работа с предметами расчёта](items.md)
|
|
||||||
6. [Работа с данными коррекции](correction_info.md)
|
|
||||||
7. [Работа с документами](documents.md)
|
|
||||||
8. [Работа с ККТ](kkt.md)
|
|
||||||
9. [Мониторинг ККТ](monitoring.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Если вы нашли опечатку или какое-то несоответствие — делайте pull-request.
|
|
||||||
|
|||||||
57
docs/response.md
Normal file
57
docs/response.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Обработка ответа API
|
||||||
|
|
||||||
|
[Вернуться к содержанию](readme.md#toc)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Объект класса `AtolOnline\Api\AtolResponse` возвращается всеми методами, которые обращаются к АТОЛ Онлайн API.
|
||||||
|
|
||||||
|
Поскольку классы `AtolOnline\Api\Fiscalizer` и `AtolOnline\Api\KktMonitor` наследуются от
|
||||||
|
абстрактного `AtolOnline\Api\AtolClient`, они оба предоставляют метод `getLastReponse()` для возврата последнего
|
||||||
|
полученного ответа от API.
|
||||||
|
|
||||||
|
Таким образом, а общем случае необязательно сразу сохранять ответ в переменную:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$response = $kkt->sell($receipt);
|
||||||
|
```
|
||||||
|
|
||||||
|
Достаточно обратиться к нему позднее:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$kkt->sell($receipt);
|
||||||
|
// ...
|
||||||
|
$response = $kkt->getLastResponse();
|
||||||
|
```
|
||||||
|
|
||||||
|
Однако, при сложной логике и многократных запросах следует пользоваться этим с умом и осторожностью.
|
||||||
|
|
||||||
|
Объект `AtolResponse` содержит в себе HTTP-код ответа, массив заголовков и JSON-декодированные данные тела ответа.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$headers = $response->getHeaders(); // вернёт заголовки
|
||||||
|
$code = $response->getCode(); // вернёт код ответа
|
||||||
|
$body = $response->getContent(); // вернёт JSON-декодированный объект тела ответа
|
||||||
|
```
|
||||||
|
|
||||||
|
Обращаться к полям тела ответа можно опуская вызов метода `getContent()`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// вернёт значение поля uuid
|
||||||
|
$uuid = $response->getContent()->uuid;
|
||||||
|
$uuid = $response->uuid;
|
||||||
|
|
||||||
|
// вернёт текст ошибки
|
||||||
|
$err_text = $response->getContent()->error->text;
|
||||||
|
$err_text = $response->error->text;
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверка успешности операции доступна через метод `isSuccessful()`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$response->isSuccessful(); // вернёт true, если ошибок нет
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[Вернуться к содержанию](readme.md#toc)
|
||||||
128
docs/vats.md
128
docs/vats.md
@@ -1,128 +0,0 @@
|
|||||||
# Работа со ставками НДС
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Один объект
|
|
||||||
|
|
||||||
Объект ставки НДС инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use AtolOnline\Entities\Vat;
|
|
||||||
use AtolOnline\Enums\VatTypes;
|
|
||||||
|
|
||||||
$vat = new Vat(
|
|
||||||
VatTypes::VAT10, // тип ставки
|
|
||||||
123.45 // сумма в рублях, от которой считать ставку
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
Для типа и суммы имеются отдельные сеттеры:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$vat->setType(VatTypes::VAT20)
|
|
||||||
->setSum(100.15); // 123.45 заменится на 100.15
|
|
||||||
```
|
|
||||||
|
|
||||||
Общую сумму, из которой расчитывается размер налога, можно увеличить, используя метод `addSum()`. Указанная в рублях
|
|
||||||
сумма увеличится на указанные рубли. Для уменьшения суммы следует передать отрицательное число.
|
|
||||||
|
|
||||||
```php
|
|
||||||
$vat->addSum(40) // 100.15 + 40 = 140.15р
|
|
||||||
->addSum(-15); // 140.15 - 15 = 125.15р
|
|
||||||
```
|
|
||||||
|
|
||||||
Получить установленную сумму можно через геттер `getSum()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$vat->getSum(); // 125.15р
|
|
||||||
```
|
|
||||||
|
|
||||||
Размер налога по ставке высчитывается из этой общей суммы. Не смотря на то, что геттер и сеттер работают с рублями, **
|
|
||||||
расчёты производятся в копейках**. Сделать это можно через `getCalculated()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$vat->getCalculated();
|
|
||||||
// для примера выше это 20% от 125.15р = 25.03р
|
|
||||||
```
|
|
||||||
|
|
||||||
Разберём комплексный пример изменения типа ставки и расчётной суммы:
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительно:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $vat;
|
|
||||||
$json_string = (string)$vat;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $vat->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
<a name="array"></a>
|
|
||||||
## Массив объектов ставок НДС
|
|
||||||
|
|
||||||
> Максимальное количество в массиве - 6.
|
|
||||||
|
|
||||||
Массив инициализируется следующим образом:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$vat_array = new AtolOnline\Entities\VatArray();
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы задать содержимое массива, используйте метод `set()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use AtolOnline\{Constants\VatTypes, Entities\Vat};
|
|
||||||
|
|
||||||
$vat_array->set([
|
|
||||||
new Vat(VatTypes::VAT10, 123),
|
|
||||||
new Vat(VatTypes::VAT110, 53.2),
|
|
||||||
new Vat(VatTypes::VAT20, 23.99),
|
|
||||||
new Vat(VatTypes::VAT120, 11.43)
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
Очистить его можно передачей в сеттер пустого массива:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$vat_array->set([]);
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы добавить объект к существующим элементам массива, используйте метод `add()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use AtolOnline\{Constants\VatTypes, Entities\Vat};
|
|
||||||
|
|
||||||
$vat = new Vat(VatTypes::VAT20, 20);
|
|
||||||
$vat_array->add($vat);
|
|
||||||
```
|
|
||||||
|
|
||||||
Методы `set()` и `add()` проверяют количество элементов в массиве перед его обновлением.
|
|
||||||
Выбрасывают исключение `AtolTooManyVatsException` (если в массиве уже максимальное количество объектов).
|
|
||||||
|
|
||||||
Чтобы получить содержимое массива, используйте метод `get()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$vat_array->get();
|
|
||||||
```
|
|
||||||
|
|
||||||
Объект класса приводится к JSON-строке автоматически или принудительным приведением к `string`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
echo $vat_array;
|
|
||||||
$json_string = (string)$vat_array;
|
|
||||||
```
|
|
||||||
|
|
||||||
Чтобы получить те же данные в виде массива, нужно вызвать метод `jsonSerialize()`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$json_array = $vat_array->jsonSerialize();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[Вернуться к содержанию](readme.md)
|
|
||||||
13
phpunit.xml
13
phpunit.xml
@@ -12,8 +12,17 @@
|
|||||||
bootstrap="vendor/autoload.php"
|
bootstrap="vendor/autoload.php"
|
||||||
colors="true">
|
colors="true">
|
||||||
<testsuites>
|
<testsuites>
|
||||||
<testsuite name="All">
|
<testsuite name="Helpers">
|
||||||
<directory suffix="Test.php">./tests</directory>
|
<file>tests/AtolOnline/Tests/HelpersTest.php</file>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite name="Entities">
|
||||||
|
<directory>tests/AtolOnline/Tests/Entities</directory>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite name="Collections">
|
||||||
|
<directory>tests/AtolOnline/Tests/Collections</directory>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite name="Api">
|
||||||
|
<directory>tests/AtolOnline/Tests/Api</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
|
|||||||
@@ -11,21 +11,34 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Api;
|
namespace AtolOnline\Api;
|
||||||
|
|
||||||
use AtolOnline\{
|
use AtolOnline\Constants\Constraints;
|
||||||
Constants\Constraints,
|
use AtolOnline\Exceptions\{
|
||||||
Exceptions\AuthFailedException,
|
AuthFailedException,
|
||||||
Exceptions\EmptyLoginException,
|
EmptyLoginException,
|
||||||
Exceptions\EmptyPasswordException,
|
EmptyPasswordException,
|
||||||
Exceptions\TooLongLoginException,
|
TooLongLoginException,
|
||||||
Exceptions\TooLongPasswordException};
|
TooLongPasswordException};
|
||||||
use GuzzleHttp\Client;
|
use AtolOnline\TestEnvParams;
|
||||||
use GuzzleHttp\Exception\GuzzleException;
|
use GuzzleHttp\{
|
||||||
|
Client,
|
||||||
|
Exception\GuzzleException};
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс для подключения АТОЛ Онлайн API
|
* Класс для подключения АТОЛ Онлайн API
|
||||||
*/
|
*/
|
||||||
abstract class AtolClient
|
abstract class AtolClient
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var array Последний запрос к серверу АТОЛ
|
||||||
|
*/
|
||||||
|
protected array $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var AtolResponse|null Последний ответ сервера АТОЛ
|
||||||
|
*/
|
||||||
|
protected ?AtolResponse $response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool Флаг тестового режима
|
* @var bool Флаг тестового режима
|
||||||
*/
|
*/
|
||||||
@@ -51,11 +64,6 @@ abstract class AtolClient
|
|||||||
*/
|
*/
|
||||||
private ?string $token = null;
|
private ?string $token = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var KktResponse|null Последний ответ сервера АТОЛ
|
|
||||||
*/
|
|
||||||
private ?KktResponse $response;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конструктор
|
* Конструктор
|
||||||
*
|
*
|
||||||
@@ -75,14 +83,36 @@ abstract class AtolClient
|
|||||||
?string $password = null,
|
?string $password = null,
|
||||||
array $config = []
|
array $config = []
|
||||||
) {
|
) {
|
||||||
$this->http = new Client(array_merge($config, [
|
$this->http = new Client(
|
||||||
'http_errors' => $config['http_errors'] ?? false,
|
array_merge($config, [
|
||||||
]));
|
'http_errors' => $config['http_errors'] ?? false,
|
||||||
|
])
|
||||||
|
);
|
||||||
$this->setTestMode($test_mode);
|
$this->setTestMode($test_mode);
|
||||||
!is_null($login) && $this->setLogin($login);
|
!is_null($login) && $this->setLogin($login);
|
||||||
!is_null($password) && $this->setPassword($password);
|
!is_null($password) && $this->setPassword($password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает последний запрос к серверу
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getLastRequest(): array
|
||||||
|
{
|
||||||
|
return $this->request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает последний ответ сервера
|
||||||
|
*
|
||||||
|
* @return AtolResponse|null
|
||||||
|
*/
|
||||||
|
public function getLastResponse(): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает установленный флаг тестового режима
|
* Возвращает установленный флаг тестового режима
|
||||||
*
|
*
|
||||||
@@ -127,24 +157,17 @@ abstract class AtolClient
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает последний ответ сервера
|
|
||||||
*
|
|
||||||
* @return KktResponse|null
|
|
||||||
*/
|
|
||||||
public function getResponse(): ?KktResponse
|
|
||||||
{
|
|
||||||
return $this->response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает логин доступа к API
|
* Возвращает логин доступа к API
|
||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function getLogin(): ?string
|
public function getLogin(): ?string
|
||||||
{
|
{
|
||||||
return $this->login;
|
return $this->isTestMode()
|
||||||
|
? TestEnvParams::FFD105()['login']
|
||||||
|
: $this->login;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -172,9 +195,12 @@ abstract class AtolClient
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function getPassword(): ?string
|
public function getPassword(): ?string
|
||||||
{
|
{
|
||||||
return $this->password;
|
return $this->isTestMode()
|
||||||
|
? TestEnvParams::FFD105()['password']
|
||||||
|
: $this->password;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,6 +227,7 @@ abstract class AtolClient
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
private function getHeaders(): array
|
private function getHeaders(): array
|
||||||
{
|
{
|
||||||
$headers['Content-type'] = 'application/json; charset=utf-8';
|
$headers['Content-type'] = 'application/json; charset=utf-8';
|
||||||
@@ -236,7 +263,7 @@ abstract class AtolClient
|
|||||||
'login' => $this->getLogin() ?? throw new EmptyLoginException(),
|
'login' => $this->getLogin() ?? throw new EmptyLoginException(),
|
||||||
'pass' => $this->getPassword() ?? throw new EmptyPasswordException(),
|
'pass' => $this->getPassword() ?? throw new EmptyPasswordException(),
|
||||||
]);
|
]);
|
||||||
if (!$result->isValid() || !$result->getContent()->token) {
|
if (!$result->isSuccessful() || !$result->getContent()->token) {
|
||||||
throw new AuthFailedException($result);
|
throw new AuthFailedException($result);
|
||||||
}
|
}
|
||||||
return $result->getContent()?->token;
|
return $result->getContent()?->token;
|
||||||
@@ -249,7 +276,7 @@ abstract class AtolClient
|
|||||||
* @param string $url URL
|
* @param string $url URL
|
||||||
* @param array|null $data Данные для передачи
|
* @param array|null $data Данные для передачи
|
||||||
* @param array|null $options Параметры Guzzle
|
* @param array|null $options Параметры Guzzle
|
||||||
* @return KktResponse
|
* @return AtolResponse
|
||||||
* @throws GuzzleException
|
* @throws GuzzleException
|
||||||
* @see https://guzzle.readthedocs.io/en/latest/request-options.html
|
* @see https://guzzle.readthedocs.io/en/latest/request-options.html
|
||||||
*/
|
*/
|
||||||
@@ -258,39 +285,32 @@ abstract class AtolClient
|
|||||||
string $url,
|
string $url,
|
||||||
?array $data = null,
|
?array $data = null,
|
||||||
?array $options = null
|
?array $options = null
|
||||||
): KktResponse {
|
): AtolResponse {
|
||||||
$http_method = strtoupper(trim($http_method));
|
$http_method = strtoupper(trim($http_method));
|
||||||
$options['headers'] = array_merge($this->getHeaders(), $options['headers'] ?? []);
|
$options['headers'] = array_merge($this->getHeaders(), $options['headers'] ?? []);
|
||||||
if ($http_method != 'GET') {
|
$http_method != 'GET' && $options['json'] = $data;
|
||||||
$options['json'] = $data;
|
$this->request = array_merge([
|
||||||
}
|
'method' => $http_method,
|
||||||
|
'url' => $url,
|
||||||
|
], $options);
|
||||||
$response = $this->http->request($http_method, $url, $options);
|
$response = $this->http->request($http_method, $url, $options);
|
||||||
return $this->response = new KktResponse($response);
|
return $this->response = new AtolResponse($response);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Выполняет авторизацию на сервере АТОЛ
|
* Выполняет авторизацию на сервере АТОЛ
|
||||||
|
* Авторизация выполнится только если неизвестен токен
|
||||||
*
|
*
|
||||||
* Авторизация выолнится только если неизвестен токен
|
|
||||||
*
|
|
||||||
* @param string|null $login
|
|
||||||
* @param string|null $password
|
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws AuthFailedException
|
* @throws AuthFailedException
|
||||||
* @throws TooLongLoginException
|
|
||||||
* @throws EmptyLoginException
|
* @throws EmptyLoginException
|
||||||
* @throws EmptyPasswordException
|
* @throws EmptyPasswordException
|
||||||
* @throws TooLongPasswordException
|
|
||||||
* @throws GuzzleException
|
* @throws GuzzleException
|
||||||
*/
|
*/
|
||||||
public function auth(?string $login = null, ?string $password = null): bool
|
public function auth(): bool
|
||||||
{
|
{
|
||||||
if (empty($this->getToken())) {
|
if (empty($this->getToken()) && $token = $this->doAuth()) {
|
||||||
$login && $this->setLogin($login);
|
$this->setToken($token);
|
||||||
$password && $this->setPassword($password);
|
|
||||||
if ($token = $this->doAuth()) {
|
|
||||||
$this->setToken($token);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return !empty($this->getToken());
|
return !empty($this->getToken());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,17 @@
|
|||||||
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** @noinspection PhpMultipleClassDeclarationsInspection */
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types = 1);
|
||||||
|
|
||||||
namespace AtolOnline\Api;
|
namespace AtolOnline\Api;
|
||||||
|
|
||||||
|
use JetBrains\PhpStorm\{
|
||||||
|
ArrayShape,
|
||||||
|
Pure};
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use stdClass;
|
|
||||||
use Stringable;
|
use Stringable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,7 +26,7 @@ use Stringable;
|
|||||||
* @property mixed $error
|
* @property mixed $error
|
||||||
* @package AtolOnline\Api
|
* @package AtolOnline\Api
|
||||||
*/
|
*/
|
||||||
class KktResponse implements JsonSerializable, Stringable
|
final class AtolResponse implements JsonSerializable, Stringable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var int Код ответа сервера
|
* @var int Код ответа сервера
|
||||||
@@ -30,10 +34,10 @@ class KktResponse implements JsonSerializable, Stringable
|
|||||||
protected int $code;
|
protected int $code;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var stdClass|array|null Содержимое ответа сервера
|
* @var object|array|null Содержимое ответа сервера
|
||||||
*/
|
*/
|
||||||
protected stdClass|array|null $content;
|
protected object|array|null $content;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array Заголовки ответа
|
* @var array Заголовки ответа
|
||||||
*/
|
*/
|
||||||
@@ -50,7 +54,7 @@ class KktResponse implements JsonSerializable, Stringable
|
|||||||
$this->headers = $response->getHeaders();
|
$this->headers = $response->getHeaders();
|
||||||
$this->content = json_decode((string)$response->getBody());
|
$this->content = json_decode((string)$response->getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает заголовки ответа
|
* Возвращает заголовки ответа
|
||||||
*
|
*
|
||||||
@@ -60,18 +64,19 @@ class KktResponse implements JsonSerializable, Stringable
|
|||||||
{
|
{
|
||||||
return $this->headers;
|
return $this->headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает запрошенный параметр из декодированного объекта результата
|
* Возвращает запрошенный параметр из декодированного объекта результата
|
||||||
*
|
*
|
||||||
* @param $name
|
* @param $name
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __get($name): mixed
|
public function __get($name): mixed
|
||||||
{
|
{
|
||||||
return $this->getContent()?->$name;
|
return $this->getContent()?->$name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает код ответа
|
* Возвращает код ответа
|
||||||
*
|
*
|
||||||
@@ -81,7 +86,7 @@ class KktResponse implements JsonSerializable, Stringable
|
|||||||
{
|
{
|
||||||
return $this->code;
|
return $this->code;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает объект результата запроса
|
* Возвращает объект результата запроса
|
||||||
*
|
*
|
||||||
@@ -91,20 +96,21 @@ class KktResponse implements JsonSerializable, Stringable
|
|||||||
{
|
{
|
||||||
return $this->content;
|
return $this->content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Проверяет успешность запроса по соержимому результата
|
* Проверяет успешность запроса по соержимому результата
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid(): bool
|
#[Pure]
|
||||||
|
public function isSuccessful(): bool
|
||||||
{
|
{
|
||||||
return !empty($this->getCode())
|
return !empty($this->getCode())
|
||||||
&& !empty($this->getContent())
|
&& !empty($this->getContent())
|
||||||
&& empty($this->getContent()->error)
|
&& empty($this->getContent()->error)
|
||||||
&& $this->getCode() < 400;
|
&& $this->getCode() < 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает текстовое представление
|
* Возвращает текстовое представление
|
||||||
*/
|
*/
|
||||||
@@ -112,10 +118,16 @@ class KktResponse implements JsonSerializable, Stringable
|
|||||||
{
|
{
|
||||||
return json_encode($this->jsonSerialize(), JSON_UNESCAPED_UNICODE);
|
return json_encode($this->jsonSerialize(), JSON_UNESCAPED_UNICODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
#[ArrayShape([
|
||||||
|
'code' => 'int',
|
||||||
|
'headers' => 'array|\string[][]',
|
||||||
|
'body' => 'mixed',
|
||||||
|
]
|
||||||
|
)]
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -124,4 +136,4 @@ class KktResponse implements JsonSerializable, Stringable
|
|||||||
'body' => $this->content,
|
'body' => $this->content,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
378
src/Api/Fiscalizer.php
Normal file
378
src/Api/Fiscalizer.php
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
<?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\Api;
|
||||||
|
|
||||||
|
use AtolOnline\{
|
||||||
|
Constants\Constraints,
|
||||||
|
TestEnvParams};
|
||||||
|
use AtolOnline\Entities\{
|
||||||
|
Correction,
|
||||||
|
Receipt};
|
||||||
|
use AtolOnline\Exceptions\{
|
||||||
|
AuthFailedException,
|
||||||
|
EmptyGroupException,
|
||||||
|
EmptyLoginException,
|
||||||
|
EmptyPasswordException,
|
||||||
|
InvalidCallbackUrlException,
|
||||||
|
InvalidEntityInCollectionException,
|
||||||
|
InvalidInnLengthException,
|
||||||
|
InvalidPaymentAddressException,
|
||||||
|
InvalidUuidException,
|
||||||
|
TooLongCallbackUrlException,
|
||||||
|
TooLongLoginException,
|
||||||
|
TooLongPasswordException,
|
||||||
|
TooLongPaymentAddressException};
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс фискализатора для регистрации документов на ККТ
|
||||||
|
*/
|
||||||
|
final class Fiscalizer extends AtolClient
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string|null Группа ККТ
|
||||||
|
*/
|
||||||
|
private ?string $group = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null URL для приёма POST-запроса от API АТОЛ с результатом регистрации документа
|
||||||
|
*/
|
||||||
|
private ?string $callback_url = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param bool $test_mode
|
||||||
|
* @param string|null $login
|
||||||
|
* @param string|null $password
|
||||||
|
* @param string|null $group
|
||||||
|
* @param array $config
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws TooLongLoginException
|
||||||
|
* @throws TooLongPasswordException
|
||||||
|
* @throws EmptyGroupException
|
||||||
|
* @see https://guzzle.readthedocs.io/en/latest/request-options.html
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
bool $test_mode = true,
|
||||||
|
?string $login = null,
|
||||||
|
?string $password = null,
|
||||||
|
?string $group = null,
|
||||||
|
array $config = []
|
||||||
|
) {
|
||||||
|
parent::__construct($test_mode, $login, $password, $config);
|
||||||
|
!is_null($group) && $this->setGroup($group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает группу доступа к ККТ в соответствии с флагом тестового режима
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
#[Pure]
|
||||||
|
public function getGroup(): ?string
|
||||||
|
{
|
||||||
|
return $this->isTestMode()
|
||||||
|
? TestEnvParams::FFD105()['group']
|
||||||
|
: $this->group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает группу доступа к ККТ
|
||||||
|
*
|
||||||
|
* @param string $group
|
||||||
|
* @return $this
|
||||||
|
* @throws EmptyGroupException
|
||||||
|
*/
|
||||||
|
public function setGroup(string $group): self
|
||||||
|
{
|
||||||
|
// критерии к длине строки не описаны ни в схеме, ни в документации
|
||||||
|
empty($group = trim($group)) && throw new EmptyGroupException();
|
||||||
|
$this->group = $group;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает URL для приёма колбеков
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCallbackUrl(): ?string
|
||||||
|
{
|
||||||
|
return $this->callback_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает URL для приёма колбеков
|
||||||
|
*
|
||||||
|
* @param string|null $url
|
||||||
|
* @return $this
|
||||||
|
* @throws TooLongCallbackUrlException
|
||||||
|
* @throws InvalidCallbackUrlException
|
||||||
|
*/
|
||||||
|
public function setCallbackUrl(?string $url = null): self
|
||||||
|
{
|
||||||
|
$url = trim((string)$url);
|
||||||
|
if (mb_strlen($url) > Constraints::MAX_LENGTH_CALLBACK_URL) {
|
||||||
|
throw new TooLongCallbackUrlException($url);
|
||||||
|
} elseif (!empty($url) && !preg_match(Constraints::PATTERN_CALLBACK_URL, $url)) {
|
||||||
|
throw new InvalidCallbackUrlException();
|
||||||
|
}
|
||||||
|
$this->callback_url = $url ?: null;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует документ прихода
|
||||||
|
*
|
||||||
|
* @param Receipt $receipt Объект документа
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function sell(Receipt $receipt, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $this->registerDocument('sell', $receipt, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует документ возврата прихода
|
||||||
|
*
|
||||||
|
* @param Receipt $receipt Объект документа
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function sellRefund(Receipt $receipt, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $this->registerDocument('sell_refund', $receipt, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует документ коррекции прихода
|
||||||
|
*
|
||||||
|
* @param Correction $correction Объект документа
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function sellCorrect(Correction $correction, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $this->registerDocument('sell_correction', $correction, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует документ расхода
|
||||||
|
*
|
||||||
|
* @param Receipt $receipt Объект документа
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function buy(Receipt $receipt, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $this->registerDocument('buy', $receipt, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует документ возврата расхода
|
||||||
|
*
|
||||||
|
* @param Receipt $receipt Объект документа
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function buyRefund(Receipt $receipt, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $this->registerDocument('buy_refund', $receipt, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует документ коррекции расхода
|
||||||
|
*
|
||||||
|
* @param Correction $correction Объект документа
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function buyCorrect(Correction $correction, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $this->registerDocument('buy_correction', $correction, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет статус чека на ККТ один раз
|
||||||
|
*
|
||||||
|
* @param string $uuid UUID регистрации
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidUuidException
|
||||||
|
*/
|
||||||
|
public function getDocumentStatus(string $uuid): ?AtolResponse
|
||||||
|
{
|
||||||
|
!Uuid::isValid($uuid = trim($uuid)) && throw new InvalidUuidException($uuid);
|
||||||
|
return $this->auth()
|
||||||
|
? $this->sendRequest('GET', $this->getFullUrl('report/' . $uuid))
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет статус чека на ККТ нужное количество раз с указанным интервалом.
|
||||||
|
* Вернёт результат как только при очередной проверке сменится статус регистрации документа.
|
||||||
|
*
|
||||||
|
* @param string $uuid UUID регистрации
|
||||||
|
* @param int $retry_count Количество попыток
|
||||||
|
* @param int $timeout Таймаут в секундах между попытками
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidUuidException
|
||||||
|
*/
|
||||||
|
public function pollDocumentStatus(string $uuid, int $retry_count = 5, int $timeout = 1): ?AtolResponse
|
||||||
|
{
|
||||||
|
$try = 0;
|
||||||
|
do {
|
||||||
|
$response = $this->getDocumentStatus($uuid);
|
||||||
|
if ($response->isSuccessful() && $response->getContent()->status == 'done') {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
sleep($timeout);
|
||||||
|
}
|
||||||
|
++$try;
|
||||||
|
} while ($try < $retry_count);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Отправляет документ на регистрацию
|
||||||
|
*
|
||||||
|
* @param string $api_method Метод API
|
||||||
|
* @param Receipt|Correction $document Документ
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
protected function registerDocument(
|
||||||
|
string $api_method,
|
||||||
|
Receipt|Correction $document,
|
||||||
|
?string $external_id = null
|
||||||
|
): ?AtolResponse {
|
||||||
|
$this->isTestMode() && $document->getCompany()
|
||||||
|
->setInn(TestEnvParams::FFD105()['inn'])
|
||||||
|
->setPaymentAddress(TestEnvParams::FFD105()['payment_address']);
|
||||||
|
$this->isTestMode() && $document instanceof Receipt
|
||||||
|
&& $document->getClient()->setInn(TestEnvParams::FFD105()['inn']);
|
||||||
|
$this->getCallbackUrl() && $data['service'] = ['callback_url' => $this->getCallbackUrl()];
|
||||||
|
return $this->auth()
|
||||||
|
? $this->sendRequest(
|
||||||
|
'POST',
|
||||||
|
$this->getFullUrl($api_method),
|
||||||
|
array_merge($data ?? [], [
|
||||||
|
'timestamp' => date('d.m.Y H:i:s'),
|
||||||
|
'external_id' => $external_id ?: Uuid::uuid4()->toString(),
|
||||||
|
$document::DOC_TYPE => $document->jsonSerialize(),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
#[Pure]
|
||||||
|
protected function getAuthEndpoint(): string
|
||||||
|
{
|
||||||
|
return $this->isTestMode()
|
||||||
|
? 'https://testonline.atol.ru/possystem/v4/getToken'
|
||||||
|
: 'https://online.atol.ru/possystem/v4/getToken';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
#[Pure]
|
||||||
|
protected function getMainEndpoint(): string
|
||||||
|
{
|
||||||
|
return $this->isTestMode()
|
||||||
|
? 'https://testonline.atol.ru/possystem/v4/'
|
||||||
|
: 'https://online.atol.ru/possystem/v4/';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает полный URL метода API
|
||||||
|
*
|
||||||
|
* @param string $api_method
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
#[Pure]
|
||||||
|
protected function getFullUrl(string $api_method): string
|
||||||
|
{
|
||||||
|
return $this->getMainEndpoint() . $this->getGroup() . '/' . trim($api_method);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,378 +0,0 @@
|
|||||||
<?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\Api;
|
|
||||||
|
|
||||||
use AtolOnline\{
|
|
||||||
Constants\Constraints,
|
|
||||||
Entities\Company,
|
|
||||||
Entities\Document,
|
|
||||||
Exceptions\AuthFailedException,
|
|
||||||
Exceptions\EmptyCorrectionInfoException,
|
|
||||||
Exceptions\EmptyLoginException,
|
|
||||||
Exceptions\EmptyPasswordException,
|
|
||||||
Exceptions\InvalidCallbackUrlException,
|
|
||||||
Exceptions\InvalidDocumentTypeException,
|
|
||||||
Exceptions\InvalidInnLengthException,
|
|
||||||
Exceptions\InvalidUuidException,
|
|
||||||
Exceptions\TooLongCallbackUrlException,
|
|
||||||
Exceptions\TooLongLoginException,
|
|
||||||
Exceptions\TooLongPasswordException,
|
|
||||||
Exceptions\TooLongPaymentAddressException,
|
|
||||||
Exceptions\TooManyItemsException,
|
|
||||||
Exceptions\TooManyVatsException,
|
|
||||||
TestEnvParams
|
|
||||||
};
|
|
||||||
use Exception;
|
|
||||||
use GuzzleHttp\Exception\GuzzleException;
|
|
||||||
use Ramsey\Uuid\Uuid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Класс для регистрации документов на ККТ
|
|
||||||
*/
|
|
||||||
class KktFiscalizer extends AtolClient
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string|null Группа ККТ
|
|
||||||
*/
|
|
||||||
private ?string $group = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null URL для приёма POST-запроса от API АТОЛ с результатом регистрации документа
|
|
||||||
*/
|
|
||||||
private ?string $callback_url = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Конструктор
|
|
||||||
*
|
|
||||||
* @param bool $test_mode
|
|
||||||
* @param string|null $login
|
|
||||||
* @param string|null $password
|
|
||||||
* @param string|null $group
|
|
||||||
* @param array $config
|
|
||||||
* @throws EmptyLoginException
|
|
||||||
* @throws EmptyPasswordException
|
|
||||||
* @throws TooLongLoginException
|
|
||||||
* @throws TooLongPasswordException
|
|
||||||
* @see https://guzzle.readthedocs.io/en/latest/request-options.html
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
bool $test_mode = true,
|
|
||||||
?string $login = null,
|
|
||||||
?string $password = null,
|
|
||||||
?string $group = null,
|
|
||||||
array $config = []
|
|
||||||
) {
|
|
||||||
parent::__construct($test_mode, $login, $password, $config);
|
|
||||||
!is_null($group) && $this->setGroup($group);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает группу доступа к ККТ
|
|
||||||
*
|
|
||||||
* @param string $group
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setGroup(string $group): self
|
|
||||||
{
|
|
||||||
// критерии к длине строки не описаны ни в схеме, ни в документации
|
|
||||||
$this->group = $group;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает группу доступа к ККТ в соответствии с флагом тестового режима
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getGroup(): ?string
|
|
||||||
{
|
|
||||||
return $this->group;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает URL для приёма колбеков
|
|
||||||
*
|
|
||||||
* @param string $url
|
|
||||||
* @return $this
|
|
||||||
* @throws TooLongCallbackUrlException
|
|
||||||
* @throws InvalidCallbackUrlException
|
|
||||||
*/
|
|
||||||
public function setCallbackUrl(string $url): self
|
|
||||||
{
|
|
||||||
if (mb_strlen($url) > Constraints::MAX_LENGTH_CALLBACK_URL) {
|
|
||||||
throw new TooLongCallbackUrlException($url, Constraints::MAX_LENGTH_CALLBACK_URL);
|
|
||||||
} elseif (!preg_match(Constraints::PATTERN_CALLBACK_URL, $url)) {
|
|
||||||
throw new InvalidCallbackUrlException('Callback URL not matches with pattern');
|
|
||||||
}
|
|
||||||
$this->callback_url = $url;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает URL для приёма колбеков
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getCallbackUrl(): string
|
|
||||||
{
|
|
||||||
return $this->callback_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Регистрирует документ прихода
|
|
||||||
*
|
|
||||||
* @param Document $document Объект документа
|
|
||||||
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
|
|
||||||
* @return KktResponse
|
|
||||||
* @throws AuthFailedException
|
|
||||||
* @throws EmptyCorrectionInfoException
|
|
||||||
* @throws InvalidInnLengthException
|
|
||||||
* @throws TooLongPaymentAddressException
|
|
||||||
* @throws InvalidDocumentTypeException
|
|
||||||
* @throws GuzzleException
|
|
||||||
*/
|
|
||||||
public function sell(Document $document, ?string $external_id = null): KktResponse
|
|
||||||
{
|
|
||||||
if ($document->getCorrectionInfo()) {
|
|
||||||
throw new EmptyCorrectionInfoException('Некорректная операция над документом коррекции');
|
|
||||||
}
|
|
||||||
return $this->registerDocument('sell', 'receipt', $document, $external_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Регистрирует документ возврата прихода
|
|
||||||
*
|
|
||||||
* @param Document $document Объект документа
|
|
||||||
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
|
|
||||||
* @return KktResponse
|
|
||||||
* @throws AuthFailedException
|
|
||||||
* @throws EmptyCorrectionInfoException
|
|
||||||
* @throws InvalidInnLengthException
|
|
||||||
* @throws TooLongPaymentAddressException
|
|
||||||
* @throws TooManyVatsException
|
|
||||||
* @throws InvalidDocumentTypeException
|
|
||||||
* @throws GuzzleException
|
|
||||||
*/
|
|
||||||
public function sellRefund(Document $document, ?string $external_id = null): KktResponse
|
|
||||||
{
|
|
||||||
if ($document->getCorrectionInfo()) {
|
|
||||||
throw new EmptyCorrectionInfoException('Invalid operation on correction document');
|
|
||||||
}
|
|
||||||
return $this->registerDocument('sell_refund', 'receipt', $document->clearVats(), $external_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Регистрирует документ коррекции прихода
|
|
||||||
*
|
|
||||||
* @param Document $document Объект документа
|
|
||||||
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
|
|
||||||
* @return KktResponse
|
|
||||||
* @throws AuthFailedException
|
|
||||||
* @throws EmptyCorrectionInfoException
|
|
||||||
* @throws InvalidInnLengthException
|
|
||||||
* @throws TooLongPaymentAddressException
|
|
||||||
* @throws TooManyItemsException
|
|
||||||
* @throws InvalidDocumentTypeException
|
|
||||||
* @throws GuzzleException
|
|
||||||
*/
|
|
||||||
public function sellCorrection(Document $document, ?string $external_id = null): KktResponse
|
|
||||||
{
|
|
||||||
if (!$document->getCorrectionInfo()) {
|
|
||||||
throw new EmptyCorrectionInfoException();
|
|
||||||
}
|
|
||||||
$document->setClient(null)->setItems([]);
|
|
||||||
return $this->registerDocument('sell_correction', 'correction', $document, $external_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Регистрирует документ расхода
|
|
||||||
*
|
|
||||||
* @param Document $document
|
|
||||||
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
|
|
||||||
* @return KktResponse
|
|
||||||
* @throws AuthFailedException
|
|
||||||
* @throws EmptyCorrectionInfoException
|
|
||||||
* @throws InvalidInnLengthException
|
|
||||||
* @throws TooLongPaymentAddressException
|
|
||||||
* @throws InvalidDocumentTypeException
|
|
||||||
* @throws GuzzleException
|
|
||||||
*/
|
|
||||||
public function buy(Document $document, ?string $external_id = null): KktResponse
|
|
||||||
{
|
|
||||||
if ($document->getCorrectionInfo()) {
|
|
||||||
throw new EmptyCorrectionInfoException('Invalid operation on correction document');
|
|
||||||
}
|
|
||||||
return $this->registerDocument('buy', 'receipt', $document, $external_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Регистрирует документ возврата расхода
|
|
||||||
*
|
|
||||||
* @param Document $document
|
|
||||||
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
|
|
||||||
* @return KktResponse
|
|
||||||
* @throws AuthFailedException
|
|
||||||
* @throws EmptyCorrectionInfoException
|
|
||||||
* @throws InvalidInnLengthException
|
|
||||||
* @throws TooLongPaymentAddressException
|
|
||||||
* @throws TooManyVatsException
|
|
||||||
* @throws InvalidDocumentTypeException
|
|
||||||
* @throws GuzzleException
|
|
||||||
*/
|
|
||||||
public function buyRefund(Document $document, ?string $external_id = null): KktResponse
|
|
||||||
{
|
|
||||||
if ($document->getCorrectionInfo()) {
|
|
||||||
throw new EmptyCorrectionInfoException('Invalid operation on correction document');
|
|
||||||
}
|
|
||||||
return $this->registerDocument('buy_refund', 'receipt', $document->clearVats(), $external_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Регистрирует документ коррекции расхода
|
|
||||||
*
|
|
||||||
* @param Document $document
|
|
||||||
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
|
|
||||||
* @return KktResponse
|
|
||||||
* @throws AuthFailedException Ошибка авторизации
|
|
||||||
* @throws EmptyCorrectionInfoException В документе отсутствуют данные коррекции
|
|
||||||
* @throws InvalidInnLengthException Некорректная длтина ИНН
|
|
||||||
* @throws TooLongPaymentAddressException Слишком длинный адрес места расчётов
|
|
||||||
* @throws TooManyItemsException Слишком много предметов расчёта
|
|
||||||
* @throws InvalidDocumentTypeException Некорректный тип документа
|
|
||||||
* @throws GuzzleException
|
|
||||||
*/
|
|
||||||
public function buyCorrection(Document $document, ?string $external_id = null): KktResponse
|
|
||||||
{
|
|
||||||
if (!$document->getCorrectionInfo()) {
|
|
||||||
throw new EmptyCorrectionInfoException();
|
|
||||||
}
|
|
||||||
$document->setClient(null)->setItems([]);
|
|
||||||
return $this->registerDocument('buy_correction', 'correction', $document, $external_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Проверяет статус чека на ККТ один раз
|
|
||||||
*
|
|
||||||
* @param string $uuid UUID регистрации
|
|
||||||
* @return KktResponse
|
|
||||||
* @throws AuthFailedException
|
|
||||||
* @throws EmptyLoginException
|
|
||||||
* @throws EmptyPasswordException
|
|
||||||
* @throws GuzzleException
|
|
||||||
* @throws InvalidUuidException
|
|
||||||
* @throws TooLongLoginException
|
|
||||||
* @throws TooLongPasswordException
|
|
||||||
*/
|
|
||||||
public function getDocumentStatus(string $uuid): KktResponse
|
|
||||||
{
|
|
||||||
$uuid = trim($uuid);
|
|
||||||
if (!Uuid::isValid($uuid)) {
|
|
||||||
throw new InvalidUuidException($uuid);
|
|
||||||
}
|
|
||||||
$this->auth();
|
|
||||||
return $this->sendRequest('GET', 'report/' . $uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Проверяет статус чека на ККТ нужное количество раз с указанным интервалом.
|
|
||||||
* Вернёт результат как только при очередной проверке сменится статус регистрации документа.
|
|
||||||
*
|
|
||||||
* @param string $uuid UUID регистрации
|
|
||||||
* @param int $retry_count Количество попыток
|
|
||||||
* @param int $timeout Таймаут в секундах между попытками
|
|
||||||
* @return KktResponse
|
|
||||||
* @throws AuthFailedException
|
|
||||||
* @throws EmptyLoginException
|
|
||||||
* @throws EmptyPasswordException
|
|
||||||
* @throws GuzzleException
|
|
||||||
* @throws InvalidUuidException
|
|
||||||
* @throws TooLongLoginException
|
|
||||||
* @throws TooLongPasswordException
|
|
||||||
*/
|
|
||||||
public function pollDocumentStatus(string $uuid, int $retry_count = 5, int $timeout = 1): KktResponse
|
|
||||||
{
|
|
||||||
$try = 0;
|
|
||||||
do {
|
|
||||||
$response = $this->getDocumentStatus($uuid);
|
|
||||||
if ($response->isValid() && $response->getContent()->status == 'done') {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
sleep($timeout);
|
|
||||||
}
|
|
||||||
++$try;
|
|
||||||
} while ($try < $retry_count);
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Отправляет документ на регистрацию
|
|
||||||
*
|
|
||||||
* @param string $api_method Метод API
|
|
||||||
* @param string $type Тип документа: receipt, correction
|
|
||||||
* @param Document $document Объект документа
|
|
||||||
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
|
|
||||||
* @return KktResponse
|
|
||||||
* @throws AuthFailedException Ошибка авторизации
|
|
||||||
* @throws InvalidDocumentTypeException Некорректный тип документа
|
|
||||||
* @throws InvalidInnLengthException Некорректная длина ИНН
|
|
||||||
* @throws TooLongPaymentAddressException Слишком длинный адрес места расчётов
|
|
||||||
* @throws GuzzleException
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
protected function registerDocument(
|
|
||||||
string $api_method,
|
|
||||||
string $type,
|
|
||||||
Document $document,
|
|
||||||
?string $external_id = null
|
|
||||||
): KktResponse {
|
|
||||||
$type = trim($type);
|
|
||||||
if (!in_array($type, ['receipt', 'correction'])) {
|
|
||||||
throw new InvalidDocumentTypeException($type);
|
|
||||||
}
|
|
||||||
$this->auth();
|
|
||||||
if ($this->isTestMode()) {
|
|
||||||
$document->setCompany(new Company(
|
|
||||||
'test@example.com',
|
|
||||||
TestEnvParams::FFD105()['sno'],
|
|
||||||
TestEnvParams::FFD105()['inn'],
|
|
||||||
TestEnvParams::FFD105()['payment_address'],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
$data['timestamp'] = date('d.m.y H:i:s');
|
|
||||||
$data['external_id'] = $external_id ?: Uuid::uuid4()->toString();
|
|
||||||
$data[$type] = $document;
|
|
||||||
if ($this->getCallbackUrl()) {
|
|
||||||
$data['service'] = ['callback_url' => $this->getCallbackUrl()];
|
|
||||||
}
|
|
||||||
return $this->sendRequest('POST', trim($api_method), $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
protected function getAuthEndpoint(): string
|
|
||||||
{
|
|
||||||
return $this->isTestMode()
|
|
||||||
? 'https://testonline.atol.ru/possystem/v1/getToken'
|
|
||||||
: 'https://online.atol.ru/possystem/v1/getToken';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
protected function getMainEndpoint(): string
|
|
||||||
{
|
|
||||||
return $this->isTestMode()
|
|
||||||
? 'https://testonline.atol.ru/possystem/v4/'
|
|
||||||
: 'https://online.atol.ru/possystem/v4/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,21 +12,27 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Api;
|
namespace AtolOnline\Api;
|
||||||
|
|
||||||
use AtolOnline\Entities\Kkt;
|
use AtolOnline\Entities\Kkt;
|
||||||
use AtolOnline\Exceptions\EmptyMonitorDataException;
|
use AtolOnline\Exceptions\{
|
||||||
use AtolOnline\Exceptions\NotEnoughMonitorDataException;
|
AuthFailedException,
|
||||||
|
EmptyLoginException,
|
||||||
|
EmptyMonitorDataException,
|
||||||
|
EmptyPasswordException,
|
||||||
|
NotEnoughMonitorDataException};
|
||||||
use GuzzleHttp\Exception\GuzzleException;
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс для мониторинга ККТ
|
* Класс для мониторинга ККТ
|
||||||
*
|
*
|
||||||
* @see https://online.atol.ru/files/API_service_information.pdf Документация
|
* @see https://online.atol.ru/files/API_service_information.pdf Документация
|
||||||
*/
|
*/
|
||||||
class KktMonitor extends AtolClient
|
final class Monitor extends AtolClient
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
protected function getAuthEndpoint(): string
|
protected function getAuthEndpoint(): string
|
||||||
{
|
{
|
||||||
return $this->isTestMode()
|
return $this->isTestMode()
|
||||||
@@ -37,6 +43,7 @@ class KktMonitor extends AtolClient
|
|||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
protected function getMainEndpoint(): string
|
protected function getMainEndpoint(): string
|
||||||
{
|
{
|
||||||
return $this->isTestMode()
|
return $this->isTestMode()
|
||||||
@@ -49,16 +56,21 @@ class KktMonitor extends AtolClient
|
|||||||
*
|
*
|
||||||
* @param int|null $limit
|
* @param int|null $limit
|
||||||
* @param int|null $offset
|
* @param int|null $offset
|
||||||
* @return KktResponse
|
* @return AtolResponse|null
|
||||||
* @throws GuzzleException
|
* @throws GuzzleException
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
* @see https://online.atol.ru/files/API_service_information.pdf Документация, стр 9
|
* @see https://online.atol.ru/files/API_service_information.pdf Документация, стр 9
|
||||||
*/
|
*/
|
||||||
protected function fetchAll(?int $limit = null, ?int $offset = null): KktResponse
|
protected function fetchAll(?int $limit = null, ?int $offset = null): ?AtolResponse
|
||||||
{
|
{
|
||||||
$params = [];
|
$params = [];
|
||||||
!is_null($limit) && $params['limit'] = $limit;
|
!is_null($limit) && $params['limit'] = $limit;
|
||||||
!is_null($offset) && $params['offset'] = $offset;
|
!is_null($offset) && $params['offset'] = $offset;
|
||||||
return $this->sendRequest('GET', self::getUrlToMethod('cash-registers'), $params);
|
return $this->auth()
|
||||||
|
? $this->sendRequest('GET', self::getUrlToMethod('cash-registers'), $params)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,6 +79,9 @@ class KktMonitor extends AtolClient
|
|||||||
* @param int|null $limit
|
* @param int|null $limit
|
||||||
* @param int|null $offset
|
* @param int|null $offset
|
||||||
* @return Collection
|
* @return Collection
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
* @throws GuzzleException
|
* @throws GuzzleException
|
||||||
* @see https://online.atol.ru/files/API_service_information.pdf Документация, стр 9
|
* @see https://online.atol.ru/files/API_service_information.pdf Документация, стр 9
|
||||||
*/
|
*/
|
||||||
@@ -80,11 +95,11 @@ class KktMonitor extends AtolClient
|
|||||||
* Получает от API информацию о конкретной ККТ по её серийному номеру
|
* Получает от API информацию о конкретной ККТ по её серийному номеру
|
||||||
*
|
*
|
||||||
* @param string $serial_number
|
* @param string $serial_number
|
||||||
* @return KktResponse
|
* @return AtolResponse
|
||||||
* @throws GuzzleException
|
* @throws GuzzleException
|
||||||
* @see https://online.atol.ru/files/API_service_information.pdf Документация, стр 11
|
* @see https://online.atol.ru/files/API_service_information.pdf Документация, стр 11
|
||||||
*/
|
*/
|
||||||
protected function fetchOne(string $serial_number): KktResponse
|
protected function fetchOne(string $serial_number): AtolResponse
|
||||||
{
|
{
|
||||||
return $this->sendRequest(
|
return $this->sendRequest(
|
||||||
'GET',
|
'GET',
|
||||||
@@ -100,7 +115,6 @@ class KktMonitor extends AtolClient
|
|||||||
/**
|
/**
|
||||||
* Возвращает информацию о конкретной ККТ по её серийному номеру
|
* Возвращает информацию о конкретной ККТ по её серийному номеру
|
||||||
*
|
*
|
||||||
* @todo кастовать к отдельному классу со своими геттерами
|
|
||||||
* @param string $serial_number
|
* @param string $serial_number
|
||||||
* @return Kkt
|
* @return Kkt
|
||||||
* @throws GuzzleException
|
* @throws GuzzleException
|
||||||
68
src/Collections/EntityCollection.php
Normal file
68
src/Collections/EntityCollection.php
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?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\Collections;
|
||||||
|
|
||||||
|
use AtolOnline\Exceptions\InvalidEntityInCollectionException;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Абстрактное описание коллекции любых сущностей
|
||||||
|
*/
|
||||||
|
abstract class EntityCollection extends Collection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
*/
|
||||||
|
public function jsonSerialize(): array
|
||||||
|
{
|
||||||
|
$this->checkCount();
|
||||||
|
$this->checkItemsClasses();
|
||||||
|
return parent::jsonSerialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет количество элементов коллекции
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function checkCount(): void
|
||||||
|
{
|
||||||
|
$this->isEmpty() && throw new (static::EMPTY_EXCEPTION_CLASS)();
|
||||||
|
$this->count() > static::MAX_COUNT && throw new (static::TOO_MANY_EXCEPTION_CLASS)(static::MAX_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет корректность класса элемента коллекции
|
||||||
|
*
|
||||||
|
* @param mixed $item
|
||||||
|
* @return void
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
*/
|
||||||
|
public function checkItemClass(mixed $item): void
|
||||||
|
{
|
||||||
|
if (!is_object($item) || $item::class !== static::ENTITY_CLASS) {
|
||||||
|
throw new InvalidEntityInCollectionException(static::class, static::ENTITY_CLASS, $item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет корректность классов элементов коллекции
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
*/
|
||||||
|
public function checkItemsClasses(): self
|
||||||
|
{
|
||||||
|
return $this->each(fn($item) => $this->checkItemClass($item));
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/Collections/Items.php
Normal file
41
src/Collections/Items.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
|
||||||
|
*
|
||||||
|
* This code is licensed under MIT.
|
||||||
|
* Этот код распространяется по лицензии MIT.
|
||||||
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AtolOnline\Collections;
|
||||||
|
|
||||||
|
use AtolOnline\Constants\Constraints;
|
||||||
|
use AtolOnline\Entities\Item;
|
||||||
|
use AtolOnline\Exceptions\EmptyItemsException;
|
||||||
|
use AtolOnline\Exceptions\TooManyItemsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс, описывающий коллекцию предметов расчёта для документа
|
||||||
|
*/
|
||||||
|
final class Items extends EntityCollection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Класс объектов, находящихся в коллекции
|
||||||
|
*/
|
||||||
|
protected const ENTITY_CLASS = Item::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Максмальное количество объектов в коллекции
|
||||||
|
*/
|
||||||
|
protected const MAX_COUNT = Constraints::MAX_COUNT_DOC_ITEMS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс исключения для выброса при пустой коллекции
|
||||||
|
*/
|
||||||
|
protected const EMPTY_EXCEPTION_CLASS = EmptyItemsException::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс-наследник TooManyException для выброса при превышении количества
|
||||||
|
*/
|
||||||
|
protected const TOO_MANY_EXCEPTION_CLASS = TooManyItemsException::class;
|
||||||
|
}
|
||||||
41
src/Collections/Payments.php
Normal file
41
src/Collections/Payments.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
|
||||||
|
*
|
||||||
|
* This code is licensed under MIT.
|
||||||
|
* Этот код распространяется по лицензии MIT.
|
||||||
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AtolOnline\Collections;
|
||||||
|
|
||||||
|
use AtolOnline\Constants\Constraints;
|
||||||
|
use AtolOnline\Entities\Payment;
|
||||||
|
use AtolOnline\Exceptions\EmptyPaymentsException;
|
||||||
|
use AtolOnline\Exceptions\TooManyPaymentsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс, описывающий коллекцию оплат для документа
|
||||||
|
*/
|
||||||
|
final class Payments extends EntityCollection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Класс объектов, находящихся в коллекции
|
||||||
|
*/
|
||||||
|
protected const ENTITY_CLASS = Payment::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Максмальное количество объектов в коллекции
|
||||||
|
*/
|
||||||
|
protected const MAX_COUNT = Constraints::MAX_COUNT_DOC_PAYMENTS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс исключения для выброса при пустой коллекции
|
||||||
|
*/
|
||||||
|
protected const EMPTY_EXCEPTION_CLASS = EmptyPaymentsException::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс-наследник TooManyException для выброса при превышении количества
|
||||||
|
*/
|
||||||
|
protected const TOO_MANY_EXCEPTION_CLASS = TooManyPaymentsException::class;
|
||||||
|
}
|
||||||
41
src/Collections/Vats.php
Normal file
41
src/Collections/Vats.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
|
||||||
|
*
|
||||||
|
* This code is licensed under MIT.
|
||||||
|
* Этот код распространяется по лицензии MIT.
|
||||||
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AtolOnline\Collections;
|
||||||
|
|
||||||
|
use AtolOnline\Constants\Constraints;
|
||||||
|
use AtolOnline\Entities\Vat;
|
||||||
|
use AtolOnline\Exceptions\EmptyVatsException;
|
||||||
|
use AtolOnline\Exceptions\TooManyVatsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс, описывающий коллекцию ставок НДС для документа
|
||||||
|
*/
|
||||||
|
final class Vats extends EntityCollection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Класс объектов, находящихся в коллекции
|
||||||
|
*/
|
||||||
|
protected const ENTITY_CLASS = Vat::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Максмальное количество объектов в коллекции
|
||||||
|
*/
|
||||||
|
protected const MAX_COUNT = Constraints::MAX_COUNT_DOC_VATS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс исключения для выброса при пустой коллекции
|
||||||
|
*/
|
||||||
|
protected const EMPTY_EXCEPTION_CLASS = EmptyVatsException::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс-наследник TooManyException для выброса при превышении количества
|
||||||
|
*/
|
||||||
|
protected const TOO_MANY_EXCEPTION_CLASS = TooManyVatsException::class;
|
||||||
|
}
|
||||||
@@ -43,24 +43,28 @@ final class Constraints
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальная длина наименования покупателя (1227)
|
* Максимальная длина наименования покупателя (1227)
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 17
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 17
|
||||||
*/
|
*/
|
||||||
const MAX_LENGTH_CLIENT_NAME = 256;
|
const MAX_LENGTH_CLIENT_NAME = 256;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальная длина наименования предмета расчёта (1030)
|
* Максимальная длина наименования предмета расчёта (1030)
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
||||||
*/
|
*/
|
||||||
const MAX_LENGTH_ITEM_NAME = 128;
|
const MAX_LENGTH_ITEM_NAME = 128;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальная цена за единицу предмета расчёта (1079)
|
* Максимальная цена за единицу предмета расчёта (1079)
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
||||||
*/
|
*/
|
||||||
const MAX_COUNT_ITEM_PRICE = 42949672.95;
|
const MAX_COUNT_ITEM_PRICE = 42949672.95;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальное количество (вес) единицы предмета расчёта (1023)
|
* Максимальное количество (вес) единицы предмета расчёта (1023)
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
||||||
*/
|
*/
|
||||||
const MAX_COUNT_ITEM_QUANTITY = 99999.999;
|
const MAX_COUNT_ITEM_QUANTITY = 99999.999;
|
||||||
@@ -68,36 +72,42 @@ final class Constraints
|
|||||||
/**
|
/**
|
||||||
* Максимальная стоимость всех предметов расчёта в документе прихода, расхода,
|
* Максимальная стоимость всех предметов расчёта в документе прихода, расхода,
|
||||||
* возврата прихода, возврата расхода (1043)
|
* возврата прихода, возврата расхода (1043)
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
||||||
*/
|
*/
|
||||||
const MAX_COUNT_ITEM_SUM = 42949672.95;
|
const MAX_COUNT_ITEM_SUM = 42949672.95;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальная длина телефона или email покупателя (1008)
|
* Максимальная длина телефона или email покупателя (1008)
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 17
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 17
|
||||||
*/
|
*/
|
||||||
const MAX_LENGTH_CLIENT_CONTACT = 64;
|
const MAX_LENGTH_CLIENT_CONTACT = 64;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Длина операции для платёжного агента (1044)
|
* Длина операции для платёжного агента (1044)
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 19
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 19
|
||||||
*/
|
*/
|
||||||
const MAX_LENGTH_PAYING_AGENT_OPERATION = 24;
|
const MAX_LENGTH_PAYING_AGENT_OPERATION = 24;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальное количество предметов расчёта в документе прихода, расхода, возврата прихода, возврата расхода
|
* Максимальное количество предметов расчёта в документе прихода, расхода, возврата прихода, возврата расхода
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
||||||
*/
|
*/
|
||||||
const MAX_COUNT_DOC_ITEMS = 100;
|
const MAX_COUNT_DOC_ITEMS = 100;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальная длина единицы измерения предмета расчётов
|
* Максимальная длина единицы измерения предмета расчётов
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
||||||
*/
|
*/
|
||||||
const MAX_LENGTH_MEASUREMENT_UNIT = 16;
|
const MAX_LENGTH_MEASUREMENT_UNIT = 16;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальная длина пользовательских данных для предмета расчётов (1191)
|
* Максимальная длина пользовательских данных для предмета расчётов (1191)
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 29
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 29
|
||||||
*/
|
*/
|
||||||
const MAX_LENGTH_USER_DATA = 64;
|
const MAX_LENGTH_USER_DATA = 64;
|
||||||
@@ -105,7 +115,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;
|
||||||
|
|
||||||
@@ -118,16 +128,23 @@ final class Constraints
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальное количество платежей в любом документе
|
* Максимальное количество платежей в любом документе
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 30 и 35
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 30 и 35
|
||||||
*/
|
*/
|
||||||
const MAX_COUNT_DOC_PAYMENTS = 10;
|
const MAX_COUNT_DOC_PAYMENTS = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальное количество ставок НДС в любом документе
|
* Максимальное количество ставок НДС в любом документе
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 31 и 36
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 31 и 36
|
||||||
*/
|
*/
|
||||||
const MAX_COUNT_DOC_VATS = 6;
|
const MAX_COUNT_DOC_VATS = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Максимальная сумма одной оплаты
|
||||||
|
*/
|
||||||
|
const MAX_COUNT_PAYMENT_SUM = 99999.999;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Максимальная длина имени кассира (1021)
|
* Максимальная длина имени кассира (1021)
|
||||||
*
|
*
|
||||||
@@ -135,12 +152,46 @@ 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Максимальная длина значения дополнительного реквизита чека (1192)
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32
|
||||||
|
*/
|
||||||
|
const MAX_LENGTH_ADD_CHECK_PROP = 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Максимальная длина наименования дополнительного реквизита пользователя (1085)
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32
|
||||||
|
*/
|
||||||
|
const MAX_LENGTH_ADD_USER_PROP_NAME = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Максимальная длина значения дополнительного реквизита пользователя (1086)
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32
|
||||||
|
*/
|
||||||
|
const MAX_LENGTH_ADD_USER_PROP_VALUE = 256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Формат даты документа коррекции
|
||||||
|
*/
|
||||||
|
const CORRECTION_DATE_FORMAT = 'd.m.Y';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Регулярное выражение для валидации строки ИНН
|
* Регулярное выражение для валидации строки ИНН
|
||||||
*
|
*
|
||||||
* @see https://online.atol.ru/possystem/v4/schema/sell Схема "#/receipt/client/inn"
|
* @see https://online.atol.ru/possystem/v4/schema/sell Схема "#/receipt/client/inn"
|
||||||
*/
|
*/
|
||||||
const PATTERN_INN = /* @lang PhpRegExp */
|
const PATTERN_INN
|
||||||
|
= /* @lang PhpRegExp */
|
||||||
'/(^[\d]{10}$)|(^[\d]{12}$)/';
|
'/(^[\d]{10}$)|(^[\d]{12}$)/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,19 +199,22 @@ 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 */
|
||||||
'/^([^\s\\\]{0,17}|\+[^\s\\\]{1,18})$/';
|
'/^([^\s\\\]{0,17}|\+[^\s\\\]{1,18})$/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Регулярное выражение для валидации строки Callback URL
|
* Регулярное выражение для валидации строки Callback URL
|
||||||
*/
|
*/
|
||||||
const PATTERN_CALLBACK_URL = /* @lang PhpRegExp */
|
const PATTERN_CALLBACK_URL
|
||||||
'/^http(s?)\:\/\/[0-9a-zA-Zа-яА-Я]' .
|
= /* @lang PhpRegExp */
|
||||||
'([-.\w]*[0-9a-zA-Zа-яА-Я])*(:(0-9)*)*(\/?)([a-zAZ0-9а-яА-Я\-\.\?\,\'\/\\\+&=%\$#_]*)?$/';
|
'/^http(s?):\/\/[0-9a-zA-Zа-яА-Я]' .
|
||||||
|
'([-.\w]*[0-9a-zA-Zа-яА-Я])*(:(0-9)*)*(\/?)([a-zAZ0-9а-яА-Я\-.?,\'\/\\\+&=%\$#_]*)?$/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Регулярное выражение для валидации кода страны происхождения товара
|
* Регулярное выражение для валидации кода страны происхождения товара
|
||||||
*/
|
*/
|
||||||
const PATTERN_OKSM_CODE = /* @lang PhpRegExp */
|
const PATTERN_OKSM_CODE
|
||||||
|
= /* @lang PhpRegExp */
|
||||||
'/^[\d]{3}$/';
|
'/^[\d]{3}$/';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,6 +162,11 @@ final class Ffd105Tags
|
|||||||
*/
|
*/
|
||||||
const CORRECTION_TYPE = 1173;
|
const CORRECTION_TYPE = 1173;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Дата документа основания для коррекции
|
||||||
|
*/
|
||||||
|
const CORRECTION_DATE = 1178;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сумма по чеку (БСО) наличными
|
* Сумма по чеку (БСО) наличными
|
||||||
*/
|
*/
|
||||||
@@ -221,4 +226,24 @@ final class Ffd105Tags
|
|||||||
* Сумма НДС чека по расч. ставке 20/120
|
* Сумма НДС чека по расч. ставке 20/120
|
||||||
*/
|
*/
|
||||||
const DOC_VAT_TYPE_VAT120 = 1106;
|
const DOC_VAT_TYPE_VAT120 = 1106;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Значение дополнительного реквизита чека
|
||||||
|
*/
|
||||||
|
const DOC_ADD_CHECK_PROP_VALUE = 1192;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Дополнительный реквизит пользователя
|
||||||
|
*/
|
||||||
|
const DOC_ADD_USER_PROP = 1084;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Наименование дополнительного реквизита пользователя
|
||||||
|
*/
|
||||||
|
const DOC_ADD_USER_PROP_NAME = 1085;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Значение дополнительного реквизита пользователя
|
||||||
|
*/
|
||||||
|
const DOC_ADD_USER_PROP_VALUE = 1086;
|
||||||
}
|
}
|
||||||
|
|||||||
132
src/Entities/AdditionalUserProps.php
Normal file
132
src/Entities/AdditionalUserProps.php
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<?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\Entities;
|
||||||
|
|
||||||
|
use AtolOnline\Constants\Constraints;
|
||||||
|
use AtolOnline\Exceptions\{
|
||||||
|
EmptyAddUserPropNameException,
|
||||||
|
EmptyAddUserPropValueException,
|
||||||
|
TooLongAddUserPropNameException,
|
||||||
|
TooLongAddUserPropValueException
|
||||||
|
};
|
||||||
|
use JetBrains\PhpStorm\{
|
||||||
|
ArrayShape,
|
||||||
|
Pure
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс, описывающий дополнительный реквизит пользователя
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32
|
||||||
|
*/
|
||||||
|
final class AdditionalUserProps extends Entity
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string Наименование (1085)
|
||||||
|
*/
|
||||||
|
protected string $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Значение (1086)
|
||||||
|
*/
|
||||||
|
protected string $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор объекта покупателя
|
||||||
|
*
|
||||||
|
* @param string $name Наименование (1227)
|
||||||
|
* @param string $value Значение (1008)
|
||||||
|
* @throws EmptyAddUserPropNameException
|
||||||
|
* @throws EmptyAddUserPropValueException
|
||||||
|
* @throws TooLongAddUserPropNameException
|
||||||
|
* @throws TooLongAddUserPropValueException
|
||||||
|
*/
|
||||||
|
public function __construct(string $name, string $value)
|
||||||
|
{
|
||||||
|
$this->setName($name)->setValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает наименование реквизита
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает наименование реквизита
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return $this
|
||||||
|
* @throws TooLongAddUserPropNameException
|
||||||
|
* @throws EmptyAddUserPropNameException
|
||||||
|
*/
|
||||||
|
public function setName(string $name): self
|
||||||
|
{
|
||||||
|
$name = trim($name);
|
||||||
|
if (mb_strlen($name) > Constraints::MAX_LENGTH_ADD_USER_PROP_NAME) {
|
||||||
|
throw new TooLongAddUserPropNameException($name);
|
||||||
|
}
|
||||||
|
if (empty($name)) {
|
||||||
|
throw new EmptyAddUserPropNameException($name);
|
||||||
|
}
|
||||||
|
$this->name = $name;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленный телефон
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getValue(): ?string
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает значение реквизита
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return $this
|
||||||
|
* @throws TooLongAddUserPropValueException
|
||||||
|
* @throws EmptyAddUserPropValueException
|
||||||
|
*/
|
||||||
|
public function setValue(string $value): self
|
||||||
|
{
|
||||||
|
$value = trim($value);
|
||||||
|
if (mb_strlen($value) > Constraints::MAX_LENGTH_CLIENT_NAME) {
|
||||||
|
throw new TooLongAddUserPropValueException($value);
|
||||||
|
}
|
||||||
|
if (empty($value)) {
|
||||||
|
throw new EmptyAddUserPropValueException($value);
|
||||||
|
}
|
||||||
|
$this->value = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
#[Pure]
|
||||||
|
#[ArrayShape(['name' => 'string', 'value' => 'null|string'])]
|
||||||
|
public function jsonSerialize(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => $this->getName(),
|
||||||
|
'value' => $this->getValue(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ use AtolOnline\Exceptions\InvalidEnumValueException;
|
|||||||
*
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 26-28
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 26-28
|
||||||
*/
|
*/
|
||||||
class AgentInfo extends Entity
|
final class AgentInfo extends Entity
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string|null Признак агента (1057)
|
* @var string|null Признак агента (1057)
|
||||||
@@ -45,21 +45,21 @@ class AgentInfo extends Entity
|
|||||||
* Конструктор
|
* Конструктор
|
||||||
*
|
*
|
||||||
* @param string|null $type Признак агента (1057)
|
* @param string|null $type Признак агента (1057)
|
||||||
* @param PayingAgent|null $paying_agent Платёжный агент
|
* @param PayingAgent|null $pagent Платёжный агент
|
||||||
* @param ReceivePaymentsOperator|null $receive_payments_operator Оператор по приёму платежей
|
* @param ReceivePaymentsOperator|null $rp_operator Оператор по приёму платежей
|
||||||
* @param MoneyTransferOperator|null $money_transfer_operator Оператор перевода
|
* @param MoneyTransferOperator|null $mt_operator Оператор перевода
|
||||||
* @throws InvalidEnumValueException
|
* @throws InvalidEnumValueException
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
?string $type = null,
|
?string $type = null,
|
||||||
?PayingAgent $paying_agent = null,
|
?PayingAgent $pagent = null,
|
||||||
?ReceivePaymentsOperator $receive_payments_operator = null,
|
?ReceivePaymentsOperator $rp_operator = null,
|
||||||
?MoneyTransferOperator $money_transfer_operator = null,
|
?MoneyTransferOperator $mt_operator = null,
|
||||||
) {
|
) {
|
||||||
!is_null($type) && $this->setType($type);
|
!is_null($type) && $this->setType($type);
|
||||||
!is_null($paying_agent) && $this->setPayingAgent($paying_agent);
|
!is_null($pagent) && $this->setPayingAgent($pagent);
|
||||||
!is_null($receive_payments_operator) && $this->setReceivePaymentsOperator($receive_payments_operator);
|
!is_null($rp_operator) && $this->setReceivePaymentsOperator($rp_operator);
|
||||||
!is_null($money_transfer_operator) && $this->setMoneyTransferOperator($money_transfer_operator);
|
!is_null($mt_operator) && $this->setMoneyTransferOperator($mt_operator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,7 +79,7 @@ class AgentInfo extends Entity
|
|||||||
* @return AgentInfo
|
* @return AgentInfo
|
||||||
* @throws InvalidEnumValueException
|
* @throws InvalidEnumValueException
|
||||||
*/
|
*/
|
||||||
public function setType(?string $type): AgentInfo
|
public function setType(?string $type): self
|
||||||
{
|
{
|
||||||
AgentTypes::isValid($type) && $this->type = $type;
|
AgentTypes::isValid($type) && $this->type = $type;
|
||||||
return $this;
|
return $this;
|
||||||
@@ -98,12 +98,12 @@ class AgentInfo extends Entity
|
|||||||
/**
|
/**
|
||||||
* Устанавливает платёжного агента
|
* Устанавливает платёжного агента
|
||||||
*
|
*
|
||||||
* @param PayingAgent|null $paying_agent
|
* @param PayingAgent|null $agent
|
||||||
* @return AgentInfo
|
* @return AgentInfo
|
||||||
*/
|
*/
|
||||||
public function setPayingAgent(?PayingAgent $paying_agent): AgentInfo
|
public function setPayingAgent(?PayingAgent $agent): self
|
||||||
{
|
{
|
||||||
$this->paying_agent = $paying_agent;
|
$this->paying_agent = $agent;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,12 +120,12 @@ class AgentInfo extends Entity
|
|||||||
/**
|
/**
|
||||||
* Устанавливает оператора по приёму платежей
|
* Устанавливает оператора по приёму платежей
|
||||||
*
|
*
|
||||||
* @param ReceivePaymentsOperator|null $receive_payments_operator
|
* @param ReceivePaymentsOperator|null $operator
|
||||||
* @return AgentInfo
|
* @return AgentInfo
|
||||||
*/
|
*/
|
||||||
public function setReceivePaymentsOperator(?ReceivePaymentsOperator $receive_payments_operator): AgentInfo
|
public function setReceivePaymentsOperator(?ReceivePaymentsOperator $operator): self
|
||||||
{
|
{
|
||||||
$this->receive_payments_operator = $receive_payments_operator;
|
$this->receive_payments_operator = $operator;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,12 +142,12 @@ class AgentInfo extends Entity
|
|||||||
/**
|
/**
|
||||||
* Устанавливает оператора перевода
|
* Устанавливает оператора перевода
|
||||||
*
|
*
|
||||||
* @param MoneyTransferOperator|null $money_transfer_operator
|
* @param MoneyTransferOperator|null $operator
|
||||||
* @return AgentInfo
|
* @return AgentInfo
|
||||||
*/
|
*/
|
||||||
public function setMoneyTransferOperator(?MoneyTransferOperator $money_transfer_operator): AgentInfo
|
public function setMoneyTransferOperator(?MoneyTransferOperator $operator): self
|
||||||
{
|
{
|
||||||
$this->money_transfer_operator = $money_transfer_operator;
|
$this->money_transfer_operator = $operator;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,54 +11,49 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Entities;
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
use AtolOnline\{
|
use AtolOnline\Constants\Constraints;
|
||||||
Constants\Constraints,
|
use AtolOnline\Exceptions\{
|
||||||
Exceptions\InvalidEmailException,
|
InvalidEmailException,
|
||||||
Exceptions\InvalidInnLengthException,
|
InvalidInnLengthException,
|
||||||
Exceptions\InvalidPhoneException,
|
InvalidPhoneException,
|
||||||
Exceptions\TooLongClientContactException,
|
TooLongClientNameException,
|
||||||
Exceptions\TooLongClientNameException,
|
TooLongEmailException};
|
||||||
Exceptions\TooLongEmailException};
|
use AtolOnline\Traits\{
|
||||||
|
HasEmail,
|
||||||
|
HasInn};
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс, описывающий покупателя
|
* Класс, описывающий покупателя
|
||||||
*
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 17
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 17
|
||||||
*/
|
*/
|
||||||
class Client extends Entity
|
final class Client extends Entity
|
||||||
{
|
{
|
||||||
|
use HasEmail, HasInn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null Наименование (1227)
|
* @var string|null Наименование (1227)
|
||||||
*/
|
*/
|
||||||
protected ?string $name = null;
|
protected ?string $name = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null Email (1008)
|
|
||||||
*/
|
|
||||||
protected ?string $email = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null Телефон (1008)
|
* @var string|null Телефон (1008)
|
||||||
*/
|
*/
|
||||||
protected ?string $phone = null;
|
protected ?string $phone = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null ИНН (1228)
|
|
||||||
*/
|
|
||||||
protected ?string $inn = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конструктор объекта покупателя
|
* Конструктор объекта покупателя
|
||||||
*
|
*
|
||||||
* @param string|null $name Наименование (1227)
|
* @param string|null $name Наименование (1227)
|
||||||
* @param string|null $phone Email (1008)
|
|
||||||
* @param string|null $email Телефон (1008)
|
* @param string|null $email Телефон (1008)
|
||||||
|
* @param string|null $phone Email (1008)
|
||||||
* @param string|null $inn ИНН (1228)
|
* @param string|null $inn ИНН (1228)
|
||||||
* @throws TooLongClientNameException
|
|
||||||
* @throws TooLongClientContactException
|
|
||||||
* @throws TooLongEmailException
|
|
||||||
* @throws InvalidEmailException
|
* @throws InvalidEmailException
|
||||||
* @throws InvalidInnLengthException
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPhoneException
|
||||||
|
* @throws TooLongClientNameException
|
||||||
|
* @throws TooLongEmailException
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
?string $name = null,
|
?string $name = null,
|
||||||
@@ -97,39 +92,7 @@ class Client extends Entity
|
|||||||
throw new TooLongClientNameException($name);
|
throw new TooLongClientNameException($name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->name = empty($name) ? null : $name;
|
$this->name = $name ?: null;
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает установленный email
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getEmail(): ?string
|
|
||||||
{
|
|
||||||
return $this->email;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает email
|
|
||||||
*
|
|
||||||
* @param string|null $email
|
|
||||||
* @return $this
|
|
||||||
* @throws TooLongEmailException Слишком длинный email
|
|
||||||
* @throws InvalidEmailException Невалидный email
|
|
||||||
*/
|
|
||||||
public function setEmail(?string $email): self
|
|
||||||
{
|
|
||||||
if (is_string($email)) {
|
|
||||||
$email = preg_replace('/[\n\r\t]/', '', trim($email));
|
|
||||||
if (mb_strlen($email) > Constraints::MAX_LENGTH_EMAIL) {
|
|
||||||
throw new TooLongEmailException($email);
|
|
||||||
} elseif (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
|
|
||||||
throw new InvalidEmailException($email);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->email = empty($email) ? null : $email;
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,45 +125,17 @@ class Client extends Entity
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает установленный ИНН
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getInn(): ?string
|
|
||||||
{
|
|
||||||
return $this->inn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает ИНН
|
|
||||||
*
|
|
||||||
* @param string|null $inn
|
|
||||||
* @return $this
|
|
||||||
* @throws InvalidInnLengthException Некорректная длина ИНН
|
|
||||||
*/
|
|
||||||
public function setInn(?string $inn): self
|
|
||||||
{
|
|
||||||
if (is_string($inn)) {
|
|
||||||
$inn = preg_replace('/[^\d]/', '', trim($inn));
|
|
||||||
if (preg_match_all(Constraints::PATTERN_INN, $inn) === 0) {
|
|
||||||
throw new InvalidInnLengthException($inn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->inn = empty($inn) ? null : $inn;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
$json = [];
|
$json = [];
|
||||||
$this->getName() && $json['name'] = $this->getName();
|
!is_null($this->getName()) && $json['name'] = $this->getName();
|
||||||
$this->getEmail() && $json['email'] = $this->getEmail();
|
!is_null($this->getEmail()) && $json['email'] = $this->getEmail();
|
||||||
$this->getPhone() && $json['phone'] = $this->getPhone();
|
!is_null($this->getPhone()) && $json['phone'] = $this->getPhone();
|
||||||
$this->getInn() && $json['inn'] = $this->getInn();
|
!is_null($this->getInn()) && $json['inn'] = $this->getInn();
|
||||||
return $json;
|
return $json;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,35 +14,33 @@ namespace AtolOnline\Entities;
|
|||||||
use AtolOnline\{
|
use AtolOnline\{
|
||||||
Constants\Constraints,
|
Constants\Constraints,
|
||||||
Enums\SnoTypes,
|
Enums\SnoTypes,
|
||||||
Exceptions\InvalidEmailException,
|
Traits\HasEmail,
|
||||||
Exceptions\InvalidEnumValueException,
|
Traits\HasInn
|
||||||
Exceptions\InvalidInnLengthException,
|
};
|
||||||
Exceptions\InvalidPaymentAddressException,
|
use AtolOnline\Exceptions\{
|
||||||
Exceptions\TooLongEmailException,
|
InvalidEmailException,
|
||||||
Exceptions\TooLongPaymentAddressException};
|
InvalidEnumValueException,
|
||||||
|
InvalidInnLengthException,
|
||||||
|
InvalidPaymentAddressException,
|
||||||
|
TooLongEmailException,
|
||||||
|
TooLongPaymentAddressException
|
||||||
|
};
|
||||||
|
use JetBrains\PhpStorm\ArrayShape;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс, описывающий сущность компании-продавца
|
* Класс, описывающий сущность компании-продавца
|
||||||
*
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 17
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 17
|
||||||
*/
|
*/
|
||||||
class Company extends Entity
|
final class Company extends Entity
|
||||||
{
|
{
|
||||||
/**
|
use HasEmail, HasInn;
|
||||||
* @var string|null Почта (1117)
|
|
||||||
*/
|
|
||||||
protected ?string $email;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null Система налогообложения продавца (1055)
|
* @var string|null Система налогообложения продавца (1055)
|
||||||
*/
|
*/
|
||||||
protected ?string $sno;
|
protected ?string $sno;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null ИНН (1018)
|
|
||||||
*/
|
|
||||||
protected ?string $inn;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null Место расчётов (адрес интернет-магазина) (1187)
|
* @var string|null Место расчётов (адрес интернет-магазина) (1187)
|
||||||
*/
|
*/
|
||||||
@@ -63,45 +61,12 @@ class Company extends Entity
|
|||||||
* @throws TooLongPaymentAddressException
|
* @throws TooLongPaymentAddressException
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
string $email,
|
string $email, //TODO сделать необязательным здесь
|
||||||
string $sno,
|
string $sno, //TODO сделать необязательным здесь
|
||||||
string $inn,
|
string $inn,
|
||||||
string $payment_address,
|
string $payment_address,
|
||||||
) {
|
) {
|
||||||
$this->setEmail($email);
|
$this->setEmail($email)->setSno($sno)->setInn($inn)->setPaymentAddress($payment_address);
|
||||||
$this->setSno($sno);
|
|
||||||
$this->setInn($inn);
|
|
||||||
$this->setPaymentAddress($payment_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает установленный email
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getEmail(): string
|
|
||||||
{
|
|
||||||
return $this->email;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает email
|
|
||||||
*
|
|
||||||
* @param string $email
|
|
||||||
* @return $this
|
|
||||||
* @throws TooLongEmailException Слишком длинный email
|
|
||||||
* @throws InvalidEmailException Невалидный email
|
|
||||||
*/
|
|
||||||
public function setEmail(string $email): self
|
|
||||||
{
|
|
||||||
$email = preg_replace('/[\n\r\t]/', '', trim($email));
|
|
||||||
if (mb_strlen($email) > Constraints::MAX_LENGTH_EMAIL) {
|
|
||||||
throw new TooLongEmailException($email);
|
|
||||||
} elseif (empty($email) || filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
|
|
||||||
throw new InvalidEmailException($email);
|
|
||||||
}
|
|
||||||
$this->email = $email;
|
|
||||||
return $this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,35 +89,7 @@ class Company extends Entity
|
|||||||
public function setSno(string $sno): self
|
public function setSno(string $sno): self
|
||||||
{
|
{
|
||||||
$sno = trim($sno);
|
$sno = trim($sno);
|
||||||
SnoTypes::isValid($sno);
|
SnoTypes::isValid($sno) && $this->sno = $sno;
|
||||||
$this->sno = $sno;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает установленный ИНН
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getInn(): string
|
|
||||||
{
|
|
||||||
return $this->inn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает ИНН
|
|
||||||
*
|
|
||||||
* @param string $inn
|
|
||||||
* @return $this
|
|
||||||
* @throws InvalidInnLengthException
|
|
||||||
*/
|
|
||||||
public function setInn(string $inn): self
|
|
||||||
{
|
|
||||||
$inn = preg_replace('/[^\d]/', '', trim($inn));
|
|
||||||
if (empty($inn) || preg_match_all(Constraints::PATTERN_INN, $inn) === 0) {
|
|
||||||
throw new InvalidInnLengthException($inn);
|
|
||||||
}
|
|
||||||
$this->inn = $inn;
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +130,12 @@ class Company extends Entity
|
|||||||
* @throws InvalidInnLengthException
|
* @throws InvalidInnLengthException
|
||||||
* @throws InvalidPaymentAddressException
|
* @throws InvalidPaymentAddressException
|
||||||
*/
|
*/
|
||||||
|
#[ArrayShape([
|
||||||
|
'email' => 'string',
|
||||||
|
'sno' => 'string',
|
||||||
|
'inn' => 'string',
|
||||||
|
'payment_address' => 'string',
|
||||||
|
])]
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|||||||
273
src/Entities/Correction.php
Normal file
273
src/Entities/Correction.php
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
|
||||||
|
*
|
||||||
|
* This code is licensed under MIT.
|
||||||
|
* Этот код распространяется по лицензии MIT.
|
||||||
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
|
use AtolOnline\{
|
||||||
|
Api\AtolResponse,
|
||||||
|
Api\Fiscalizer,
|
||||||
|
Collections\Payments,
|
||||||
|
Collections\Vats,
|
||||||
|
Constants\Constraints};
|
||||||
|
use AtolOnline\Exceptions\{
|
||||||
|
AuthFailedException,
|
||||||
|
EmptyLoginException,
|
||||||
|
EmptyPasswordException,
|
||||||
|
InvalidEntityInCollectionException,
|
||||||
|
InvalidInnLengthException,
|
||||||
|
InvalidPaymentAddressException,
|
||||||
|
TooLongCashierException,
|
||||||
|
TooLongPaymentAddressException};
|
||||||
|
use Exception;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
use JetBrains\PhpStorm\ArrayShape;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс, описывающий документ коррекции
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 35
|
||||||
|
*/
|
||||||
|
final class Correction extends Entity
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Тип документа
|
||||||
|
*/
|
||||||
|
public const DOC_TYPE = 'correction';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Company Продавец
|
||||||
|
*/
|
||||||
|
protected Company $company;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo вынести в трейт?
|
||||||
|
* @var string|null ФИО кассира
|
||||||
|
*/
|
||||||
|
protected ?string $cashier = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var CorrectionInfo Данные коррекции
|
||||||
|
*/
|
||||||
|
protected CorrectionInfo $correction_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Payments Коллекция оплат
|
||||||
|
*/
|
||||||
|
protected Payments $payments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Vats Коллекция ставок НДС
|
||||||
|
*/
|
||||||
|
protected Vats $vats;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param Company $company
|
||||||
|
* @param CorrectionInfo $correction_info
|
||||||
|
* @param Payments $payments
|
||||||
|
* @param Vats $vats
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Company $company,
|
||||||
|
CorrectionInfo $correction_info,
|
||||||
|
Payments $payments,
|
||||||
|
Vats $vats,
|
||||||
|
) {
|
||||||
|
$this->setCompany($company)->setCorrectionInfo($correction_info)->setPayments($payments)->setVats($vats);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленного продавца
|
||||||
|
*
|
||||||
|
* @return Company
|
||||||
|
*/
|
||||||
|
public function getCompany(): Company
|
||||||
|
{
|
||||||
|
return $this->company;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает продавца
|
||||||
|
*
|
||||||
|
* @param Company $company
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setCompany(Company $company): self
|
||||||
|
{
|
||||||
|
$this->company = $company;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленного кассира
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCashier(): ?string
|
||||||
|
{
|
||||||
|
return $this->cashier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает кассира
|
||||||
|
*
|
||||||
|
* @param string|null $cashier
|
||||||
|
* @return $this
|
||||||
|
* @throws TooLongCashierException
|
||||||
|
*/
|
||||||
|
public function setCashier(?string $cashier): self
|
||||||
|
{
|
||||||
|
if (is_string($cashier)) {
|
||||||
|
$cashier = trim($cashier);
|
||||||
|
if (mb_strlen($cashier) > Constraints::MAX_LENGTH_CASHIER_NAME) {
|
||||||
|
throw new TooLongCashierException($cashier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->cashier = $cashier ?: null;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленные данные коррекции
|
||||||
|
*
|
||||||
|
* @return CorrectionInfo
|
||||||
|
*/
|
||||||
|
public function getCorrectionInfo(): CorrectionInfo
|
||||||
|
{
|
||||||
|
return $this->correction_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает данные коррекции
|
||||||
|
*
|
||||||
|
* @param CorrectionInfo $correction_info
|
||||||
|
* @return Correction
|
||||||
|
*/
|
||||||
|
public function setCorrectionInfo(CorrectionInfo $correction_info): Correction
|
||||||
|
{
|
||||||
|
$this->correction_info = $correction_info;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленную коллекцию оплат
|
||||||
|
*
|
||||||
|
* @return Payments
|
||||||
|
*/
|
||||||
|
public function getPayments(): Payments
|
||||||
|
{
|
||||||
|
return $this->payments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает коллекцию оплат
|
||||||
|
*
|
||||||
|
* @param Payments $payments
|
||||||
|
* @return $this
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
*/
|
||||||
|
public function setPayments(Payments $payments): self
|
||||||
|
{
|
||||||
|
$payments->checkCount();
|
||||||
|
$payments->checkItemsClasses();
|
||||||
|
$this->payments = $payments;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленную коллекцию ставок НДС
|
||||||
|
*
|
||||||
|
* @return Vats|null
|
||||||
|
*/
|
||||||
|
public function getVats(): Vats
|
||||||
|
{
|
||||||
|
return $this->vats ?? new Vats();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает коллекцию ставок НДС
|
||||||
|
*
|
||||||
|
* @param Vats|null $vats
|
||||||
|
* @return $this
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function setVats(Vats $vats): self
|
||||||
|
{
|
||||||
|
$vats->checkCount();
|
||||||
|
$vats->checkItemsClasses();
|
||||||
|
$this->vats = $vats;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует коррекцию прихода по текущему документу
|
||||||
|
*
|
||||||
|
* @param Fiscalizer $fiscalizer Объект фискализатора
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function sellCorrect(Fiscalizer $fiscalizer, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $fiscalizer->sellCorrect($this, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует коррекцию расхода по текущему документу
|
||||||
|
*
|
||||||
|
* @param Fiscalizer $fiscalizer Объект фискализатора
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function buyCorrect(Fiscalizer $fiscalizer, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $fiscalizer->buyCorrect($this, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
*/
|
||||||
|
#[ArrayShape([
|
||||||
|
'company' => '\AtolOnline\Entities\Company',
|
||||||
|
'correction_info' => '\AtolOnline\Entities\CorrectionInfo',
|
||||||
|
'payments' => 'array',
|
||||||
|
'vats' => '\AtolOnline\Collections\Vats|null',
|
||||||
|
'cashier' => 'null|string',
|
||||||
|
])]
|
||||||
|
public function jsonSerialize(): array
|
||||||
|
{
|
||||||
|
$json = [
|
||||||
|
'company' => $this->getCompany(),
|
||||||
|
'correction_info' => $this->getCorrectionInfo(),
|
||||||
|
'payments' => $this->getPayments()->jsonSerialize(),
|
||||||
|
'vats' => $this->getVats(),
|
||||||
|
];
|
||||||
|
!is_null($this->getCashier()) && $json['cashier'] = $this->getCashier();
|
||||||
|
return $json;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,94 +11,57 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Entities;
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
|
use AtolOnline\Constants\Constraints;
|
||||||
|
use AtolOnline\Enums\CorrectionTypes;
|
||||||
|
use AtolOnline\Exceptions\{
|
||||||
|
EmptyCorrectionNumberException,
|
||||||
|
InvalidCorrectionDateException,
|
||||||
|
InvalidEnumValueException};
|
||||||
|
use DateTime;
|
||||||
|
use Exception;
|
||||||
|
use JetBrains\PhpStorm\{
|
||||||
|
ArrayShape,
|
||||||
|
Pure};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс CorrectionInfo, описывающий данные чек коррекции
|
* Класс, описывающий данные коррекции
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 35
|
||||||
*/
|
*/
|
||||||
class CorrectionInfo extends Entity
|
final class CorrectionInfo extends Entity
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string Тип коррекции. Тег ФФД - 1173.
|
* @var string|null Тип коррекции (1173)
|
||||||
*/
|
*/
|
||||||
protected string $type;
|
protected ?string $type = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string Дата документа основания для коррекции. Тег ФФД - 1178.
|
* @var string|null Дата документа основания для коррекции (1178)
|
||||||
*/
|
*/
|
||||||
protected string $base_date;
|
protected ?string $date = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string Номер документа основания для коррекции. Тег ФФД - 1179.
|
* @var string|null Номер документа основания для коррекции (1179)
|
||||||
*/
|
*/
|
||||||
protected string $base_number;
|
protected ?string $number = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CorrectionInfo constructor.
|
* Конструктор
|
||||||
*
|
*
|
||||||
* @param string|null $type Тип коррекции
|
* @param string $type Тип коррекции
|
||||||
* @param string|null $base_date Дата документа
|
* @param string $date Дата документа
|
||||||
* @param string|null $base_number Номер документа
|
* @param string $number Номер документа
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws InvalidCorrectionDateException
|
||||||
|
* @throws EmptyCorrectionNumberException
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(string $type, string $date, string $number)
|
||||||
?string $type = null,
|
|
||||||
?string $base_date = null,
|
|
||||||
?string $base_number = null
|
|
||||||
) {
|
|
||||||
$type && $this->setType($type);
|
|
||||||
$base_date && $this->setDate($base_date);
|
|
||||||
$base_number && $this->setNumber($base_number);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает номер документа основания для коррекции.
|
|
||||||
* Тег ФФД - 1179.
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getNumber(): ?string
|
|
||||||
{
|
{
|
||||||
return $this->base_number;
|
$this->setType($type)->setDate($date)->setNumber($number);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Устанавливает номер документа основания для коррекции.
|
* Возвращает тип коррекции
|
||||||
* Тег ФФД - 1179.
|
|
||||||
*
|
|
||||||
* @param string $number
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setNumber(string $number): CorrectionInfo
|
|
||||||
{
|
|
||||||
$this->base_number = trim($number);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает дату документа основания для коррекции.
|
|
||||||
* Тег ФФД - 1178.
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getDate(): ?string
|
|
||||||
{
|
|
||||||
return $this->base_date;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает дату документа основания для коррекции.
|
|
||||||
* Тег ФФД - 1178.
|
|
||||||
*
|
|
||||||
* @param string $date Строка в формате d.m.Y
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setDate(string $date): CorrectionInfo
|
|
||||||
{
|
|
||||||
$this->base_date = $date;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает тип коррекции.
|
|
||||||
* Тег ФФД - 1173.
|
|
||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
@@ -108,27 +71,85 @@ class CorrectionInfo extends Entity
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Устанавливает тип коррекции.
|
* Устанавливает тип коррекции
|
||||||
* Тег ФФД - 1173.
|
|
||||||
*
|
*
|
||||||
* @param string $type
|
* @param string $type
|
||||||
* @return $this
|
* @return $this
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
*/
|
*/
|
||||||
public function setType(string $type): CorrectionInfo
|
public function setType(string $type): self
|
||||||
{
|
{
|
||||||
$this->type = $type;
|
$type = trim($type);
|
||||||
|
CorrectionTypes::isValid($type) && $this->type = $type;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает дату документа основания для коррекции
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getDate(): ?string
|
||||||
|
{
|
||||||
|
return $this->date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает дату документа основания для коррекции
|
||||||
|
*
|
||||||
|
* @param DateTime|string $date Строковая дата в формате d.m.Y либо объект DateTime с датой
|
||||||
|
* @return $this
|
||||||
|
* @throws InvalidCorrectionDateException
|
||||||
|
*/
|
||||||
|
public function setDate(DateTime|string $date): self
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (is_string($date)) {
|
||||||
|
$date = new DateTime(trim($date));
|
||||||
|
}
|
||||||
|
$this->date = $date->format(Constraints::CORRECTION_DATE_FORMAT);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
throw new InvalidCorrectionDateException($date, $e->getMessage());
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленный номер документа основания для коррекции
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getNumber(): ?string
|
||||||
|
{
|
||||||
|
return $this->number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает номер документа основания для коррекции
|
||||||
|
*
|
||||||
|
* @param string $number
|
||||||
|
* @return $this
|
||||||
|
* @throws EmptyCorrectionNumberException
|
||||||
|
*/
|
||||||
|
public function setNumber(string $number): self
|
||||||
|
{
|
||||||
|
$number = trim($number);
|
||||||
|
empty($number) && throw new EmptyCorrectionNumberException();
|
||||||
|
$this->number = $number;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
|
#[ArrayShape(['type' => 'string', 'base_date' => 'string', 'base_number' => 'string'])]
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'type' => $this->getType() ?? '',
|
'type' => $this->getType(),
|
||||||
'base_date' => $this->getDate() ?? '',
|
'base_date' => $this->getDate(),
|
||||||
'base_number' => $this->getNumber() ?? '',
|
'base_number' => $this->getNumber(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,468 +0,0 @@
|
|||||||
<?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\Entities;
|
|
||||||
|
|
||||||
use AtolOnline\Constants\Constraints;
|
|
||||||
use AtolOnline\Exceptions\AtolException;
|
|
||||||
use AtolOnline\Exceptions\InvalidEmailException;
|
|
||||||
use AtolOnline\Exceptions\InvalidInnLengthException;
|
|
||||||
use AtolOnline\Exceptions\InvalidJsonException;
|
|
||||||
use AtolOnline\Exceptions\TooHighPriceException;
|
|
||||||
use AtolOnline\Exceptions\TooLongCashierException;
|
|
||||||
use AtolOnline\Exceptions\TooLongClientContactException;
|
|
||||||
use AtolOnline\Exceptions\TooLongEmailException;
|
|
||||||
use AtolOnline\Exceptions\TooLongItemNameException;
|
|
||||||
use AtolOnline\Exceptions\TooLongMeasurementUnitException;
|
|
||||||
use AtolOnline\Exceptions\TooLongPaymentAddressException;
|
|
||||||
use AtolOnline\Exceptions\TooLongUserdataException;
|
|
||||||
use AtolOnline\Exceptions\TooManyException;
|
|
||||||
use AtolOnline\Exceptions\TooManyItemsException;
|
|
||||||
use AtolOnline\Exceptions\TooManyPaymentsException;
|
|
||||||
use AtolOnline\Exceptions\TooManyVatsException;
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Класс, описывающий документ
|
|
||||||
*
|
|
||||||
* @package AtolOnline\Entities
|
|
||||||
*/
|
|
||||||
class Document extends Entity
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var ItemArray Массив предметов расчёта
|
|
||||||
*/
|
|
||||||
protected ItemArray $items;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var VatArray Массив ставок НДС
|
|
||||||
*/
|
|
||||||
protected VatArray $vats;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var PaymentArray Массив оплат
|
|
||||||
*/
|
|
||||||
protected PaymentArray $payments;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Company Объект компании (продавца)
|
|
||||||
*/
|
|
||||||
protected Company $company;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Client Объект клиента (покупателя)
|
|
||||||
*/
|
|
||||||
protected Client $client;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var float Итоговая сумма чека. Тег ФФД - 1020.
|
|
||||||
*/
|
|
||||||
protected float $total = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string ФИО кассира. Тег ФФД - 1021.
|
|
||||||
*/
|
|
||||||
protected string $cashier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var CorrectionInfo Данные коррекции
|
|
||||||
*/
|
|
||||||
protected CorrectionInfo $correction_info;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Document constructor.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->vats = new VatArray();
|
|
||||||
$this->payments = new PaymentArray();
|
|
||||||
$this->items = new ItemArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Удаляет все налоги из документа и предметов расчёта
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
* @throws TooManyVatsException Слишком много ставок НДС
|
|
||||||
*/
|
|
||||||
public function clearVats(): Document
|
|
||||||
{
|
|
||||||
$this->setVats([]);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавляет новую ставку НДС в массив ставок НДС
|
|
||||||
*
|
|
||||||
* @param Vat $vat Объект ставки НДС
|
|
||||||
* @return $this
|
|
||||||
* @throws TooManyVatsException Слишком много ставок НДС
|
|
||||||
*/
|
|
||||||
public function addVat(Vat $vat): Document
|
|
||||||
{
|
|
||||||
$this->vats->add($vat);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает массив ставок НДС
|
|
||||||
*
|
|
||||||
* @return Vat[]
|
|
||||||
*/
|
|
||||||
public function getVats(): array
|
|
||||||
{
|
|
||||||
return $this->vats->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает массив ставок НДС
|
|
||||||
*
|
|
||||||
* @param Vat[] $vats Массив ставок НДС
|
|
||||||
* @return $this
|
|
||||||
* @throws TooManyVatsException Слишком много ставок НДС
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public function setVats(array $vats): Document
|
|
||||||
{
|
|
||||||
$this->vats->set($vats);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавляет новую оплату в массив оплат
|
|
||||||
*
|
|
||||||
* @param Payment $payment Объект оплаты
|
|
||||||
* @return $this
|
|
||||||
* @throws Exception
|
|
||||||
* @throws TooManyPaymentsException Слишком много оплат
|
|
||||||
*/
|
|
||||||
public function addPayment(Payment $payment): Document
|
|
||||||
{
|
|
||||||
if (count($this->getPayments()) == 0 && !$payment->getSum()) {
|
|
||||||
$payment->setSum($this->calcTotal());
|
|
||||||
}
|
|
||||||
$this->payments->add($payment);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает массив оплат
|
|
||||||
*
|
|
||||||
* @return Payment[]
|
|
||||||
*/
|
|
||||||
public function getPayments(): array
|
|
||||||
{
|
|
||||||
return $this->payments->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает массив оплат
|
|
||||||
*
|
|
||||||
* @param Payment[] $payments Массив оплат
|
|
||||||
* @return $this
|
|
||||||
* @throws TooManyPaymentsException Слишком много оплат
|
|
||||||
*/
|
|
||||||
public function setPayments(array $payments): Document
|
|
||||||
{
|
|
||||||
$this->payments->set($payments);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавляет новый предмет расчёта в массив предметов расчёта
|
|
||||||
*
|
|
||||||
* @param Item $item Объект предмета расчёта
|
|
||||||
* @return $this
|
|
||||||
* @throws TooManyItemsException Слишком много предметов расчёта
|
|
||||||
*/
|
|
||||||
public function addItem(Item $item): Document
|
|
||||||
{
|
|
||||||
$this->items->add($item);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает массив предметов расчёта
|
|
||||||
*
|
|
||||||
* @return Item[]
|
|
||||||
*/
|
|
||||||
public function getItems(): array
|
|
||||||
{
|
|
||||||
return $this->items->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает массив предметов расчёта
|
|
||||||
*
|
|
||||||
* @param Item[] $items Массив предметов расчёта
|
|
||||||
* @return $this
|
|
||||||
* @throws TooManyItemsException Слишком много предметов расчёта
|
|
||||||
*/
|
|
||||||
public function setItems(array $items): Document
|
|
||||||
{
|
|
||||||
$this->items->set($items);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает заданного клиента (покупателя)
|
|
||||||
*
|
|
||||||
* @return Client|null
|
|
||||||
*/
|
|
||||||
public function getClient(): ?Client
|
|
||||||
{
|
|
||||||
return $this->client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает клиента (покупателя)
|
|
||||||
*
|
|
||||||
* @param Client|null $client
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setClient(?Client $client): Document
|
|
||||||
{
|
|
||||||
$this->client = $client;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает заданную компанию (продавца)
|
|
||||||
*
|
|
||||||
* @return Company|null
|
|
||||||
*/
|
|
||||||
public function getCompany(): ?Company
|
|
||||||
{
|
|
||||||
return $this->company;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает компанию (продавца)
|
|
||||||
*
|
|
||||||
* @param Company|null $company
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setCompany(?Company $company): Document
|
|
||||||
{
|
|
||||||
$this->company = $company;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает ФИО кассира. Тег ФФД - 1021.
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getCashier(): ?string
|
|
||||||
{
|
|
||||||
return $this->cashier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает ФИО кассира. Тег ФФД - 1021.
|
|
||||||
*
|
|
||||||
* @param string|null $cashier
|
|
||||||
* @return $this
|
|
||||||
* @throws TooLongCashierException
|
|
||||||
*/
|
|
||||||
public function setCashier(?string $cashier): Document
|
|
||||||
{
|
|
||||||
if ($cashier !== null) {
|
|
||||||
$cashier = trim($cashier);
|
|
||||||
if (mb_strlen($cashier) > Constraints::MAX_LENGTH_CASHIER_NAME) {
|
|
||||||
throw new TooLongCashierException($cashier, Constraints::MAX_LENGTH_CASHIER_NAME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->cashier = $cashier;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает данные коррекции
|
|
||||||
*
|
|
||||||
* @return CorrectionInfo|null
|
|
||||||
*/
|
|
||||||
public function getCorrectionInfo(): ?CorrectionInfo
|
|
||||||
{
|
|
||||||
return $this->correction_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает данные коррекции
|
|
||||||
*
|
|
||||||
* @param CorrectionInfo|null $correction_info
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setCorrectionInfo(?CorrectionInfo $correction_info): Document
|
|
||||||
{
|
|
||||||
$this->correction_info = $correction_info;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Пересчитывает, сохраняет и возвращает итоговую сумму чека по всем позициям (включая НДС). Тег ФФД - 1020.
|
|
||||||
*
|
|
||||||
* @return float
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public function calcTotal(): float
|
|
||||||
{
|
|
||||||
$sum = 0;
|
|
||||||
$this->clearVats();
|
|
||||||
foreach ($this->items->get() as $item) {
|
|
||||||
$sum += $item->calcSum();
|
|
||||||
$this->addVat(new Vat($item->getVat()->getType(), $item->getSum()));
|
|
||||||
}
|
|
||||||
return $this->total = round($sum, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает итоговую сумму чека. Тег ФФД - 1020.
|
|
||||||
*
|
|
||||||
* @return float
|
|
||||||
*/
|
|
||||||
public function getTotal(): float
|
|
||||||
{
|
|
||||||
return $this->total;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Собирает объект документа из сырой json-строки
|
|
||||||
*
|
|
||||||
* @param string $json
|
|
||||||
* @return Document
|
|
||||||
* @throws TooLongEmailException
|
|
||||||
* @throws InvalidEmailException
|
|
||||||
* @throws AtolException
|
|
||||||
* @throws InvalidInnLengthException
|
|
||||||
* @throws InvalidJsonException
|
|
||||||
* @throws TooLongItemNameException
|
|
||||||
* @throws TooLongPaymentAddressException
|
|
||||||
* @throws TooLongClientContactException
|
|
||||||
* @throws TooHighPriceException
|
|
||||||
* @throws TooManyException
|
|
||||||
* @throws TooManyItemsException
|
|
||||||
* @throws TooManyPaymentsException
|
|
||||||
* @throws TooLongMeasurementUnitException
|
|
||||||
* @throws TooLongUserdataException
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public static function fromRaw(string $json): Document
|
|
||||||
{
|
|
||||||
$array = json_decode($json, true);
|
|
||||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
||||||
throw new InvalidJsonException();
|
|
||||||
}
|
|
||||||
$doc = new self();
|
|
||||||
if (isset($array['company'])) {
|
|
||||||
$doc->setCompany(new Company(
|
|
||||||
$array['company']['sno'] ?? null,
|
|
||||||
$array['company']['inn'] ?? null,
|
|
||||||
$array['company']['payment_address'] ?? null,
|
|
||||||
$array['company']['email'] ?? null
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if (isset($array['client'])) {
|
|
||||||
$doc->setClient(new Client(
|
|
||||||
$array['client']['name'] ?? null,
|
|
||||||
$array['client']['phone'] ?? null,
|
|
||||||
$array['client']['email'] ?? null,
|
|
||||||
$array['client']['inn'] ?? null
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if (isset($array['correction_info'])) {
|
|
||||||
$doc->setCorrectionInfo(new CorrectionInfo(
|
|
||||||
$array['correction_info']['type'] ?? null,
|
|
||||||
$array['correction_info']['base_date'] ?? null,
|
|
||||||
$array['correction_info']['base_number'] ?? null,
|
|
||||||
$array['correction_info']['base_name'] ?? null,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if (isset($array['items'])) {
|
|
||||||
foreach ($array['items'] as $ar_item) {
|
|
||||||
$item = new Item(
|
|
||||||
$ar_item['name'] ?? null,
|
|
||||||
$ar_item['price'] ?? null,
|
|
||||||
$ar_item['quantity'] ?? null,
|
|
||||||
$ar_item['measurement_unit'] ?? null,
|
|
||||||
$ar_item['vat']['type'] ?? null,
|
|
||||||
$ar_item['payment_object'] ?? null,
|
|
||||||
$ar_item['payment_method'] ?? null
|
|
||||||
);
|
|
||||||
if (!empty($ar_item['user_data'])) {
|
|
||||||
$item->setUserData($ar_item['user_data'] ?? null);
|
|
||||||
}
|
|
||||||
$doc->addItem($item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isset($array['payments'])) {
|
|
||||||
foreach ($array['payments'] as $ar_payment) {
|
|
||||||
$payment = new Payment();
|
|
||||||
if (isset($ar_payment['type'])) {
|
|
||||||
$payment->setType($ar_payment['type']);
|
|
||||||
}
|
|
||||||
if (isset($ar_payment['sum'])) {
|
|
||||||
$payment->setSum($ar_payment['sum']);
|
|
||||||
}
|
|
||||||
$doc->payments->add($payment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isset($array['vats'])) {
|
|
||||||
foreach ($array['vats'] as $vat_payment) {
|
|
||||||
$vat = new Vat();
|
|
||||||
if (isset($vat_payment['type'])) {
|
|
||||||
$vat->setType($vat_payment['type']);
|
|
||||||
}
|
|
||||||
if (isset($vat_payment['sum'])) {
|
|
||||||
$vat->setSum($vat_payment['sum']);
|
|
||||||
}
|
|
||||||
$doc->vats->add($vat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isset($array['total']) && $array['total'] != $doc->calcTotal()) {
|
|
||||||
throw new AtolException('Real total sum not equals to provided in JSON one');
|
|
||||||
}
|
|
||||||
return $doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает массив для кодирования в json
|
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public function jsonSerialize(): array
|
|
||||||
{
|
|
||||||
if ($this->getCompany()) {
|
|
||||||
$json['company'] = $this->getCompany()->jsonSerialize(); // обязательно
|
|
||||||
}
|
|
||||||
if ($this->getPayments()) {
|
|
||||||
$json['payments'] = $this->payments->jsonSerialize(); // обязательно
|
|
||||||
}
|
|
||||||
if ($this->getCashier()) {
|
|
||||||
$json['cashier'] = $this->getCashier();
|
|
||||||
}
|
|
||||||
if ($this->getCorrectionInfo()) {
|
|
||||||
$json['correction_info'] = $this->getCorrectionInfo()->jsonSerialize(); // обязательно для коррекционных
|
|
||||||
} else {
|
|
||||||
if ($this->getClient()) {
|
|
||||||
$json['client'] = $this->getClient()->jsonSerialize(); // обязательно для некоррекционных
|
|
||||||
}
|
|
||||||
if ($this->getItems()) {
|
|
||||||
$json['items'] = $this->items->jsonSerialize(); // обязательно для некоррекционных
|
|
||||||
}
|
|
||||||
$json['total'] = $this->calcTotal(); // обязательно для некоррекционных
|
|
||||||
}
|
|
||||||
if ($this->getVats()) {
|
|
||||||
$json['vats'] = $this->vats->jsonSerialize();
|
|
||||||
}
|
|
||||||
return $json;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,18 +7,44 @@
|
|||||||
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** @noinspection PhpMultipleClassDeclarationsInspection */
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types = 1);
|
||||||
|
|
||||||
namespace AtolOnline\Entities;
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
|
use ArrayAccess;
|
||||||
|
use BadMethodCallException;
|
||||||
|
use Illuminate\Contracts\Support\Arrayable;
|
||||||
|
use JetBrains\PhpStorm\ArrayShape;
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
use Stringable;
|
use Stringable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Абстрактное описание любой сущности, представляемой как json
|
* Абстрактное описание любой сущности, представляемой как json
|
||||||
*/
|
*/
|
||||||
abstract class Entity implements JsonSerializable, Stringable
|
abstract class Entity implements JsonSerializable, Stringable, Arrayable, ArrayAccess
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
abstract public function jsonSerialize(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
#[ArrayShape([
|
||||||
|
'company' => "\AtolOnline\Entities\Company",
|
||||||
|
'correction_info' => "\AtolOnline\Entities\CorrectionInfo",
|
||||||
|
'payments' => "array",
|
||||||
|
'vats' => "\AtolOnline\Collections\Vats|null",
|
||||||
|
'cashier' => "null|string",
|
||||||
|
])]
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
return $this->jsonSerialize();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает строковое представление json-структуры объекта
|
* Возвращает строковое представление json-структуры объекта
|
||||||
*
|
*
|
||||||
@@ -26,6 +52,42 @@ abstract class Entity implements JsonSerializable, Stringable
|
|||||||
*/
|
*/
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
return json_encode($this->jsonSerialize(), JSON_UNESCAPED_UNICODE);
|
return json_encode($this->toArray(), JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function offsetExists(mixed $offset): bool
|
||||||
|
{
|
||||||
|
return isset($this->toArray()[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function offsetGet(mixed $offset): mixed
|
||||||
|
{
|
||||||
|
return $this->toArray()[$offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function offsetSet(mixed $offset, mixed $value)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException(
|
||||||
|
'Объект ' . static::class . ' нельзя изменять как массив. Следует использовать сеттеры.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function offsetUnset(mixed $offset): void
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException(
|
||||||
|
'Объект ' . static::class . ' нельзя изменять как массив. Следует использовать сеттеры.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,25 +11,28 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Entities;
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
use AtolOnline\{
|
use AtolOnline\Constants\Constraints;
|
||||||
Constants\Constraints,
|
use AtolOnline\Enums\{
|
||||||
Enums\PaymentMethods,
|
PaymentMethods,
|
||||||
Enums\PaymentObjects,
|
PaymentObjects,
|
||||||
Enums\VatTypes,
|
VatTypes
|
||||||
Exceptions\EmptyItemNameException,
|
};
|
||||||
Exceptions\InvalidDeclarationNumberException,
|
use AtolOnline\Exceptions\{
|
||||||
Exceptions\InvalidEnumValueException,
|
EmptyItemNameException,
|
||||||
Exceptions\InvalidOKSMCodeException,
|
InvalidDeclarationNumberException,
|
||||||
Exceptions\NegativeItemExciseException,
|
InvalidEnumValueException,
|
||||||
Exceptions\NegativeItemPriceException,
|
InvalidOKSMCodeException,
|
||||||
Exceptions\NegativeItemQuantityException,
|
NegativeItemExciseException,
|
||||||
Exceptions\TooHighItemQuantityException,
|
NegativeItemPriceException,
|
||||||
Exceptions\TooHighPriceException,
|
NegativeItemQuantityException,
|
||||||
Exceptions\TooHighSumException,
|
TooHighItemPriceException,
|
||||||
Exceptions\TooLongItemNameException,
|
TooHighItemQuantityException,
|
||||||
Exceptions\TooLongMeasurementUnitException,
|
TooHighItemSumException,
|
||||||
Exceptions\TooLongUserdataException,
|
TooLongItemCodeException,
|
||||||
Exceptions\TooManyException
|
TooLongItemNameException,
|
||||||
|
TooLongMeasurementUnitException,
|
||||||
|
TooLongUserdataException,
|
||||||
|
TooManyException
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +40,7 @@ use AtolOnline\{
|
|||||||
*
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21-30
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21-30
|
||||||
*/
|
*/
|
||||||
class Item extends Entity
|
final class Item extends Entity
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string Наименование (1030)
|
* @var string Наименование (1030)
|
||||||
@@ -59,6 +62,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)
|
||||||
*/
|
*/
|
||||||
@@ -111,7 +124,7 @@ class Item extends Entity
|
|||||||
* @param float|null $price Цена за одну единицу
|
* @param float|null $price Цена за одну единицу
|
||||||
* @param float|null $quantity Количество
|
* @param float|null $quantity Количество
|
||||||
* @throws TooLongItemNameException
|
* @throws TooLongItemNameException
|
||||||
* @throws TooHighPriceException
|
* @throws TooHighItemPriceException
|
||||||
* @throws TooManyException
|
* @throws TooManyException
|
||||||
* @throws NegativeItemPriceException
|
* @throws NegativeItemPriceException
|
||||||
* @throws EmptyItemNameException
|
* @throws EmptyItemNameException
|
||||||
@@ -142,7 +155,7 @@ class Item extends Entity
|
|||||||
*
|
*
|
||||||
* @param string $name Наименование
|
* @param string $name Наименование
|
||||||
* @return $this
|
* @return $this
|
||||||
* @throws TooLongItemNameException Слишком длинное имя/наименование
|
* @throws TooLongItemNameException
|
||||||
* @throws EmptyItemNameException
|
* @throws EmptyItemNameException
|
||||||
*/
|
*/
|
||||||
public function setName(string $name): self
|
public function setName(string $name): self
|
||||||
@@ -171,21 +184,23 @@ class Item extends Entity
|
|||||||
/**
|
/**
|
||||||
* Устанавливает цену в рублях
|
* Устанавливает цену в рублях
|
||||||
*
|
*
|
||||||
* @param float $rubles
|
* @param float $price
|
||||||
* @return $this
|
* @return $this
|
||||||
* @throws NegativeItemPriceException
|
* @throws NegativeItemPriceException
|
||||||
* @throws TooHighPriceException
|
* @throws TooHighItemPriceException
|
||||||
|
* @throws TooHighItemSumException
|
||||||
*/
|
*/
|
||||||
public function setPrice(float $rubles): self
|
public function setPrice(float $price): self
|
||||||
{
|
{
|
||||||
if ($rubles > Constraints::MAX_COUNT_ITEM_PRICE) {
|
$price = round($price, 2);
|
||||||
throw new TooHighPriceException($this->getName(), $rubles);
|
if ($price > Constraints::MAX_COUNT_ITEM_PRICE) {
|
||||||
|
throw new TooHighItemPriceException($this->getName(), $price);
|
||||||
}
|
}
|
||||||
if ($rubles < 0) {
|
if ($price < 0) {
|
||||||
throw new NegativeItemPriceException($this->getName(), $rubles);
|
throw new NegativeItemPriceException($this->getName(), $price);
|
||||||
}
|
}
|
||||||
$this->price = $rubles;
|
$this->price = $price;
|
||||||
//$this->calcSum();
|
$this->getVat()?->setSum($this->getSum());
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +221,7 @@ class Item extends Entity
|
|||||||
* @return $this
|
* @return $this
|
||||||
* @throws TooHighItemQuantityException
|
* @throws TooHighItemQuantityException
|
||||||
* @throws NegativeItemQuantityException
|
* @throws NegativeItemQuantityException
|
||||||
|
* @throws TooHighItemSumException
|
||||||
*/
|
*/
|
||||||
public function setQuantity(float $quantity): self
|
public function setQuantity(float $quantity): self
|
||||||
{
|
{
|
||||||
@@ -217,6 +233,7 @@ class Item extends Entity
|
|||||||
throw new NegativeItemQuantityException($this->getName(), $quantity);
|
throw new NegativeItemQuantityException($this->getName(), $quantity);
|
||||||
}
|
}
|
||||||
$this->quantity = $quantity;
|
$this->quantity = $quantity;
|
||||||
|
$this->getVat()?->setSum($this->getSum());
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,13 +241,13 @@ class Item extends Entity
|
|||||||
* Возвращает стоимость (цена * количество + акциз)
|
* Возвращает стоимость (цена * количество + акциз)
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
* @throws TooHighSumException
|
* @throws TooHighItemSumException
|
||||||
*/
|
*/
|
||||||
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 TooHighItemSumException($this->getName(), $sum);
|
||||||
}
|
}
|
||||||
return $sum;
|
return $sum;
|
||||||
}
|
}
|
||||||
@@ -262,6 +279,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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает признак способа оплаты
|
* Возвращает признак способа оплаты
|
||||||
*
|
*
|
||||||
@@ -327,7 +387,7 @@ class Item extends Entity
|
|||||||
*
|
*
|
||||||
* @param Vat|string|null $vat Объект ставки, одно из значений VatTypes или null для удаления ставки
|
* @param Vat|string|null $vat Объект ставки, одно из значений VatTypes или null для удаления ставки
|
||||||
* @return $this
|
* @return $this
|
||||||
* @throws TooHighSumException
|
* @throws TooHighItemSumException
|
||||||
* @throws InvalidEnumValueException
|
* @throws InvalidEnumValueException
|
||||||
*/
|
*/
|
||||||
public function setVat(Vat|string|null $vat): self
|
public function setVat(Vat|string|null $vat): self
|
||||||
@@ -403,7 +463,7 @@ class Item extends Entity
|
|||||||
*
|
*
|
||||||
* @param string|null $user_data Дополнительный реквизит
|
* @param string|null $user_data Дополнительный реквизит
|
||||||
* @return $this
|
* @return $this
|
||||||
* @throws TooLongUserdataException Слишком длинный дополнительный реквизит
|
* @throws TooLongUserdataException
|
||||||
*/
|
*/
|
||||||
public function setUserData(?string $user_data): self
|
public function setUserData(?string $user_data): self
|
||||||
{
|
{
|
||||||
@@ -431,13 +491,15 @@ class Item extends Entity
|
|||||||
* @param float|null $excise
|
* @param float|null $excise
|
||||||
* @return Item
|
* @return Item
|
||||||
* @throws NegativeItemExciseException
|
* @throws NegativeItemExciseException
|
||||||
|
* @throws TooHighItemSumException
|
||||||
*/
|
*/
|
||||||
public function setExcise(?float $excise): Item
|
public function setExcise(?float $excise): self
|
||||||
{
|
{
|
||||||
if ($excise < 0) {
|
if ($excise < 0) {
|
||||||
throw new NegativeItemExciseException($this->getName(), $excise);
|
throw new NegativeItemExciseException($this->getName(), $excise);
|
||||||
}
|
}
|
||||||
$this->excise = $excise;
|
$this->excise = $excise;
|
||||||
|
$this->getVat()?->setSum($this->getSum());
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,8 +556,8 @@ class Item extends Entity
|
|||||||
if (is_string($declaration_number)) {
|
if (is_string($declaration_number)) {
|
||||||
$declaration_number = trim($declaration_number);
|
$declaration_number = trim($declaration_number);
|
||||||
if (
|
if (
|
||||||
mb_strlen($declaration_number) < Constraints::MIN_LENGTH_DECLARATION_NUMBER ||
|
mb_strlen($declaration_number) < Constraints::MIN_LENGTH_DECLARATION_NUMBER
|
||||||
mb_strlen($declaration_number) > Constraints::MAX_LENGTH_DECLARATION_NUMBER
|
|| mb_strlen($declaration_number) > Constraints::MAX_LENGTH_DECLARATION_NUMBER
|
||||||
) {
|
) {
|
||||||
throw new InvalidDeclarationNumberException($declaration_number);
|
throw new InvalidDeclarationNumberException($declaration_number);
|
||||||
}
|
}
|
||||||
@@ -504,28 +566,9 @@ class Item extends Entity
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Расчитывает стоимость и размер НДС на неё
|
|
||||||
*
|
|
||||||
* @return float
|
|
||||||
* @throws TooHighPriceException Слишком большая сумма
|
|
||||||
*/
|
|
||||||
//public function calcSum(): float
|
|
||||||
//{
|
|
||||||
// $sum = $this->quantity * $this->price;
|
|
||||||
// if (rubles($sum) > 42949672.95) {
|
|
||||||
// throw new TooHighPriceException($sum, 42949672.95);
|
|
||||||
// }
|
|
||||||
// $this->sum = $sum;
|
|
||||||
// if ($this->vat) {
|
|
||||||
// $this->vat->setSum(rubles($sum));
|
|
||||||
// }
|
|
||||||
// return $this->getSum();
|
|
||||||
//}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
* @throws TooHighSumException
|
* @throws TooHighItemSumException
|
||||||
*/
|
*/
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
@@ -536,6 +579,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 +589,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,41 +11,43 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Entities;
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
use AtolOnline\Exceptions\EmptyMonitorDataException;
|
use AtolOnline\Exceptions\{
|
||||||
use AtolOnline\Exceptions\NotEnoughMonitorDataException;
|
EmptyMonitorDataException,
|
||||||
|
NotEnoughMonitorDataException};
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс сущности ККТ, получаемой от монитора
|
* Класс сущности ККТ, получаемой от монитора
|
||||||
*
|
*
|
||||||
* @property string|null serialNumber Заводской номер ККТ
|
|
||||||
* @property string|null registrationNumber Регистрационный номер машины (РНМ)
|
|
||||||
* @property string|null deviceNumber Номер автоматического устройства (внутренний идентификатор устройства)
|
|
||||||
* @property DateTime|string|null fiscalizationDate Дата активации (фискализации) ФН с указанием таймзоны
|
|
||||||
* @property DateTime|string|null fiscalStorageExpiration Дата замены ФН (Срок действия ФН), с указанием таймзоны
|
|
||||||
* @property int|null signedDocuments Количество подписанных документов в ФН
|
|
||||||
* @property float|null fiscalStoragePercentageUse Наполненость ФН в %
|
|
||||||
* @property string|null fiscalStorageINN ИНН компании (указанный в ФН)
|
|
||||||
* @property string|null fiscalStorageSerialNumber Заводской (серийный) номер ФН
|
|
||||||
* @property string|null fiscalStoragePaymentAddress Адрес расчёта, указанный в ФН
|
|
||||||
* @property string|null groupCode Код группы кассы
|
|
||||||
* @property DateTime|string|null timestamp Время и дата формирования данных, UTC
|
|
||||||
* @property bool|null isShiftOpened Признак открыта смена (true) или закрыта (false)
|
|
||||||
* @property int|null shiftNumber Номер смены (или "Номер закрытой смены", когда смена закрыта)
|
|
||||||
* @property int|null shiftReceipt Номер документа за смену (или "Кол-во чеков закрытой смены", когда смена закрыта)
|
|
||||||
* @property int|null unsentDocs Количество неотправленных документов. Указывается, если значение отлично от 0.
|
|
||||||
* @property DateTime|string|null firstUnsetDocTimestamp Дата первого неотправленного документа. Указывается, если
|
|
||||||
* есть неотправленные документы.
|
|
||||||
* @property int|null networkErrorCode Код ошибки сети
|
|
||||||
* @see https://online.atol.ru/files/API_service_information.pdf Документация, стр 11
|
* @see https://online.atol.ru/files/API_service_information.pdf Документация, стр 11
|
||||||
|
* @property-read string|null serialNumber Заводской номер ККТ
|
||||||
|
* @property-read string|null registrationNumber Регистрационный номер машины (РНМ)
|
||||||
|
* @property-read string|null deviceNumber Номер автоматического устройства (внутренний идентификатор устройства)
|
||||||
|
* @property-read DateTime|string|null fiscalizationDate Дата активации (фискализации) ФН с указанием таймзоны
|
||||||
|
* @property-read DateTime|string|null fiscalStorageExpiration Дата замены ФН (Срок действия ФН), с указанием таймзоны
|
||||||
|
* @property-read int|null signedDocuments Количество подписанных документов в ФН
|
||||||
|
* @property-read float|null fiscalStoragePercentageUse Наполненость ФН в %
|
||||||
|
* @property-read string|null fiscalStorageINN ИНН компании (указанный в ФН)
|
||||||
|
* @property-read string|null fiscalStorageSerialNumber Заводской (серийный) номер ФН
|
||||||
|
* @property-read string|null fiscalStoragePaymentAddress Адрес расчёта, указанный в ФН
|
||||||
|
* @property-read string|null groupCode Код группы кассы
|
||||||
|
* @property-read DateTime|string|null timestamp Время и дата формирования данных, UTC
|
||||||
|
* @property-read bool|null isShiftOpened Признак открыта смена (true) или закрыта (false)
|
||||||
|
* @property-read int|null shiftNumber Номер смены (или "Номер закрытой смены", когда смена закрыта)
|
||||||
|
* @property-read int|null shiftReceipt Номер документа за смену (или "Кол-во чеков закрытой смены", когда смена
|
||||||
|
* закрыта)
|
||||||
|
* @property-read int|null unsentDocs Количество неотправленных документов. Указывается, если значение отлично от 0.
|
||||||
|
* @property-read DateTime|string|null firstUnsetDocTimestamp Дата первого неотправленного документа. Указывается, если
|
||||||
|
* есть неотправленные документы.
|
||||||
|
* @property-read int|null networkErrorCode Код ошибки сети
|
||||||
*/
|
*/
|
||||||
final class Kkt extends Entity
|
final class Kkt extends Entity
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Сопоставление кодов сетевых ошибок ККТ с их описаниями
|
* Сопоставление кодов сетевых ошибок ККТ с их описаниями
|
||||||
*/
|
*/
|
||||||
public const ERROR_CODES = [
|
public const ERROR_CODES = [
|
||||||
0 => 'Нет ошибок',
|
0 => 'Нет ошибок',
|
||||||
1 => 'Отсутствует физический канал связи',
|
1 => 'Отсутствует физический канал связи',
|
||||||
2 => 'Ошибка сетевых настроек или нет соединения с сервером ОФД',
|
2 => 'Ошибка сетевых настроек или нет соединения с сервером ОФД',
|
||||||
@@ -97,7 +99,7 @@ final class Kkt extends Entity
|
|||||||
* @throws EmptyMonitorDataException
|
* @throws EmptyMonitorDataException
|
||||||
* @throws NotEnoughMonitorDataException
|
* @throws NotEnoughMonitorDataException
|
||||||
*/
|
*/
|
||||||
public function __construct(protected \stdClass $data)
|
public function __construct(protected object $data)
|
||||||
{
|
{
|
||||||
if (empty((array)$data)) {
|
if (empty((array)$data)) {
|
||||||
throw new EmptyMonitorDataException();
|
throw new EmptyMonitorDataException();
|
||||||
|
|||||||
@@ -11,9 +11,14 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Entities;
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
use AtolOnline\Constants\Constraints;
|
use AtolOnline\Exceptions\{
|
||||||
use AtolOnline\Exceptions\InvalidInnLengthException;
|
InvalidInnLengthException,
|
||||||
use AtolOnline\Exceptions\InvalidPhoneException;
|
InvalidPhoneException
|
||||||
|
};
|
||||||
|
use AtolOnline\Traits\{
|
||||||
|
HasInn,
|
||||||
|
HasPhones
|
||||||
|
};
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,8 +26,10 @@ use Illuminate\Support\Collection;
|
|||||||
*
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 28
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 28
|
||||||
*/
|
*/
|
||||||
class MoneyTransferOperator extends Entity
|
final class MoneyTransferOperator extends Entity
|
||||||
{
|
{
|
||||||
|
use HasInn, HasPhones;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null Наименование (1026)
|
* @var string|null Наименование (1026)
|
||||||
*/
|
*/
|
||||||
@@ -111,69 +118,6 @@ class MoneyTransferOperator extends Entity
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает установленные номера телефонов
|
|
||||||
*
|
|
||||||
* @todo вытащить в трейт
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function getPhones(): Collection
|
|
||||||
{
|
|
||||||
return $this->phones;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает массив номеров телефонов
|
|
||||||
*
|
|
||||||
* @todo вытащить в трейт
|
|
||||||
* @param array|Collection|null $phones
|
|
||||||
* @return $this
|
|
||||||
* @throws InvalidPhoneException
|
|
||||||
*/
|
|
||||||
public function setPhones(array|Collection|null $phones): self
|
|
||||||
{
|
|
||||||
if (!is_null($phones)) {
|
|
||||||
$phones = is_array($phones) ? collect($phones) : $phones;
|
|
||||||
$phones->each(function ($phone) {
|
|
||||||
$phone = preg_replace('/[^\d]/', '', trim($phone));
|
|
||||||
if (preg_match(Constraints::PATTERN_PHONE, $phone) != 1) {
|
|
||||||
throw new InvalidPhoneException($phone);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$this->phones = $phones ?? collect();
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает установленный ИНН
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getInn(): ?string
|
|
||||||
{
|
|
||||||
return $this->inn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает ИНН
|
|
||||||
*
|
|
||||||
* @param string|null $inn
|
|
||||||
* @return $this
|
|
||||||
* @throws InvalidInnLengthException Некорректная длина ИНН
|
|
||||||
*/
|
|
||||||
public function setInn(?string $inn): self
|
|
||||||
{
|
|
||||||
if (is_string($inn)) {
|
|
||||||
$inn = preg_replace('/[^\d]/', '', trim($inn));
|
|
||||||
if (preg_match_all(Constraints::PATTERN_INN, $inn) === 0) {
|
|
||||||
throw new InvalidInnLengthException($inn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->inn = $inn ?: null;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Entities;
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
use AtolOnline\Constants\Constraints;
|
use AtolOnline\Constants\Constraints;
|
||||||
use AtolOnline\Exceptions\InvalidPhoneException;
|
use AtolOnline\Exceptions\{
|
||||||
use AtolOnline\Exceptions\TooLongPayingAgentOperationException;
|
InvalidPhoneException,
|
||||||
|
TooLongPayingAgentOperationException};
|
||||||
|
use AtolOnline\Traits\HasPhones;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,18 +23,15 @@ use Illuminate\Support\Collection;
|
|||||||
*
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 19
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 19
|
||||||
*/
|
*/
|
||||||
class PayingAgent extends Entity
|
final class PayingAgent extends Entity
|
||||||
{
|
{
|
||||||
|
use HasPhones;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null Наименование операции (1044)
|
* @var string|null Наименование операции (1044)
|
||||||
*/
|
*/
|
||||||
protected ?string $operation = null;
|
protected ?string $operation = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Collection Телефоны платёжного агента (1073)
|
|
||||||
*/
|
|
||||||
protected Collection $phones;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конструктор
|
* Конструктор
|
||||||
*
|
*
|
||||||
@@ -64,7 +63,7 @@ class PayingAgent extends Entity
|
|||||||
throw new TooLongPayingAgentOperationException($operation);
|
throw new TooLongPayingAgentOperationException($operation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->operation = empty($operation) ? null : $operation;
|
$this->operation = $operation ?: null;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,40 +77,6 @@ class PayingAgent extends Entity
|
|||||||
return $this->operation;
|
return $this->operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает массив номеров телефонов
|
|
||||||
*
|
|
||||||
* @todo вытащить в трейт
|
|
||||||
* @param array|Collection|null $phones
|
|
||||||
* @return $this
|
|
||||||
* @throws InvalidPhoneException
|
|
||||||
*/
|
|
||||||
public function setPhones(array|Collection|null $phones): self
|
|
||||||
{
|
|
||||||
if (!is_null($phones)) {
|
|
||||||
$phones = is_array($phones) ? collect($phones) : $phones;
|
|
||||||
$phones->each(function ($phone) {
|
|
||||||
$phone = preg_replace('/[^\d]/', '', trim($phone));
|
|
||||||
if (preg_match(Constraints::PATTERN_PHONE, $phone) != 1) {
|
|
||||||
throw new InvalidPhoneException($phone);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$this->phones = empty($phones) ? collect() : $phones;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает установленные номера телефонов
|
|
||||||
*
|
|
||||||
* @todo вытащить в трейт
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function getPhones(): Collection
|
|
||||||
{
|
|
||||||
return $this->phones;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -11,39 +11,53 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Entities;
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
use AtolOnline\Enums\PaymentTypes;
|
use AtolOnline\{
|
||||||
|
Constants\Constraints,
|
||||||
|
Enums\PaymentTypes,
|
||||||
|
};
|
||||||
|
use AtolOnline\Exceptions\{
|
||||||
|
InvalidEnumValueException,
|
||||||
|
NegativePaymentSumException,
|
||||||
|
TooHighPaymentSumException,
|
||||||
|
};
|
||||||
|
use JetBrains\PhpStorm\{
|
||||||
|
ArrayShape,
|
||||||
|
Pure
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс, описывающий оплату. Тег ФФД - 1031, 1081, 1215, 1216, 1217.
|
* Класс, описывающий оплату
|
||||||
*
|
*
|
||||||
* @package AtolOnline\Entities
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 30
|
||||||
*/
|
*/
|
||||||
class Payment extends Entity
|
final class Payment extends Entity
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var int Тип оплаты
|
* @var int Тип оплаты
|
||||||
*/
|
*/
|
||||||
protected int $type;
|
protected int $type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var float Сумма оплаты
|
* @var float Сумма оплаты (1031, 1081, 1215, 1216, 1217)
|
||||||
*/
|
*/
|
||||||
protected float $sum;
|
protected float $sum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payment constructor.
|
* Конструктор
|
||||||
*
|
*
|
||||||
* @param int $payment_type Тип оплаты
|
* @param int $type Тип оплаты
|
||||||
* @param float $sum Сумма оплаты
|
* @param float $sum Сумма оплаты
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
*/
|
*/
|
||||||
public function __construct(int $payment_type = PaymentTypes::ELECTRON, float $sum = 0.0)
|
public function __construct(int $type, float $sum)
|
||||||
{
|
{
|
||||||
$this->setType($payment_type);
|
$this->setType($type)->setSum($sum);
|
||||||
$this->setSum($sum);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает тип оплаты. Тег ФФД - 1031, 1081, 1215, 1216, 1217.
|
* Возвращает установленный тип оплаты
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@@ -51,21 +65,22 @@ class Payment extends Entity
|
|||||||
{
|
{
|
||||||
return $this->type;
|
return $this->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Устанавливает тип оплаты. Тег ФФД - 1031, 1081, 1215, 1216, 1217.
|
* Устанавливает тип оплаты
|
||||||
*
|
*
|
||||||
* @param int $type
|
* @param int $type
|
||||||
* @return $this
|
* @return $this
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
*/
|
*/
|
||||||
public function setType(int $type): Payment
|
public function setType(int $type): self
|
||||||
{
|
{
|
||||||
$this->type = $type;
|
PaymentTypes::isValid($type) && $this->type = $type;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает сумму оплаты
|
* Возвращает установленную сумму оплаты
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
@@ -73,23 +88,34 @@ class Payment extends Entity
|
|||||||
{
|
{
|
||||||
return $this->sum;
|
return $this->sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Устанавливает сумму оплаты
|
* Устанавливает сумму оплаты
|
||||||
*
|
*
|
||||||
* @param float $sum
|
* @param float $sum
|
||||||
* @return $this
|
* @return $this
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
*/
|
*/
|
||||||
public function setSum(float $sum): Payment
|
public function setSum(float $sum): self
|
||||||
{
|
{
|
||||||
|
$sum = round($sum, 2);
|
||||||
|
if ($sum > Constraints::MAX_COUNT_PAYMENT_SUM) {
|
||||||
|
throw new TooHighPaymentSumException($sum);
|
||||||
|
}
|
||||||
|
if ($sum < 0) {
|
||||||
|
throw new NegativePaymentSumException($sum);
|
||||||
|
}
|
||||||
$this->sum = $sum;
|
$this->sum = $sum;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function jsonSerialize()
|
#[Pure]
|
||||||
|
#[ArrayShape(['type' => 'int', 'sum' => 'float'])]
|
||||||
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'type' => $this->getType(),
|
'type' => $this->getType(),
|
||||||
|
|||||||
480
src/Entities/Receipt.php
Normal file
480
src/Entities/Receipt.php
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
<?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\Entities;
|
||||||
|
|
||||||
|
use AtolOnline\Api\AtolResponse;
|
||||||
|
use AtolOnline\Api\Fiscalizer;
|
||||||
|
use AtolOnline\Collections\Items;
|
||||||
|
use AtolOnline\Collections\Payments;
|
||||||
|
use AtolOnline\Collections\Vats;
|
||||||
|
use AtolOnline\Constants\Constraints;
|
||||||
|
use AtolOnline\Exceptions\AuthFailedException;
|
||||||
|
use AtolOnline\Exceptions\EmptyItemsException;
|
||||||
|
use AtolOnline\Exceptions\EmptyLoginException;
|
||||||
|
use AtolOnline\Exceptions\EmptyPasswordException;
|
||||||
|
use AtolOnline\Exceptions\InvalidEntityInCollectionException;
|
||||||
|
use AtolOnline\Exceptions\InvalidInnLengthException;
|
||||||
|
use AtolOnline\Exceptions\InvalidPaymentAddressException;
|
||||||
|
use AtolOnline\Exceptions\TooLongAddCheckPropException;
|
||||||
|
use AtolOnline\Exceptions\TooLongCashierException;
|
||||||
|
use AtolOnline\Exceptions\TooLongPaymentAddressException;
|
||||||
|
use Exception;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс, описывающий документ прихода, расхода, возврата прихода, возврата расхода
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 17
|
||||||
|
*/
|
||||||
|
final class Receipt extends Entity
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Тип документа
|
||||||
|
*/
|
||||||
|
public const DOC_TYPE = 'receipt';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Client Покупатель
|
||||||
|
*/
|
||||||
|
protected Client $client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo вынести в трейт?
|
||||||
|
* @var Company Продавец
|
||||||
|
*/
|
||||||
|
protected Company $company;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var AgentInfo|null Агент
|
||||||
|
*/
|
||||||
|
protected ?AgentInfo $agent_info = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Supplier|null Поставщик
|
||||||
|
*/
|
||||||
|
protected ?Supplier $supplier = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Items Коллекция предметов расчёта
|
||||||
|
*/
|
||||||
|
protected Items $items;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo вынести в трейт?
|
||||||
|
* @var Payments Коллекция оплат
|
||||||
|
*/
|
||||||
|
protected Payments $payments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Vats|null Коллекция ставок НДС
|
||||||
|
*/
|
||||||
|
protected ?Vats $vats = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float Итоговая сумма чека
|
||||||
|
*/
|
||||||
|
protected float $total = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo вынести в трейт?
|
||||||
|
* @var string|null ФИО кассира
|
||||||
|
*/
|
||||||
|
protected ?string $cashier = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null Дополнительный реквизит
|
||||||
|
*/
|
||||||
|
protected ?string $add_check_props = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var AdditionalUserProps|null Дополнительный реквизит пользователя
|
||||||
|
*/
|
||||||
|
protected ?AdditionalUserProps $add_user_props = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param Client $client
|
||||||
|
* @param Company $company
|
||||||
|
* @param Items $items
|
||||||
|
* @param Payments $payments
|
||||||
|
* @throws EmptyItemsException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
*/
|
||||||
|
public function __construct(Client $client, Company $company, Items $items, Payments $payments)
|
||||||
|
{
|
||||||
|
$this->setClient($client)->setCompany($company)->setItems($items)->setPayments($payments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленного покупателя
|
||||||
|
*
|
||||||
|
* @return Client
|
||||||
|
*/
|
||||||
|
public function getClient(): Client
|
||||||
|
{
|
||||||
|
return $this->client;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает покупателя
|
||||||
|
*
|
||||||
|
* @param Client $client
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setClient(Client $client): self
|
||||||
|
{
|
||||||
|
$this->client = $client;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленного продавца
|
||||||
|
*
|
||||||
|
* @return Company
|
||||||
|
*/
|
||||||
|
public function getCompany(): Company
|
||||||
|
{
|
||||||
|
return $this->company;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает продавца
|
||||||
|
*
|
||||||
|
* @param Company $company
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setCompany(Company $company): self
|
||||||
|
{
|
||||||
|
$this->company = $company;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленного агента
|
||||||
|
*
|
||||||
|
* @return AgentInfo|null
|
||||||
|
*/
|
||||||
|
public function getAgentInfo(): ?AgentInfo
|
||||||
|
{
|
||||||
|
return $this->agent_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает агента
|
||||||
|
*
|
||||||
|
* @param AgentInfo|null $agent_info
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setAgentInfo(?AgentInfo $agent_info): self
|
||||||
|
{
|
||||||
|
$this->agent_info = $agent_info;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поставщика
|
||||||
|
*
|
||||||
|
* @return Supplier|null
|
||||||
|
*/
|
||||||
|
public function getSupplier(): ?Supplier
|
||||||
|
{
|
||||||
|
return $this->supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поставщика
|
||||||
|
*
|
||||||
|
* @param Supplier|null $supplier
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setSupplier(?Supplier $supplier): self
|
||||||
|
{
|
||||||
|
$this->supplier = $supplier;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленную коллекцию предметов расчёта
|
||||||
|
*
|
||||||
|
* @return Items
|
||||||
|
*/
|
||||||
|
public function getItems(): Items
|
||||||
|
{
|
||||||
|
return $this->items ?? new Items();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает коллекцию предметов расчёта
|
||||||
|
*
|
||||||
|
* @param Items $items
|
||||||
|
* @return $this
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws Exception
|
||||||
|
* @throws EmptyItemsException
|
||||||
|
*/
|
||||||
|
public function setItems(Items $items): self
|
||||||
|
{
|
||||||
|
$items->checkCount();
|
||||||
|
$items->checkItemsClasses();
|
||||||
|
$this->items = $items;
|
||||||
|
$this->getItems()->each(fn($item) => $this->total += $item->getSum());
|
||||||
|
$this->total = round($this->total, 2);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленную коллекцию оплат
|
||||||
|
*
|
||||||
|
* @return Payments
|
||||||
|
*/
|
||||||
|
public function getPayments(): Payments
|
||||||
|
{
|
||||||
|
return $this->payments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает коллекцию оплат
|
||||||
|
*
|
||||||
|
* @param Payments $payments
|
||||||
|
* @return $this
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
*/
|
||||||
|
public function setPayments(Payments $payments): self
|
||||||
|
{
|
||||||
|
$payments->checkCount();
|
||||||
|
$payments->checkItemsClasses();
|
||||||
|
$this->payments = $payments;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленную коллекцию ставок НДС
|
||||||
|
*
|
||||||
|
* @return Vats|null
|
||||||
|
*/
|
||||||
|
public function getVats(): ?Vats
|
||||||
|
{
|
||||||
|
return $this->vats ?? new Vats();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает коллекцию ставок НДС
|
||||||
|
*
|
||||||
|
* @param Vats|null $vats
|
||||||
|
* @return $this
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function setVats(?Vats $vats): self
|
||||||
|
{
|
||||||
|
$vats->checkCount();
|
||||||
|
$vats->checkItemsClasses();
|
||||||
|
$this->vats = $vats;
|
||||||
|
/** @var Vat $vat */
|
||||||
|
$this->getVats()->each(fn($vat) => $vat->setSum($this->getTotal()));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает полную сумму чека
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
public function getTotal(): float
|
||||||
|
{
|
||||||
|
return $this->total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленного кассира
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getCashier(): ?string
|
||||||
|
{
|
||||||
|
return $this->cashier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает кассира
|
||||||
|
*
|
||||||
|
* @param string|null $cashier
|
||||||
|
* @return $this
|
||||||
|
* @throws TooLongCashierException
|
||||||
|
*/
|
||||||
|
public function setCashier(?string $cashier): self
|
||||||
|
{
|
||||||
|
if (is_string($cashier)) {
|
||||||
|
$cashier = trim($cashier);
|
||||||
|
if (mb_strlen($cashier) > Constraints::MAX_LENGTH_CASHIER_NAME) {
|
||||||
|
throw new TooLongCashierException($cashier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->cashier = $cashier ?: null;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленный дополнительный реквизит чека
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getAddCheckProps(): ?string
|
||||||
|
{
|
||||||
|
return $this->add_check_props;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает дополнительный реквизит чека
|
||||||
|
*
|
||||||
|
* @param string|null $add_check_props
|
||||||
|
* @return $this
|
||||||
|
* @throws TooLongAddCheckPropException
|
||||||
|
*/
|
||||||
|
public function setAddCheckProps(?string $add_check_props): self
|
||||||
|
{
|
||||||
|
if (is_string($add_check_props)) {
|
||||||
|
$add_check_props = trim($add_check_props);
|
||||||
|
if (mb_strlen($add_check_props) > Constraints::MAX_LENGTH_ADD_CHECK_PROP) {
|
||||||
|
throw new TooLongAddCheckPropException($add_check_props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->add_check_props = $add_check_props ?: null;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленный дополнительный реквизит пользователя
|
||||||
|
*
|
||||||
|
* @return AdditionalUserProps|null
|
||||||
|
*/
|
||||||
|
public function getAddUserProps(): ?AdditionalUserProps
|
||||||
|
{
|
||||||
|
return $this->add_user_props;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанаваливает дополнительный реквизит пользователя
|
||||||
|
*
|
||||||
|
* @param AdditionalUserProps|null $add_user_props
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setAddUserProps(?AdditionalUserProps $add_user_props): self
|
||||||
|
{
|
||||||
|
$this->add_user_props = $add_user_props;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует приход по текущему документу
|
||||||
|
*
|
||||||
|
* @param Fiscalizer $fiscalizer Объект фискализатора
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function sell(Fiscalizer $fiscalizer, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $fiscalizer->sell($this, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует возврат прихода по текущему документу
|
||||||
|
*
|
||||||
|
* @param Fiscalizer $fiscalizer Объект фискализатора
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function sellRefund(Fiscalizer $fiscalizer, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $fiscalizer->sellRefund($this, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует расход по текущему документу
|
||||||
|
*
|
||||||
|
* @param Fiscalizer $fiscalizer Объект фискализатора
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function buy(Fiscalizer $fiscalizer, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $fiscalizer->buy($this, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Регистрирует возврат расхода по текущему документу
|
||||||
|
*
|
||||||
|
* @param Fiscalizer $fiscalizer Объект фискализатора
|
||||||
|
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан новый UUID)
|
||||||
|
* @return AtolResponse|null
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
*/
|
||||||
|
public function buyRefund(Fiscalizer $fiscalizer, ?string $external_id = null): ?AtolResponse
|
||||||
|
{
|
||||||
|
return $fiscalizer->buyRefund($this, $external_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает массив для кодирования в json
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function jsonSerialize(): array
|
||||||
|
{
|
||||||
|
$json = [
|
||||||
|
'client' => $this->getClient()->jsonSerialize(),
|
||||||
|
'company' => $this->getCompany()->jsonSerialize(),
|
||||||
|
'items' => $this->getItems()->jsonSerialize(),
|
||||||
|
'total' => $this->getTotal(),
|
||||||
|
'payments' => $this->getPayments()->jsonSerialize(),
|
||||||
|
];
|
||||||
|
$this->getAgentInfo()?->jsonSerialize() && $json['agent_info'] = $this->getAgentInfo()->jsonSerialize();
|
||||||
|
$this->getSupplier()?->jsonSerialize() && $json['supplier_info'] = $this->getSupplier()->jsonSerialize();
|
||||||
|
$this->getVats()?->isNotEmpty() && $json['vats'] = $this->getVats();
|
||||||
|
!is_null($this->getAddCheckProps()) && $json['additional_check_props'] = $this->getAddCheckProps();
|
||||||
|
!is_null($this->getCashier()) && $json['cashier'] = $this->getCashier();
|
||||||
|
$this->getAddUserProps()?->jsonSerialize() &&
|
||||||
|
$json['additional_user_props'] = $this->getAddUserProps()->jsonSerialize();
|
||||||
|
return $json;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,8 +11,8 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Entities;
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
use AtolOnline\Constants\Constraints;
|
|
||||||
use AtolOnline\Exceptions\InvalidPhoneException;
|
use AtolOnline\Exceptions\InvalidPhoneException;
|
||||||
|
use AtolOnline\Traits\HasPhones;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,12 +20,9 @@ use Illuminate\Support\Collection;
|
|||||||
*
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 19-20
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 19-20
|
||||||
*/
|
*/
|
||||||
class ReceivePaymentsOperator extends Entity
|
final class ReceivePaymentsOperator extends Entity
|
||||||
{
|
{
|
||||||
/**
|
use HasPhones;
|
||||||
* @var Collection Телефоны оператора по приёму платежей (1074)
|
|
||||||
*/
|
|
||||||
protected Collection $phones;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конструктор
|
* Конструктор
|
||||||
@@ -33,46 +30,11 @@ class ReceivePaymentsOperator extends Entity
|
|||||||
* @param array|Collection|null $phones Телефоны оператора по приёму платежей (1074)
|
* @param array|Collection|null $phones Телефоны оператора по приёму платежей (1074)
|
||||||
* @throws InvalidPhoneException
|
* @throws InvalidPhoneException
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(array|Collection|null $phones = null)
|
||||||
array|Collection|null $phones = null,
|
{
|
||||||
) {
|
|
||||||
$this->setPhones($phones);
|
$this->setPhones($phones);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает установленные номера телефонов
|
|
||||||
*
|
|
||||||
* @todo вытащить в трейт
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function getPhones(): Collection
|
|
||||||
{
|
|
||||||
return $this->phones;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает массив номеров телефонов
|
|
||||||
*
|
|
||||||
* @todo вытащить в трейт
|
|
||||||
* @param array|Collection|null $phones
|
|
||||||
* @return $this
|
|
||||||
* @throws InvalidPhoneException
|
|
||||||
*/
|
|
||||||
public function setPhones(array|Collection|null $phones): self
|
|
||||||
{
|
|
||||||
if (!is_null($phones)) {
|
|
||||||
$phones = is_array($phones) ? collect($phones) : $phones;
|
|
||||||
$phones->each(function ($phone) {
|
|
||||||
$phone = preg_replace('/[^\d]/', '', trim($phone));
|
|
||||||
if (preg_match(Constraints::PATTERN_PHONE, $phone) != 1) {
|
|
||||||
throw new InvalidPhoneException($phone);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$this->phones = empty($phones) ? collect() : $phones;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -11,9 +11,14 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Entities;
|
namespace AtolOnline\Entities;
|
||||||
|
|
||||||
use AtolOnline\Constants\Constraints;
|
use AtolOnline\Exceptions\{
|
||||||
use AtolOnline\Exceptions\InvalidInnLengthException;
|
InvalidInnLengthException,
|
||||||
use AtolOnline\Exceptions\InvalidPhoneException;
|
InvalidPhoneException
|
||||||
|
};
|
||||||
|
use AtolOnline\Traits\{
|
||||||
|
HasInn,
|
||||||
|
HasPhones
|
||||||
|
};
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,23 +26,15 @@ use Illuminate\Support\Collection;
|
|||||||
*
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 29
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 29
|
||||||
*/
|
*/
|
||||||
class Supplier extends Entity
|
final class Supplier extends Entity
|
||||||
{
|
{
|
||||||
|
use HasPhones, HasInn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null Наименование (1225)
|
* @var string|null Наименование (1225)
|
||||||
*/
|
*/
|
||||||
protected ?string $name = null;
|
protected ?string $name = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null ИНН (1226)
|
|
||||||
*/
|
|
||||||
protected ?string $inn = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Collection Телефоны (1171)
|
|
||||||
*/
|
|
||||||
protected Collection $phones;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конструктор
|
* Конструктор
|
||||||
*
|
*
|
||||||
@@ -80,69 +77,6 @@ class Supplier extends Entity
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает установленные номера телефонов
|
|
||||||
*
|
|
||||||
* @todo вытащить в трейт
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function getPhones(): Collection
|
|
||||||
{
|
|
||||||
return $this->phones;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает массив номеров телефонов
|
|
||||||
*
|
|
||||||
* @todo вытащить в трейт
|
|
||||||
* @param array|Collection|null $phones
|
|
||||||
* @return $this
|
|
||||||
* @throws InvalidPhoneException
|
|
||||||
*/
|
|
||||||
public function setPhones(array|Collection|null $phones): self
|
|
||||||
{
|
|
||||||
if (!is_null($phones)) {
|
|
||||||
$phones = is_array($phones) ? collect($phones) : $phones;
|
|
||||||
$phones->each(function ($phone) {
|
|
||||||
$phone = preg_replace('/[^\d]/', '', trim($phone));
|
|
||||||
if (preg_match(Constraints::PATTERN_PHONE, $phone) != 1) {
|
|
||||||
throw new InvalidPhoneException($phone);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$this->phones = empty($phones) ? collect() : $phones;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Возвращает установленный ИНН
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getInn(): ?string
|
|
||||||
{
|
|
||||||
return $this->inn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Устанавливает ИНН
|
|
||||||
*
|
|
||||||
* @param string|null $inn
|
|
||||||
* @return $this
|
|
||||||
* @throws InvalidInnLengthException Некорректная длина ИНН
|
|
||||||
*/
|
|
||||||
public function setInn(?string $inn): self
|
|
||||||
{
|
|
||||||
if (is_string($inn)) {
|
|
||||||
$inn = preg_replace('/[^\d]/', '', trim($inn));
|
|
||||||
if (preg_match_all(Constraints::PATTERN_INN, $inn) === 0) {
|
|
||||||
throw new InvalidInnLengthException($inn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->inn = empty($inn) ? null : $inn;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,13 +14,16 @@ namespace AtolOnline\Entities;
|
|||||||
use AtolOnline\Enums\VatTypes;
|
use AtolOnline\Enums\VatTypes;
|
||||||
use AtolOnline\Exceptions\InvalidEnumValueException;
|
use AtolOnline\Exceptions\InvalidEnumValueException;
|
||||||
use AtolOnline\Helpers;
|
use AtolOnline\Helpers;
|
||||||
|
use JetBrains\PhpStorm\{
|
||||||
|
ArrayShape,
|
||||||
|
Pure};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс, описывающий ставку НДС
|
* Класс, описывающий ставку НДС
|
||||||
*
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 25, 31
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 25, 31
|
||||||
*/
|
*/
|
||||||
class Vat extends Entity
|
final class Vat extends Entity
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string Тип ставки НДС (1199, 1105, 1104, 1103, 1102, 1107, 1106)
|
* @var string Тип ставки НДС (1199, 1105, 1104, 1103, 1102, 1107, 1106)
|
||||||
@@ -37,6 +40,7 @@ class Vat extends Entity
|
|||||||
*
|
*
|
||||||
* @param string $type Тип ставки НДС (1199, 1105, 1104, 1103, 1102, 1107, 1106)
|
* @param string $type Тип ставки НДС (1199, 1105, 1104, 1103, 1102, 1107, 1106)
|
||||||
* @param float $rubles Исходная сумма в рублях, от которой нужно расчитать размер НДС
|
* @param float $rubles Исходная сумма в рублях, от которой нужно расчитать размер НДС
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
*/
|
*/
|
||||||
public function __construct(string $type, float $rubles)
|
public function __construct(string $type, float $rubles)
|
||||||
{
|
{
|
||||||
@@ -87,30 +91,32 @@ class Vat extends Entity
|
|||||||
*/
|
*/
|
||||||
public function setSum(float $rubles): self
|
public function setSum(float $rubles): self
|
||||||
{
|
{
|
||||||
$this->sum = $rubles;
|
$this->sum = round($rubles, 2);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает sdрасчитанный итоговый размер ставки НДС в рублях
|
* Возвращает расчитанный итоговый размер ставки НДС в рублях
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
* @see https://nalog-nalog.ru/nds/nalogovaya_baza_nds/kak-schitat-nds-pravilno-vychislyaem-20-ot-summy-primer-algoritm/
|
* @see https://nalog-nalog.ru/nds/nalogovaya_baza_nds/kak-schitat-nds-pravilno-vychislyaem-20-ot-summy-primer-algoritm/
|
||||||
* @see https://glavkniga.ru/situations/k500734
|
* @see https://glavkniga.ru/situations/k500734
|
||||||
* @see https://www.b-kontur.ru/nds-kalkuljator-online
|
* @see https://www.b-kontur.ru/nds-kalkuljator-online
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function getCalculated(): float
|
public function getCalculated(): float
|
||||||
{
|
{
|
||||||
$kopeks = Helpers::toKop($this->sum);
|
return Helpers::toRub(
|
||||||
return Helpers::toRub(match ($this->getType()) {
|
match ($this->getType()) {
|
||||||
VatTypes::VAT10 => $kopeks * 10 / 100,
|
VatTypes::VAT10 => Helpers::toKop($this->sum) * 10 / 100,
|
||||||
VatTypes::VAT18 => $kopeks * 18 / 100,
|
VatTypes::VAT18 => Helpers::toKop($this->sum) * 18 / 100,
|
||||||
VatTypes::VAT20 => $kopeks * 20 / 100,
|
VatTypes::VAT20 => Helpers::toKop($this->sum) * 20 / 100,
|
||||||
VatTypes::VAT110 => $kopeks * 10 / 110,
|
VatTypes::VAT110 => Helpers::toKop($this->sum) * 10 / 110,
|
||||||
VatTypes::VAT118 => $kopeks * 18 / 118,
|
VatTypes::VAT118 => Helpers::toKop($this->sum) * 18 / 118,
|
||||||
VatTypes::VAT120 => $kopeks * 20 / 120,
|
VatTypes::VAT120 => Helpers::toKop($this->sum) * 20 / 120,
|
||||||
default => 0,
|
default => 0,
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,6 +134,8 @@ class Vat extends Entity
|
|||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
|
#[ArrayShape(['type' => 'string', 'sum' => 'float'])]
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
<?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\Enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Константы, определяющие типы документов
|
|
||||||
*/
|
|
||||||
final class DocumentTypes extends Enum
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Чек прихода, возврата прихода, расхода, возврата расхода
|
|
||||||
*/
|
|
||||||
const RECEIPT = 'receipt';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Чек коррекции
|
|
||||||
*/
|
|
||||||
const CORRECTION = 'correction';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public static function getFfdTags(): array
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,8 +24,7 @@ abstract class Enum extends \MyCLabs\Enum\Enum
|
|||||||
*/
|
*/
|
||||||
public static function isValid($value)
|
public static function isValid($value)
|
||||||
{
|
{
|
||||||
return parent::isValid($value)
|
return parent::isValid($value) ?: throw new InvalidEnumValueException(static::class, $value);
|
||||||
?: throw new InvalidEnumValueException(static::class, $value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ final class PaymentObjects extends Enum
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Составной предмет расчёта
|
* Составной предмет расчёта
|
||||||
|
*
|
||||||
* @deprecated Более не используется согласно ФФД 1.05
|
* @deprecated Более не используется согласно ФФД 1.05
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 25 (payment_object)
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 25 (payment_object)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -47,4 +47,4 @@ final class ReceiptOperationTypes extends Enum
|
|||||||
* Коррекция прихода (догоняем неучтённые средства)
|
* Коррекция прихода (догоняем неучтённые средства)
|
||||||
*/
|
*/
|
||||||
const BUY_CORRECTION = 'buy_correction';
|
const BUY_CORRECTION = 'buy_correction';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при работе с АТОЛ Онлайн
|
* Исключение, возникающее при работе с АТОЛ Онлайн
|
||||||
@@ -29,11 +30,12 @@ class AtolException extends Exception
|
|||||||
* @param string $message Сообщение
|
* @param string $message Сообщение
|
||||||
* @param int[] $ffd_tags Переопредление тегов ФФД
|
* @param int[] $ffd_tags Переопредление тегов ФФД
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $message = '', array $ffd_tags = [])
|
public function __construct(string $message = '', array $ffd_tags = [])
|
||||||
{
|
{
|
||||||
$tags = implode(', ', $ffd_tags ?: $this->ffd_tags);
|
$tags = implode(', ', $ffd_tags ?: $this->ffd_tags);
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
($message ?: $this->message) . ($tags ? ' [Теги ФФД: ' . $tags : '') . ']'
|
($message ?: $this->message) . ($tags ? ' [Теги ФФД: ' . $tags . ']' : '')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use AtolOnline\Api\KktResponse;
|
use AtolOnline\Api\AtolResponse;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при неудачной авторизации
|
* Исключение, возникающее при неудачной авторизации
|
||||||
@@ -22,10 +23,11 @@ class AuthFailedException extends Exception
|
|||||||
/**
|
/**
|
||||||
* Конструктор
|
* Конструктор
|
||||||
*
|
*
|
||||||
* @param KktResponse $response
|
* @param AtolResponse $response
|
||||||
* @param string $message
|
* @param string $message
|
||||||
*/
|
*/
|
||||||
public function __construct(KktResponse $response, string $message = '')
|
#[Pure]
|
||||||
|
public function __construct(AtolResponse $response, string $message = '')
|
||||||
{
|
{
|
||||||
parent::__construct(($message ?: 'Ошибка авторизации: ') . ': ' . $response);
|
parent::__construct(($message ?: 'Ошибка авторизации: ') . ': ' . $response);
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/Exceptions/EmptyAddUserPropNameException.php
Normal file
25
src/Exceptions/EmptyAddUserPropNameException.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?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\Ffd105Tags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при пустом наименовании дополнительного реквизита пользователя
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32
|
||||||
|
*/
|
||||||
|
class EmptyAddUserPropNameException extends AtolException
|
||||||
|
{
|
||||||
|
protected $message = 'Наименование дополнительного реквизита пользователя не может быть пустым';
|
||||||
|
protected array $ffd_tags = [Ffd105Tags::DOC_ADD_USER_PROP_NAME];
|
||||||
|
}
|
||||||
25
src/Exceptions/EmptyAddUserPropValueException.php
Normal file
25
src/Exceptions/EmptyAddUserPropValueException.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?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\Ffd105Tags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при пустом наименовании дополнительного реквизита пользователя
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32
|
||||||
|
*/
|
||||||
|
class EmptyAddUserPropValueException extends AtolException
|
||||||
|
{
|
||||||
|
protected $message = 'Значение дополнительного реквизита пользователя не может быть пустым';
|
||||||
|
protected array $ffd_tags = [Ffd105Tags::DOC_ADD_USER_PROP_VALUE];
|
||||||
|
}
|
||||||
23
src/Exceptions/EmptyCorrectionNumberException.php
Normal file
23
src/Exceptions/EmptyCorrectionNumberException.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?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\Ffd105Tags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при пустом номере документа коррекции
|
||||||
|
*/
|
||||||
|
class EmptyCorrectionNumberException extends AtolException
|
||||||
|
{
|
||||||
|
protected $message = 'Номер документа коррекции не может быть пустым';
|
||||||
|
protected array $ffd_tags = [Ffd105Tags::CORRECTION_DATE];
|
||||||
|
}
|
||||||
20
src/Exceptions/EmptyGroupException.php
Normal file
20
src/Exceptions/EmptyGroupException.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать пустую группу ККТ
|
||||||
|
*/
|
||||||
|
class EmptyGroupException extends AtolException
|
||||||
|
{
|
||||||
|
protected $message = 'Группа ККТ должна быть указана';
|
||||||
|
}
|
||||||
22
src/Exceptions/EmptyItemsException.php
Normal file
22
src/Exceptions/EmptyItemsException.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать документу пустую коллекцию предметов расчёта
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 21
|
||||||
|
*/
|
||||||
|
class EmptyItemsException extends AtolException
|
||||||
|
{
|
||||||
|
protected $message = 'Документ не может содержать пустую коллекцию предметов расчёта';
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ namespace AtolOnline\Exceptions;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке указать пустой логин
|
* Исключение, возникающее при попытке указать пустой логин
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 12
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 12
|
||||||
*/
|
*/
|
||||||
class EmptyLoginException extends AtolException
|
class EmptyLoginException extends AtolException
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace AtolOnline\Exceptions;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке указать пустой пароль
|
* Исключение, возникающее при попытке указать пустой пароль
|
||||||
|
*
|
||||||
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 12
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 12
|
||||||
*/
|
*/
|
||||||
class EmptyPasswordException extends AtolException
|
class EmptyPasswordException extends AtolException
|
||||||
|
|||||||
22
src/Exceptions/EmptyPaymentsException.php
Normal file
22
src/Exceptions/EmptyPaymentsException.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать документу пустую коллекцию оплат
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 30
|
||||||
|
*/
|
||||||
|
class EmptyPaymentsException extends AtolException
|
||||||
|
{
|
||||||
|
protected $message = 'Документ не может содержать пустую коллекцию оплат';
|
||||||
|
}
|
||||||
22
src/Exceptions/EmptyVatsException.php
Normal file
22
src/Exceptions/EmptyVatsException.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать документу пустую коллекцию ставок НДС
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 31
|
||||||
|
*/
|
||||||
|
class EmptyVatsException extends AtolException
|
||||||
|
{
|
||||||
|
protected $message = 'Документ не может содержать пустую коллекцию ставок НДС';
|
||||||
|
}
|
||||||
35
src/Exceptions/InvalidCorrectionDateException.php
Normal file
35
src/Exceptions/InvalidCorrectionDateException.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\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать некорректную дату коррекции
|
||||||
|
*/
|
||||||
|
class InvalidCorrectionDateException extends AtolException
|
||||||
|
{
|
||||||
|
protected array $ffd_tags = [Ffd105Tags::CORRECTION_DATE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param string $date
|
||||||
|
* @param string $message
|
||||||
|
*/
|
||||||
|
#[Pure]
|
||||||
|
public function __construct(string $date = '', string $message = '')
|
||||||
|
{
|
||||||
|
parent::__construct("Ошибка даты документа коррекции '$date': " . $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при ошибке валидации кода таможенной декларации
|
* Исключение, возникающее при ошибке валидации кода таможенной декларации
|
||||||
@@ -25,6 +26,7 @@ class InvalidDeclarationNumberException extends AtolException
|
|||||||
*
|
*
|
||||||
* @param string $code
|
* @param string $code
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $code = '')
|
public function __construct(string $code = '')
|
||||||
{
|
{
|
||||||
parent::__construct("Невалидный код таможенной декларации: '$code'");
|
parent::__construct("Невалидный код таможенной декларации: '$code'");
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при ошибке валидации email
|
* Исключение, возникающее при ошибке валидации email
|
||||||
@@ -30,6 +31,7 @@ class InvalidEmailException extends AtolException
|
|||||||
*
|
*
|
||||||
* @param string $email
|
* @param string $email
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $email = '')
|
public function __construct(string $email = '')
|
||||||
{
|
{
|
||||||
parent::__construct("Невалидный email: '$email'");
|
parent::__construct("Невалидный email: '$email'");
|
||||||
|
|||||||
37
src/Exceptions/InvalidEntityInCollectionException.php
Normal file
37
src/Exceptions/InvalidEntityInCollectionException.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при наличии некорректных объектов в коллекции
|
||||||
|
*/
|
||||||
|
class InvalidEntityInCollectionException extends AtolException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param string $collection_class
|
||||||
|
* @param string $expected_class
|
||||||
|
* @param mixed $actual
|
||||||
|
*/
|
||||||
|
public function __construct(string $collection_class, string $expected_class, mixed $actual)
|
||||||
|
{
|
||||||
|
if (is_object($actual)) {
|
||||||
|
$actual = $actual::class;
|
||||||
|
} elseif (is_scalar($actual)) {
|
||||||
|
$actual = '(' . gettype($actual) . ')' . var_export($actual, true);
|
||||||
|
}
|
||||||
|
parent::__construct(
|
||||||
|
"Коллекция $collection_class должна содержать объекты $expected_class, найден $actual"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке указать ИНН некорректной длины
|
* Исключение, возникающее при попытке указать ИНН некорректной длины
|
||||||
@@ -31,6 +32,7 @@ class InvalidInnLengthException extends AtolException
|
|||||||
* @param string $inn
|
* @param string $inn
|
||||||
* @param string $message
|
* @param string $message
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $inn = '', string $message = '')
|
public function __construct(string $inn = '', string $message = '')
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при работе с невалидным JSON
|
* Исключение, возникающее при работе с невалидным JSON
|
||||||
*/
|
*/
|
||||||
@@ -19,6 +21,7 @@ class InvalidJsonException extends AtolException
|
|||||||
/**
|
/**
|
||||||
* Конструктор
|
* Конструктор
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct('[' . json_last_error() . '] ' . json_last_error_msg());
|
parent::__construct('[' . json_last_error() . '] ' . json_last_error_msg());
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при ошибке валидации кода страны происхождения товара
|
* Исключение, возникающее при ошибке валидации кода страны происхождения товара
|
||||||
@@ -27,6 +28,7 @@ class InvalidOKSMCodeException extends AtolException
|
|||||||
*
|
*
|
||||||
* @param string $code
|
* @param string $code
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $code)
|
public function __construct(string $code)
|
||||||
{
|
{
|
||||||
parent::__construct('Невалидный код страны происхождения товара: ' . $code);
|
parent::__construct('Невалидный код страны происхождения товара: ' . $code);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке указать некорректный адрес места расчётов
|
* Исключение, возникающее при попытке указать некорректный адрес места расчётов
|
||||||
@@ -28,7 +29,8 @@ class InvalidPaymentAddressException extends AtolException
|
|||||||
* @param string $address
|
* @param string $address
|
||||||
* @param string $message
|
* @param string $message
|
||||||
*/
|
*/
|
||||||
public function __construct($address = '', $message = "")
|
#[Pure]
|
||||||
|
public function __construct(string $address = '', string $message = '')
|
||||||
{
|
{
|
||||||
parent::__construct($message ?: "Некорректный адрес места расчётов: '$address'");
|
parent::__construct($message ?: "Некорректный адрес места расчётов: '$address'");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при ошибке валидации номера телефона
|
* Исключение, возникающее при ошибке валидации номера телефона
|
||||||
@@ -31,6 +32,7 @@ class InvalidPhoneException extends AtolException
|
|||||||
*
|
*
|
||||||
* @param string $phone
|
* @param string $phone
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $phone = '')
|
public function __construct(string $phone = '')
|
||||||
{
|
{
|
||||||
parent::__construct("Невалидный номер телефона: '$phone'");
|
parent::__construct("Невалидный номер телефона: '$phone'");
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при ошибке валидации UUID
|
* Исключение, возникающее при ошибке валидации UUID
|
||||||
*/
|
*/
|
||||||
@@ -19,13 +21,11 @@ class InvalidUuidException extends AtolException
|
|||||||
/**
|
/**
|
||||||
* Конструктор
|
* Конструктор
|
||||||
*
|
*
|
||||||
* @param $uuid
|
* @param string $uuid
|
||||||
* @param string $message
|
|
||||||
* @param int $code
|
|
||||||
* @param Throwable|null $previous
|
|
||||||
*/
|
*/
|
||||||
public function __construct(?string $uuid = null)
|
#[Pure]
|
||||||
|
public function __construct(string $uuid = '')
|
||||||
{
|
{
|
||||||
parent::__construct('Невалидный UUID' . ($uuid ? ': ' . $uuid : ''));
|
parent::__construct('Невалидный UUID: ' . $uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке указать предмету расчёта отрицательный акциз
|
* Исключение, возникающее при попытке указать предмету расчёта отрицательный акциз
|
||||||
@@ -26,6 +27,7 @@ class NegativeItemExciseException extends AtolException
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @param float $excise
|
* @param float $excise
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $name, float $excise)
|
public function __construct(string $name, float $excise)
|
||||||
{
|
{
|
||||||
parent::__construct("Предмет расчёта '$name' не может иметь отрицательный акциз $excise");
|
parent::__construct("Предмет расчёта '$name' не может иметь отрицательный акциз $excise");
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке указать предмету расчёта отрицательную цену
|
* Исключение, возникающее при попытке указать предмету расчёта отрицательную цену
|
||||||
@@ -26,6 +27,7 @@ class NegativeItemPriceException extends AtolException
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @param float $price
|
* @param float $price
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $name, float $price)
|
public function __construct(string $name, float $price)
|
||||||
{
|
{
|
||||||
parent::__construct("Предмет расчёта '$name' не может иметь отрицательную цену $price");
|
parent::__construct("Предмет расчёта '$name' не может иметь отрицательную цену $price");
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ declare(strict_types = 1);
|
|||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке указать предмету расчёта отрицательное количество
|
* Исключение, возникающее при попытке указать предмету расчёта отрицательное количество
|
||||||
@@ -26,6 +27,7 @@ class NegativeItemQuantityException extends AtolException
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @param float $quantity
|
* @param float $quantity
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $name, float $quantity)
|
public function __construct(string $name, float $quantity)
|
||||||
{
|
{
|
||||||
parent::__construct("Предмет расчёта '$name' не может иметь отрицательное количество $quantity");
|
parent::__construct("Предмет расчёта '$name' не может иметь отрицательное количество $quantity");
|
||||||
|
|||||||
40
src/Exceptions/NegativePaymentSumException.php
Normal file
40
src/Exceptions/NegativePaymentSumException.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?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\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать оплате отрицательную сумму
|
||||||
|
*/
|
||||||
|
class NegativePaymentSumException extends AtolException
|
||||||
|
{
|
||||||
|
protected array $ffd_tags = [
|
||||||
|
Ffd105Tags::PAYMENT_TYPE_CASH,
|
||||||
|
Ffd105Tags::PAYMENT_TYPE_CREDIT,
|
||||||
|
Ffd105Tags::PAYMENT_TYPE_ELECTRON,
|
||||||
|
Ffd105Tags::PAYMENT_TYPE_PREPAID,
|
||||||
|
Ffd105Tags::PAYMENT_TYPE_OTHER,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param float $sum
|
||||||
|
*/
|
||||||
|
#[Pure]
|
||||||
|
public function __construct(float $sum)
|
||||||
|
{
|
||||||
|
parent::__construct('Размер оплаты не может быть отрицательным: ' . $sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке создать объект ККТ с неполными данными от монитора
|
* Исключение, возникающее при попытке создать объект ККТ с неполными данными от монитора
|
||||||
*/
|
*/
|
||||||
@@ -27,6 +29,7 @@ class NotEnoughMonitorDataException extends AtolException
|
|||||||
* @param array $props_diff
|
* @param array $props_diff
|
||||||
* @param string $message
|
* @param string $message
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(array $props_diff, string $message = '')
|
public function __construct(array $props_diff, string $message = '')
|
||||||
{
|
{
|
||||||
parent::__construct($message ?: $this->message . implode(', ', $props_diff));
|
parent::__construct($message ?: $this->message . implode(', ', $props_diff));
|
||||||
|
|||||||
@@ -13,11 +13,12 @@ namespace AtolOnline\Exceptions;
|
|||||||
|
|
||||||
use AtolOnline\Constants\Constraints;
|
use AtolOnline\Constants\Constraints;
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке указать слишком высокую цену (сумму)
|
* Исключение, возникающее при попытке указать слишком высокую цену (сумму) предмета расчёта
|
||||||
*/
|
*/
|
||||||
class TooHighPriceException extends TooManyException
|
class TooHighItemPriceException extends TooManyException
|
||||||
{
|
{
|
||||||
protected array $ffd_tags = [Ffd105Tags::ITEM_PRICE];
|
protected array $ffd_tags = [Ffd105Tags::ITEM_PRICE];
|
||||||
protected float $max = Constraints::MAX_COUNT_ITEM_PRICE;
|
protected float $max = Constraints::MAX_COUNT_ITEM_PRICE;
|
||||||
@@ -28,6 +29,7 @@ class TooHighPriceException extends TooManyException
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @param float $price
|
* @param float $price
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $name, float $price)
|
public function __construct(string $name, float $price)
|
||||||
{
|
{
|
||||||
parent::__construct($price, "Слишком высокая цена для предмета расчёта '$name'");
|
parent::__construct($price, "Слишком высокая цена для предмета расчёта '$name'");
|
||||||
@@ -13,6 +13,7 @@ namespace AtolOnline\Exceptions;
|
|||||||
|
|
||||||
use AtolOnline\Constants\Constraints;
|
use AtolOnline\Constants\Constraints;
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке добавить слишком большое количество предмета расчёта
|
* Исключение, возникающее при попытке добавить слишком большое количество предмета расчёта
|
||||||
@@ -28,6 +29,7 @@ class TooHighItemQuantityException extends TooManyException
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @param float $quantity
|
* @param float $quantity
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $name, float $quantity)
|
public function __construct(string $name, float $quantity)
|
||||||
{
|
{
|
||||||
parent::__construct($quantity, "Слишком большое количество предмета расчёта '$name'");
|
parent::__construct($quantity, "Слишком большое количество предмета расчёта '$name'");
|
||||||
|
|||||||
@@ -13,14 +13,15 @@ namespace AtolOnline\Exceptions;
|
|||||||
|
|
||||||
use AtolOnline\Constants\Constraints;
|
use AtolOnline\Constants\Constraints;
|
||||||
use AtolOnline\Constants\Ffd105Tags;
|
use AtolOnline\Constants\Ffd105Tags;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке получеиня слишком высокой стоимости
|
* Исключение, возникающее при попытке получеиня слишком высокой стоимости предмета расчёта
|
||||||
*/
|
*/
|
||||||
class TooHighSumException extends TooManyException
|
class TooHighItemSumException extends TooManyException
|
||||||
{
|
{
|
||||||
protected array $ffd_tags = [Ffd105Tags::ITEM_SUM];
|
protected array $ffd_tags = [Ffd105Tags::ITEM_SUM];
|
||||||
protected float $max = Constraints::MAX_COUNT_ITEM_PRICE;
|
protected float $max = Constraints::MAX_COUNT_ITEM_SUM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конструктор
|
* Конструктор
|
||||||
@@ -28,6 +29,7 @@ class TooHighSumException extends TooManyException
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @param float $sum
|
* @param float $sum
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(string $name, float $sum)
|
public function __construct(string $name, float $sum)
|
||||||
{
|
{
|
||||||
parent::__construct($sum, "Слишком высокая стоимость предмета расчёта '$name'");
|
parent::__construct($sum, "Слишком высокая стоимость предмета расчёта '$name'");
|
||||||
31
src/Exceptions/TooHighPaymentSumException.php
Normal file
31
src/Exceptions/TooHighPaymentSumException.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?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 TooHighPaymentSumException extends TooManyException
|
||||||
|
{
|
||||||
|
protected $message = 'Слишком высокый размер оплаты';
|
||||||
|
protected array $ffd_tags = [
|
||||||
|
Ffd105Tags::PAYMENT_TYPE_CASH,
|
||||||
|
Ffd105Tags::PAYMENT_TYPE_CREDIT,
|
||||||
|
Ffd105Tags::PAYMENT_TYPE_ELECTRON,
|
||||||
|
Ffd105Tags::PAYMENT_TYPE_PREPAID,
|
||||||
|
Ffd105Tags::PAYMENT_TYPE_OTHER,
|
||||||
|
];
|
||||||
|
protected float $max = Constraints::MAX_COUNT_PAYMENT_SUM;
|
||||||
|
}
|
||||||
28
src/Exceptions/TooLongAddCheckPropException.php
Normal file
28
src/Exceptions/TooLongAddCheckPropException.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?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,
|
||||||
|
Ffd105Tags};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать слишком длинное наименование дополнительного реквизита чека
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32
|
||||||
|
*/
|
||||||
|
class TooLongAddCheckPropException extends TooLongException
|
||||||
|
{
|
||||||
|
protected $message = 'Слишком длинное наименование дополнительного реквизита чека';
|
||||||
|
protected float $max = Constraints::MAX_LENGTH_ADD_CHECK_PROP;
|
||||||
|
protected array $ffd_tags = [Ffd105Tags::DOC_ADD_CHECK_PROP_VALUE];
|
||||||
|
}
|
||||||
28
src/Exceptions/TooLongAddUserPropNameException.php
Normal file
28
src/Exceptions/TooLongAddUserPropNameException.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?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,
|
||||||
|
Ffd105Tags};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать слишком длинное наименование дополнительного реквизита пользователя
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32
|
||||||
|
*/
|
||||||
|
class TooLongAddUserPropNameException extends TooLongException
|
||||||
|
{
|
||||||
|
protected $message = 'Слишком длинное наименование дополнительного реквизита пользователя';
|
||||||
|
protected float $max = Constraints::MAX_LENGTH_ADD_USER_PROP_NAME;
|
||||||
|
protected array $ffd_tags = [Ffd105Tags::DOC_ADD_USER_PROP_NAME];
|
||||||
|
}
|
||||||
28
src/Exceptions/TooLongAddUserPropValueException.php
Normal file
28
src/Exceptions/TooLongAddUserPropValueException.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?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,
|
||||||
|
Ffd105Tags};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать слишком длинное значение дополнительного реквизита пользователя
|
||||||
|
*
|
||||||
|
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32
|
||||||
|
*/
|
||||||
|
class TooLongAddUserPropValueException extends TooLongException
|
||||||
|
{
|
||||||
|
protected $message = 'Слишком длинное значение дополнительного реквизита пользователя';
|
||||||
|
protected float $max = Constraints::MAX_LENGTH_ADD_USER_PROP_VALUE;
|
||||||
|
protected array $ffd_tags = [Ffd105Tags::DOC_ADD_USER_PROP_VALUE];
|
||||||
|
}
|
||||||
@@ -18,6 +18,6 @@ use AtolOnline\Constants\Constraints;
|
|||||||
*/
|
*/
|
||||||
class TooLongCallbackUrlException extends TooLongException
|
class TooLongCallbackUrlException extends TooLongException
|
||||||
{
|
{
|
||||||
protected $message = 'Слишком длинный адрес колбека';
|
protected $message = 'Слишком длинный callback_url';
|
||||||
protected float $max = Constraints::MAX_LENGTH_CALLBACK_URL;
|
protected float $max = Constraints::MAX_LENGTH_CALLBACK_URL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке указать слишком длинное что-либо
|
* Исключение, возникающее при попытке указать слишком длинное что-либо
|
||||||
*/
|
*/
|
||||||
@@ -31,14 +33,14 @@ 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)
|
#[Pure]
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/Exceptions/TooLongItemCodeException.php
Normal file
37
src/Exceptions/TooLongItemCodeException.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?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;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Исключение, возникающее при попытке указать слишком длинный код товара
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
#[Pure]
|
||||||
|
public function __construct(string $name, string $code)
|
||||||
|
{
|
||||||
|
parent::__construct($code, "Слишком длинный код товара '$name'");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Exceptions;
|
namespace AtolOnline\Exceptions;
|
||||||
|
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке указать слишком большое количество чего-либо
|
* Исключение, возникающее при попытке указать слишком большое количество чего-либо
|
||||||
*/
|
*/
|
||||||
@@ -33,6 +35,7 @@ class TooManyException extends AtolException
|
|||||||
* @param string $message
|
* @param string $message
|
||||||
* @param float|null $max
|
* @param float|null $max
|
||||||
*/
|
*/
|
||||||
|
#[Pure]
|
||||||
public function __construct(float $value, string $message = '', ?float $max = null)
|
public function __construct(float $value, string $message = '', ?float $max = null)
|
||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace AtolOnline\Exceptions;
|
|||||||
use AtolOnline\Constants\Constraints;
|
use AtolOnline\Constants\Constraints;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Исключение, возникающее при попытке добавить слишком много ставок НДС в массив
|
* Исключение, возникающее при попытке добавить слишком много ставок НДС в документ
|
||||||
*/
|
*/
|
||||||
class TooManyVatsException extends TooManyException
|
class TooManyVatsException extends TooManyException
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,67 +52,4 @@ final class Helpers
|
|||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Проверяет идентичность двух классов
|
|
||||||
*
|
|
||||||
* @param object|string $class1
|
|
||||||
* @param object|string $class2
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function isSameClass(object|string $class1, object|string $class2): bool
|
|
||||||
{
|
|
||||||
return (is_object($class1) ? $class1::class : $class1) === (is_object($class2) ? $class2::class : $class2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Тестирует наследование класса (объекта) от указанных классов
|
|
||||||
*
|
|
||||||
* @param object|string $class Объект или имя класса для проверки
|
|
||||||
* @param string[] $parents Имена классов-родителей
|
|
||||||
* @see https://www.php.net/manual/ru/function.class-parents.php
|
|
||||||
*/
|
|
||||||
public static function checkExtendsClasses(object|string $class, array $parents): bool
|
|
||||||
{
|
|
||||||
return self::checkClassesIntersection($parents, $class, 'class_parents');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Тестирует имплементацию классом (объектом) указанных интерфейсов
|
|
||||||
*
|
|
||||||
* @param object|string $actual Объект или имя класса для проверки
|
|
||||||
* @param string[] $interfaces Имена классов-интерфейсов
|
|
||||||
* @see https://www.php.net/manual/ru/function.class-implements.php
|
|
||||||
*/
|
|
||||||
public static function checkImplementsInterfaces(object|string $actual, array $interfaces): bool
|
|
||||||
{
|
|
||||||
return self::checkClassesIntersection($interfaces, $actual, 'class_implements');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Тестирует использование классом (объектом) указанных трейтов
|
|
||||||
*
|
|
||||||
* @param object|string $class
|
|
||||||
* @param string[] $traits
|
|
||||||
* @return bool
|
|
||||||
* @see https://www.php.net/manual/ru/function.class-uses.php
|
|
||||||
*/
|
|
||||||
public static function checkUsesTraits(array $traits, object|string $class): bool
|
|
||||||
{
|
|
||||||
return self::checkClassesIntersection($traits, $class, 'class_uses');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Проверяет пересечение классов указанной функцией SPL
|
|
||||||
*
|
|
||||||
* @param object|string $class Класс для проверки на вхождение, или объект, класс коего нужно проверить
|
|
||||||
* @param string[] $classes Массив классов, вхождение в который нужно проверить
|
|
||||||
* @param string $function class_parents|class_implements|class_uses
|
|
||||||
*/
|
|
||||||
protected static function checkClassesIntersection(array $classes, object|string $class, string $function): bool
|
|
||||||
{
|
|
||||||
$actual_classes = is_object($class) ? $function($class) : [$class::class];
|
|
||||||
return is_array($actual_classes)
|
|
||||||
&& !empty(array_intersect($classes, $actual_classes));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline;
|
namespace AtolOnline;
|
||||||
|
|
||||||
|
use JetBrains\PhpStorm\ArrayShape;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Константы, определяющие параметры тестовых сред
|
* Константы, определяющие параметры тестовых сред
|
||||||
*
|
*
|
||||||
@@ -23,6 +25,16 @@ final class TestEnvParams
|
|||||||
*
|
*
|
||||||
* @return string[]
|
* @return string[]
|
||||||
*/
|
*/
|
||||||
|
#[ArrayShape([
|
||||||
|
'endpoint' => "string",
|
||||||
|
'company_name' => "string",
|
||||||
|
'inn' => "string",
|
||||||
|
'payment_address' => "string",
|
||||||
|
'group' => "string",
|
||||||
|
'login' => "string",
|
||||||
|
'password' => "string",
|
||||||
|
'endpoint_ofd' => "string",
|
||||||
|
])]
|
||||||
public static function FFD105(): array
|
public static function FFD105(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -41,7 +53,18 @@ final class TestEnvParams
|
|||||||
* Возвращает данные для работы с тестовой средой АТОЛ Онлайн ФФД 1.2
|
* Возвращает данные для работы с тестовой средой АТОЛ Онлайн ФФД 1.2
|
||||||
*
|
*
|
||||||
* @return string[]
|
* @return string[]
|
||||||
|
* @noinspection PhpUnused
|
||||||
*/
|
*/
|
||||||
|
#[ArrayShape([
|
||||||
|
'endpoint' => "string",
|
||||||
|
'company_name' => "string",
|
||||||
|
'inn' => "string",
|
||||||
|
'payment_address' => "string",
|
||||||
|
'group' => "string",
|
||||||
|
'login' => "string",
|
||||||
|
'password' => "string",
|
||||||
|
'endpoint_ofd' => "string",
|
||||||
|
])]
|
||||||
public static function FFD12(): array
|
public static function FFD12(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|||||||
57
src/Traits/HasEmail.php
Normal file
57
src/Traits/HasEmail.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
|
||||||
|
*
|
||||||
|
* This code is licensed under MIT.
|
||||||
|
* Этот код распространяется по лицензии MIT.
|
||||||
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AtolOnline\Traits;
|
||||||
|
|
||||||
|
use AtolOnline\Constants\Constraints;
|
||||||
|
use AtolOnline\Exceptions\InvalidEmailException;
|
||||||
|
use AtolOnline\Exceptions\TooLongEmailException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для сущностей, которые могут иметь email
|
||||||
|
*/
|
||||||
|
trait HasEmail
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string|null Email (1008, 1117)
|
||||||
|
*/
|
||||||
|
protected ?string $email = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает email
|
||||||
|
*
|
||||||
|
* @param string|null $email
|
||||||
|
* @return $this
|
||||||
|
* @throws TooLongEmailException
|
||||||
|
* @throws InvalidEmailException
|
||||||
|
*/
|
||||||
|
public function setEmail(?string $email): static
|
||||||
|
{
|
||||||
|
if (is_string($email)) {
|
||||||
|
$email = preg_replace('/[\n\r\t]/', '', trim($email));
|
||||||
|
if (mb_strlen($email) > Constraints::MAX_LENGTH_EMAIL) {
|
||||||
|
throw new TooLongEmailException($email);
|
||||||
|
} elseif (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
|
||||||
|
throw new InvalidEmailException($email);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->email = $email ?: null;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленный email
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getEmail(): ?string
|
||||||
|
{
|
||||||
|
return $this->email;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/Traits/HasInn.php
Normal file
53
src/Traits/HasInn.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
|
||||||
|
*
|
||||||
|
* This code is licensed under MIT.
|
||||||
|
* Этот код распространяется по лицензии MIT.
|
||||||
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AtolOnline\Traits;
|
||||||
|
|
||||||
|
use AtolOnline\Constants\Constraints;
|
||||||
|
use AtolOnline\Exceptions\InvalidInnLengthException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для сущностей, которые могут иметь ИНН
|
||||||
|
*/
|
||||||
|
trait HasInn
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string|null ИНН (1226, 1228, 1018)
|
||||||
|
*/
|
||||||
|
protected ?string $inn = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает ИНН
|
||||||
|
*
|
||||||
|
* @param string|null $inn
|
||||||
|
* @return $this
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
*/
|
||||||
|
public function setInn(?string $inn): static
|
||||||
|
{
|
||||||
|
if (is_string($inn)) {
|
||||||
|
$inn = preg_replace('/[^\d]/', '', trim($inn));
|
||||||
|
if (preg_match_all(Constraints::PATTERN_INN, $inn) === 0) {
|
||||||
|
throw new InvalidInnLengthException($inn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->inn = $inn ?: null;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленный ИНН
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getInn(): ?string
|
||||||
|
{
|
||||||
|
return $this->inn;
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/Traits/HasPhones.php
Normal file
57
src/Traits/HasPhones.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
|
||||||
|
*
|
||||||
|
* This code is licensed under MIT.
|
||||||
|
* Этот код распространяется по лицензии MIT.
|
||||||
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AtolOnline\Traits;
|
||||||
|
|
||||||
|
use AtolOnline\Constants\Constraints;
|
||||||
|
use AtolOnline\Exceptions\InvalidPhoneException;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для сущностей, которые могут иметь массив номеров телефонов
|
||||||
|
*/
|
||||||
|
trait HasPhones
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Collection Телефоны платёжного агента (1073), поставщика (1171), оператора по приёму платежей (1074)
|
||||||
|
*/
|
||||||
|
protected Collection $phones;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливает массив номеров телефонов
|
||||||
|
*
|
||||||
|
* @param array|Collection|null $phones
|
||||||
|
* @return $this
|
||||||
|
* @throws InvalidPhoneException
|
||||||
|
*/
|
||||||
|
public function setPhones(array|Collection|null $phones): static
|
||||||
|
{
|
||||||
|
if (!is_null($phones)) {
|
||||||
|
$phones = is_array($phones) ? collect($phones) : $phones;
|
||||||
|
$phones->each(function ($phone) {
|
||||||
|
$phone = preg_replace('/[^\d]/', '', trim($phone));
|
||||||
|
if (preg_match(Constraints::PATTERN_PHONE, $phone) != 1) {
|
||||||
|
throw new InvalidPhoneException($phone);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$this->phones = empty($phones) ? collect() : $phones;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает установленные номера телефонов
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getPhones(): Collection
|
||||||
|
{
|
||||||
|
return $this->phones;
|
||||||
|
}
|
||||||
|
}
|
||||||
400
tests/AtolOnline/Tests/Api/FiscalizerTest.php
Normal file
400
tests/AtolOnline/Tests/Api/FiscalizerTest.php
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
|
||||||
|
*
|
||||||
|
* This code is licensed under MIT.
|
||||||
|
* Этот код распространяется по лицензии MIT.
|
||||||
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AtolOnline\Tests\Api;
|
||||||
|
|
||||||
|
use AtolOnline\{
|
||||||
|
Constants\Constraints,
|
||||||
|
Helpers,
|
||||||
|
TestEnvParams,
|
||||||
|
Tests\BasicTestCase};
|
||||||
|
use AtolOnline\Api\{
|
||||||
|
AtolClient,
|
||||||
|
Fiscalizer};
|
||||||
|
use AtolOnline\Exceptions\{
|
||||||
|
AuthFailedException,
|
||||||
|
EmptyCorrectionNumberException,
|
||||||
|
EmptyGroupException,
|
||||||
|
EmptyItemNameException,
|
||||||
|
EmptyItemsException,
|
||||||
|
EmptyLoginException,
|
||||||
|
EmptyPasswordException,
|
||||||
|
InvalidCallbackUrlException,
|
||||||
|
InvalidCorrectionDateException,
|
||||||
|
InvalidEntityInCollectionException,
|
||||||
|
InvalidEnumValueException,
|
||||||
|
InvalidInnLengthException,
|
||||||
|
InvalidPaymentAddressException,
|
||||||
|
InvalidUuidException,
|
||||||
|
NegativeItemPriceException,
|
||||||
|
NegativeItemQuantityException,
|
||||||
|
NegativePaymentSumException,
|
||||||
|
TooHighItemPriceException,
|
||||||
|
TooHighPaymentSumException,
|
||||||
|
TooLongCallbackUrlException,
|
||||||
|
TooLongItemNameException,
|
||||||
|
TooLongPaymentAddressException,
|
||||||
|
TooManyException};
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Набор тестов для проверки работы фискализатора
|
||||||
|
*/
|
||||||
|
class FiscalizerTest extends BasicTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array Массив UUID-ов результатов регистрации документов для переиспользования
|
||||||
|
* в тестах получения их статусов фискализации
|
||||||
|
*/
|
||||||
|
private static array $registered_uuids = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует успешное создание объекта фискализатора без аргументов конструктора
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer
|
||||||
|
*/
|
||||||
|
public function testConstructorWithourArgs(): void
|
||||||
|
{
|
||||||
|
$fisc = new Fiscalizer();
|
||||||
|
$this->assertIsObject($fisc);
|
||||||
|
$this->assertIsSameClass(Fiscalizer::class, $fisc);
|
||||||
|
$this->assertExtendsClasses([AtolClient::class], $fisc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует установку и возврат группы ККТ
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getGroup
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::setGroup
|
||||||
|
*/
|
||||||
|
public function testGroup(): void
|
||||||
|
{
|
||||||
|
// test mode
|
||||||
|
$this->assertEquals(
|
||||||
|
TestEnvParams::FFD105()['group'],
|
||||||
|
(new Fiscalizer(group: 'group'))->getGroup()
|
||||||
|
);
|
||||||
|
// prod mode
|
||||||
|
$this->assertEquals('group', (new Fiscalizer(false, group: 'group'))->getGroup());
|
||||||
|
$this->assertNull((new Fiscalizer(false))->getGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует выброс исключения при попытке передать пустую группу ККТ в конструктор
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::setGroup
|
||||||
|
* @covers \AtolOnline\Exceptions\EmptyGroupException
|
||||||
|
*/
|
||||||
|
public function testEmptyGroupException(): void
|
||||||
|
{
|
||||||
|
$this->expectException(EmptyGroupException::class);
|
||||||
|
new Fiscalizer(group: "\n\r \0\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует выброс исключения при попытке установить слишком длинный адрес колбека
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::setCallbackUrl
|
||||||
|
* @covers \AtolOnline\Exceptions\TooLongCallbackUrlException
|
||||||
|
* @throws InvalidCallbackUrlException
|
||||||
|
* @throws TooLongCallbackUrlException
|
||||||
|
*/
|
||||||
|
public function testTooLongCallbackUrlException(): void
|
||||||
|
{
|
||||||
|
$this->expectException(TooLongCallbackUrlException::class);
|
||||||
|
(new Fiscalizer())->setCallbackUrl(Helpers::randomStr(Constraints::MAX_LENGTH_CALLBACK_URL + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует выброс исключения при попытке установить слишком длинный адрес колбека
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::setCallbackUrl
|
||||||
|
* @covers \AtolOnline\Exceptions\InvalidCallbackUrlException
|
||||||
|
* @throws InvalidCallbackUrlException
|
||||||
|
* @throws TooLongCallbackUrlException
|
||||||
|
*/
|
||||||
|
public function testInvalidCallbackUrlException(): void
|
||||||
|
{
|
||||||
|
$this->expectException(InvalidCallbackUrlException::class);
|
||||||
|
(new Fiscalizer())->setCallbackUrl(Helpers::randomStr());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует обнуление адреса колбека
|
||||||
|
*
|
||||||
|
* @param mixed $param
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::setCallbackUrl
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getCallbackUrl
|
||||||
|
* @dataProvider providerNullableStrings
|
||||||
|
* @throws InvalidCallbackUrlException
|
||||||
|
* @throws TooLongCallbackUrlException
|
||||||
|
*/
|
||||||
|
public function testNullableCallbackUrl(mixed $param): void
|
||||||
|
{
|
||||||
|
$this->assertNull((new Fiscalizer())->setCallbackUrl($param)->getCallbackUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует регистрацию документа прихода
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Entities\Receipt::sell
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::sell
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getFullUrl
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getAuthEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getMainEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::registerDocument
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyItemNameException
|
||||||
|
* @throws EmptyItemsException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws NegativeItemPriceException
|
||||||
|
* @throws NegativeItemQuantityException
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
|
* @throws TooHighItemPriceException
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws TooLongItemNameException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
* @throws TooManyException
|
||||||
|
* @throws GuzzleException
|
||||||
|
*/
|
||||||
|
public function testSell(): void
|
||||||
|
{
|
||||||
|
$fisc_result = $this->newReceipt()->sell(new Fiscalizer());
|
||||||
|
$this->assertTrue($fisc_result->isSuccessful());
|
||||||
|
$this->assertEquals('wait', $fisc_result->getContent()->status);
|
||||||
|
self::$registered_uuids[] = $fisc_result->getContent()->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует регистрацию документа возврата прихода
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Entities\Receipt::sellRefund
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::sellRefund
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getFullUrl
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getAuthEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getMainEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::registerDocument
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyItemNameException
|
||||||
|
* @throws EmptyItemsException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws NegativeItemPriceException
|
||||||
|
* @throws NegativeItemQuantityException
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
|
* @throws TooHighItemPriceException
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws TooLongItemNameException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
* @throws TooManyException
|
||||||
|
* @throws GuzzleException
|
||||||
|
*/
|
||||||
|
public function testSellRefund(): void
|
||||||
|
{
|
||||||
|
$fisc_result = $this->newReceipt()->sellRefund(new Fiscalizer());
|
||||||
|
$this->assertTrue($fisc_result->isSuccessful());
|
||||||
|
$this->assertEquals('wait', $fisc_result->getContent()->status);
|
||||||
|
self::$registered_uuids[] = $fisc_result->getContent()->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует регистрацию документа возврата прихода
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Entities\Correction::sellCorrect
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::sellCorrect
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getFullUrl
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getAuthEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getMainEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::registerDocument
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
* @throws EmptyCorrectionNumberException
|
||||||
|
* @throws InvalidCorrectionDateException
|
||||||
|
*/
|
||||||
|
public function testSellCorrect(): void
|
||||||
|
{
|
||||||
|
$fisc_result = $this->newCorrection()->sellCorrect(new Fiscalizer());
|
||||||
|
$this->assertTrue($fisc_result->isSuccessful());
|
||||||
|
$this->assertEquals('wait', $fisc_result->getContent()->status);
|
||||||
|
//self::$registered_uuids[] = $fisc_result->getContent()->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует регистрацию документа расхода
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Entities\Receipt::buy
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::buy
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getFullUrl
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getAuthEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getMainEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::registerDocument
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyItemNameException
|
||||||
|
* @throws EmptyItemsException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws NegativeItemPriceException
|
||||||
|
* @throws NegativeItemQuantityException
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
|
* @throws TooHighItemPriceException
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws TooLongItemNameException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
* @throws TooManyException
|
||||||
|
* @throws GuzzleException
|
||||||
|
*/
|
||||||
|
public function testBuy(): void
|
||||||
|
{
|
||||||
|
$fisc_result = $this->newReceipt()->buy(new Fiscalizer());
|
||||||
|
$this->assertTrue($fisc_result->isSuccessful());
|
||||||
|
$this->assertEquals('wait', $fisc_result->getContent()->status);
|
||||||
|
//self::$registered_uuids[] = $fisc_result->getContent()->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует регистрацию документа возврата расхода
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Entities\Receipt::buyRefund
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::buyRefund
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getFullUrl
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getAuthEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getMainEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::registerDocument
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyItemNameException
|
||||||
|
* @throws EmptyItemsException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws NegativeItemPriceException
|
||||||
|
* @throws NegativeItemQuantityException
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
|
* @throws TooHighItemPriceException
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws TooLongItemNameException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
* @throws TooManyException
|
||||||
|
* @throws GuzzleException
|
||||||
|
*/
|
||||||
|
public function testBuyRefund(): void
|
||||||
|
{
|
||||||
|
$fisc_result = $this->newReceipt()->buyRefund(new Fiscalizer());
|
||||||
|
$this->assertTrue($fisc_result->isSuccessful());
|
||||||
|
$this->assertEquals('wait', $fisc_result->getContent()->status);
|
||||||
|
//self::$registered_uuids[] = $fisc_result->getContent()->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует регистрацию документа возврата прихода
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Entities\Correction::buyCorrect
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::buyCorrect
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getFullUrl
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getAuthEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getMainEndpoint
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::registerDocument
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws InvalidInnLengthException
|
||||||
|
* @throws InvalidPaymentAddressException
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws TooLongPaymentAddressException
|
||||||
|
* @throws EmptyCorrectionNumberException
|
||||||
|
* @throws InvalidCorrectionDateException
|
||||||
|
*/
|
||||||
|
public function testBuyCorrect(): void
|
||||||
|
{
|
||||||
|
$fisc_result = $this->newCorrection()->buyCorrect(new Fiscalizer());
|
||||||
|
$this->assertTrue($fisc_result->isSuccessful());
|
||||||
|
$this->assertEquals('wait', $fisc_result->getContent()->status);
|
||||||
|
//self::$registered_uuids[] = $fisc_result->getContent()->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует разовое получение статуса фискализации документа
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::getDocumentStatus
|
||||||
|
* @depends testSell
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidUuidException
|
||||||
|
*/
|
||||||
|
public function testGetDocumentStatus(): void
|
||||||
|
{
|
||||||
|
$fisc_status = (new Fiscalizer())->getDocumentStatus(array_shift(self::$registered_uuids));
|
||||||
|
//$this->assertTrue($fisc_status->isSuccessful());
|
||||||
|
$this->assertTrue(in_array($fisc_status->getContent()->status, ['wait', 'done']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует опрос API на получение статуса фискализации документа
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @covers \AtolOnline\Api\Fiscalizer::pollDocumentStatus
|
||||||
|
* @depends testSellRefund
|
||||||
|
* @throws AuthFailedException
|
||||||
|
* @throws EmptyLoginException
|
||||||
|
* @throws EmptyPasswordException
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws InvalidUuidException
|
||||||
|
*/
|
||||||
|
public function testPollDocumentStatus(): void
|
||||||
|
{
|
||||||
|
$fisc_status = (new Fiscalizer())->pollDocumentStatus(array_shift(self::$registered_uuids));
|
||||||
|
//$this->assertTrue($fisc_status->isSuccessful());
|
||||||
|
$this->assertEquals('done', $fisc_status->getContent()->status);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,8 +10,8 @@
|
|||||||
namespace AtolOnline\Tests\Api;
|
namespace AtolOnline\Tests\Api;
|
||||||
|
|
||||||
use AtolOnline\Api\AtolClient;
|
use AtolOnline\Api\AtolClient;
|
||||||
use AtolOnline\Api\KktMonitor;
|
use AtolOnline\Api\AtolResponse;
|
||||||
use AtolOnline\Api\KktResponse;
|
use AtolOnline\Api\Monitor;
|
||||||
use AtolOnline\Entities\Kkt;
|
use AtolOnline\Entities\Kkt;
|
||||||
use AtolOnline\Exceptions\AuthFailedException;
|
use AtolOnline\Exceptions\AuthFailedException;
|
||||||
use AtolOnline\Exceptions\EmptyLoginException;
|
use AtolOnline\Exceptions\EmptyLoginException;
|
||||||
@@ -23,51 +23,51 @@ use AtolOnline\Exceptions\TooLongPasswordException;
|
|||||||
use AtolOnline\Helpers;
|
use AtolOnline\Helpers;
|
||||||
use AtolOnline\TestEnvParams;
|
use AtolOnline\TestEnvParams;
|
||||||
use AtolOnline\Tests\BasicTestCase;
|
use AtolOnline\Tests\BasicTestCase;
|
||||||
|
use Exception;
|
||||||
use GuzzleHttp\Exception\GuzzleException;
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Набор тестов для проверки работы API-клиента на примере монитора ККТ
|
* Набор тестов для проверки работы API-клиента на примере монитора ККТ
|
||||||
*/
|
*/
|
||||||
class KktMonitorTest extends BasicTestCase
|
class MonitorTest extends BasicTestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Возвращает объект клиента для тестирования с тестовым API АТОЛ
|
* Возвращает объект монитора для тестирования с тестовым API АТОЛ
|
||||||
*
|
*
|
||||||
* @return KktMonitor
|
* @return Monitor
|
||||||
* @throws EmptyLoginException
|
* @throws EmptyLoginException
|
||||||
* @throws EmptyPasswordException
|
* @throws EmptyPasswordException
|
||||||
* @throws TooLongLoginException
|
* @throws TooLongLoginException
|
||||||
* @throws TooLongPasswordException
|
* @throws TooLongPasswordException
|
||||||
*/
|
*/
|
||||||
private function newTestClient(): KktMonitor
|
private function newTestClient(): Monitor
|
||||||
{
|
{
|
||||||
$credentials = TestEnvParams::FFD105();
|
return (new Monitor(true))
|
||||||
return (new KktMonitor(true))
|
->setLogin(TestEnvParams::FFD105()['login'])
|
||||||
->setLogin($credentials['login'])
|
->setPassword(TestEnvParams::FFD105()['password']);
|
||||||
->setPassword($credentials['password']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует успешное создание объекта монитора без аргументов конструктора
|
* Тестирует успешное создание объекта монитора без аргументов конструктора
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Api\KktMonitor::__construct
|
* @covers \AtolOnline\Api\Monitor::__construct
|
||||||
*/
|
*/
|
||||||
public function testConstructorWithoutArgs(): void
|
public function testConstructorWithoutArgs(): void
|
||||||
{
|
{
|
||||||
$client = new KktMonitor();
|
$client = new Monitor();
|
||||||
$this->assertIsObject($client);
|
$this->assertIsObject($client);
|
||||||
$this->assertIsSameClass(KktMonitor::class, $client);
|
$this->assertIsSameClass(Monitor::class, $client);
|
||||||
$this->assertExtendsClasses($client, [AtolClient::class]);
|
$this->assertExtendsClasses([AtolClient::class], $client);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует успешное создание объекта монитора с аргументами конструктора
|
* Тестирует успешное создание объекта монитора с аргументами конструктора
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Api\KktMonitor::__construct
|
* @covers \AtolOnline\Api\Monitor::__construct
|
||||||
* @covers \AtolOnline\Api\KktMonitor::setLogin
|
* @covers \AtolOnline\Api\Monitor::setLogin
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getLogin
|
* @covers \AtolOnline\Api\Monitor::getLogin
|
||||||
* @covers \AtolOnline\Api\KktMonitor::setPassword
|
* @covers \AtolOnline\Api\Monitor::setPassword
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getPassword
|
* @covers \AtolOnline\Api\Monitor::getPassword
|
||||||
* @throws EmptyLoginException
|
* @throws EmptyLoginException
|
||||||
* @throws EmptyPasswordException
|
* @throws EmptyPasswordException
|
||||||
* @throws TooLongLoginException
|
* @throws TooLongLoginException
|
||||||
@@ -75,51 +75,52 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
*/
|
*/
|
||||||
public function testConstructorWithArgs(): void
|
public function testConstructorWithArgs(): void
|
||||||
{
|
{
|
||||||
$client = new KktMonitor(false, 'login', 'password', []);
|
$client = new Monitor(false, 'login', 'password', []);
|
||||||
$this->assertIsObject($client);
|
$this->assertIsObject($client);
|
||||||
$this->assertIsSameClass($client, KktMonitor::class);
|
$this->assertIsSameClass($client, Monitor::class);
|
||||||
$this->assertExtendsClasses($client, [AtolClient::class]);
|
$this->assertExtendsClasses([AtolClient::class], $client);
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует установку и возврат логина
|
* Тестирует установку и возврат логина
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Api\KktMonitor::__construct
|
* @covers \AtolOnline\Api\Monitor::__construct
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getLogin
|
* @covers \AtolOnline\Api\Monitor::getLogin
|
||||||
* @covers \AtolOnline\Api\KktMonitor::setLogin
|
* @covers \AtolOnline\Api\Monitor::setLogin
|
||||||
* @throws EmptyLoginException
|
* @throws EmptyLoginException
|
||||||
* @throws TooLongLoginException
|
* @throws TooLongLoginException
|
||||||
*/
|
*/
|
||||||
public function testLogin(): void
|
public function testLogin(): void
|
||||||
{
|
{
|
||||||
$client = new KktMonitor(login: 'login');
|
$client = new Monitor(false, login: 'login');
|
||||||
$this->assertEquals('login', $client->getLogin());
|
$this->assertEquals('login', $client->getLogin());
|
||||||
|
|
||||||
$client = new KktMonitor();
|
$client = new Monitor();
|
||||||
$this->assertNull($client->getLogin());
|
$this->assertEquals(TestEnvParams::FFD105()['login'], $client->getLogin());
|
||||||
|
|
||||||
$client->setLogin('login');
|
$client->setLogin('login');
|
||||||
$this->assertEquals('login', $client->getLogin());
|
$this->assertEquals(TestEnvParams::FFD105()['login'], $client->getLogin());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует исключение при попытке передать пустой логин в конструктор
|
* Тестирует исключение при попытке передать пустой логин в конструктор
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Api\KktMonitor::__construct
|
* @covers \AtolOnline\Api\Monitor::__construct
|
||||||
* @covers \AtolOnline\Api\KktMonitor::setLogin
|
* @covers \AtolOnline\Api\Monitor::setLogin
|
||||||
* @covers \AtolOnline\Exceptions\EmptyLoginException
|
* @covers \AtolOnline\Exceptions\EmptyLoginException
|
||||||
*/
|
*/
|
||||||
public function testEmptyLoginException(): void
|
public function testEmptyLoginException(): void
|
||||||
{
|
{
|
||||||
$this->expectException(EmptyLoginException::class);
|
$this->expectException(EmptyLoginException::class);
|
||||||
new KktMonitor(login: '');
|
new Monitor(login: '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует исключение при попытке передать слишком длинный логин в конструктор
|
* Тестирует исключение при попытке передать слишком длинный логин в конструктор
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Api\KktMonitor::__construct
|
* @covers \AtolOnline\Api\Monitor::__construct
|
||||||
* @covers \AtolOnline\Api\KktMonitor::setLogin
|
* @covers \AtolOnline\Api\Monitor::setLogin
|
||||||
* @covers \AtolOnline\Exceptions\TooLongLoginException
|
* @covers \AtolOnline\Exceptions\TooLongLoginException
|
||||||
* @throws EmptyLoginException
|
* @throws EmptyLoginException
|
||||||
* @throws EmptyPasswordException
|
* @throws EmptyPasswordException
|
||||||
@@ -129,48 +130,48 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
public function testTooLongLoginException(): void
|
public function testTooLongLoginException(): void
|
||||||
{
|
{
|
||||||
$this->expectException(TooLongLoginException::class);
|
$this->expectException(TooLongLoginException::class);
|
||||||
new KktMonitor(login: Helpers::randomStr(101));
|
new Monitor(login: Helpers::randomStr(101));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует установку и возврат пароля
|
* Тестирует установку и возврат пароля
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Api\KktMonitor::__construct
|
* @covers \AtolOnline\Api\Monitor::__construct
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getPassword
|
* @covers \AtolOnline\Api\Monitor::getPassword
|
||||||
* @covers \AtolOnline\Api\KktMonitor::setPassword
|
* @covers \AtolOnline\Api\Monitor::setPassword
|
||||||
* @throws EmptyPasswordException
|
* @throws EmptyPasswordException
|
||||||
* @throws TooLongPasswordException
|
* @throws TooLongPasswordException
|
||||||
*/
|
*/
|
||||||
public function testPassword(): void
|
public function testPassword(): void
|
||||||
{
|
{
|
||||||
$client = new KktMonitor(password: 'password');
|
$client = new Monitor(false, password: 'password');
|
||||||
$this->assertEquals('password', $client->getPassword());
|
$this->assertEquals('password', $client->getPassword());
|
||||||
|
|
||||||
$client = new KktMonitor();
|
$client = new Monitor();
|
||||||
$this->assertNull($client->getPassword());
|
$this->assertEquals(TestEnvParams::FFD105()['password'], $client->getPassword());
|
||||||
|
|
||||||
$client->setPassword('password');
|
$client->setPassword('password');
|
||||||
$this->assertEquals('password', $client->getPassword());
|
$this->assertEquals(TestEnvParams::FFD105()['password'], $client->getPassword());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует исключение при попытке передать пустой пароль в конструктор
|
* Тестирует исключение при попытке передать пустой пароль в конструктор
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Api\KktMonitor::__construct
|
* @covers \AtolOnline\Api\Monitor::__construct
|
||||||
* @covers \AtolOnline\Api\KktMonitor::setPassword
|
* @covers \AtolOnline\Api\Monitor::setPassword
|
||||||
* @covers \AtolOnline\Exceptions\EmptyPasswordException
|
* @covers \AtolOnline\Exceptions\EmptyPasswordException
|
||||||
*/
|
*/
|
||||||
public function testEmptyPasswordException(): void
|
public function testEmptyPasswordException(): void
|
||||||
{
|
{
|
||||||
$this->expectException(EmptyPasswordException::class);
|
$this->expectException(EmptyPasswordException::class);
|
||||||
new KktMonitor(password: '');
|
new Monitor(password: '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует исключение при попытке передать слишком длинный пароль в конструктор
|
* Тестирует исключение при попытке передать слишком длинный пароль в конструктор
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Api\KktMonitor::__construct
|
* @covers \AtolOnline\Api\Monitor::__construct
|
||||||
* @covers \AtolOnline\Api\KktMonitor::setPassword
|
* @covers \AtolOnline\Api\Monitor::setPassword
|
||||||
* @throws EmptyLoginException
|
* @throws EmptyLoginException
|
||||||
* @throws EmptyPasswordException
|
* @throws EmptyPasswordException
|
||||||
* @throws TooLongLoginException
|
* @throws TooLongLoginException
|
||||||
@@ -179,34 +180,34 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
public function testConstructorWithLongPassword(): void
|
public function testConstructorWithLongPassword(): void
|
||||||
{
|
{
|
||||||
$this->expectException(TooLongPasswordException::class);
|
$this->expectException(TooLongPasswordException::class);
|
||||||
new KktMonitor(password: Helpers::randomStr(101));
|
new Monitor(password: Helpers::randomStr(101));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует установку тестового режима
|
* Тестирует установку тестового режима
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Api\KktMonitor::__construct
|
* @covers \AtolOnline\Api\Monitor::__construct
|
||||||
* @covers \AtolOnline\Api\KktMonitor::isTestMode
|
* @covers \AtolOnline\Api\Monitor::isTestMode
|
||||||
* @covers \AtolOnline\Api\KktMonitor::setTestMode
|
* @covers \AtolOnline\Api\Monitor::setTestMode
|
||||||
*/
|
*/
|
||||||
public function testTestMode(): void
|
public function testTestMode(): void
|
||||||
{
|
{
|
||||||
$client = new KktMonitor();
|
$client = new Monitor();
|
||||||
$this->assertTrue($client->isTestMode());
|
$this->assertTrue($client->isTestMode());
|
||||||
|
|
||||||
$client = new KktMonitor(true);
|
$client = new Monitor(true);
|
||||||
$this->assertTrue($client->isTestMode());
|
$this->assertTrue($client->isTestMode());
|
||||||
|
|
||||||
$client = new KktMonitor(false);
|
$client = new Monitor(false);
|
||||||
$this->assertFalse($client->isTestMode());
|
$this->assertFalse($client->isTestMode());
|
||||||
|
|
||||||
$client = (new KktMonitor())->setTestMode();
|
$client = (new Monitor())->setTestMode();
|
||||||
$this->assertTrue($client->isTestMode());
|
$this->assertTrue($client->isTestMode());
|
||||||
|
|
||||||
$client = (new KktMonitor())->setTestMode(true);
|
$client = (new Monitor())->setTestMode(true);
|
||||||
$this->assertTrue($client->isTestMode());
|
$this->assertTrue($client->isTestMode());
|
||||||
|
|
||||||
$client = (new KktMonitor())->setTestMode(false);
|
$client = (new Monitor())->setTestMode(false);
|
||||||
$this->assertFalse($client->isTestMode());
|
$this->assertFalse($client->isTestMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,10 +215,10 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
* Тестирует авторизацию
|
* Тестирует авторизацию
|
||||||
*
|
*
|
||||||
* @covers \AtolOnline\Api\AtolClient::getHeaders
|
* @covers \AtolOnline\Api\AtolClient::getHeaders
|
||||||
* @covers \AtolOnline\Api\KktMonitor::sendRequest
|
* @covers \AtolOnline\Api\Monitor::sendRequest
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getAuthEndpoint
|
* @covers \AtolOnline\Api\Monitor::getAuthEndpoint
|
||||||
* @covers \AtolOnline\Api\KktMonitor::doAuth
|
* @covers \AtolOnline\Api\Monitor::doAuth
|
||||||
* @covers \AtolOnline\Api\KktMonitor::auth
|
* @covers \AtolOnline\Api\Monitor::auth
|
||||||
* @covers \AtolOnline\Exceptions\AuthFailedException
|
* @covers \AtolOnline\Exceptions\AuthFailedException
|
||||||
* @throws EmptyLoginException
|
* @throws EmptyLoginException
|
||||||
* @throws EmptyPasswordException
|
* @throws EmptyPasswordException
|
||||||
@@ -237,8 +238,8 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
* Тестирует возврат токена после авторизации
|
* Тестирует возврат токена после авторизации
|
||||||
*
|
*
|
||||||
* @depends testAuth
|
* @depends testAuth
|
||||||
* @covers \AtolOnline\Api\KktMonitor::setToken
|
* @covers \AtolOnline\Api\Monitor::setToken
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getToken
|
* @covers \AtolOnline\Api\Monitor::getToken
|
||||||
* @covers \AtolOnline\Exceptions\AuthFailedException
|
* @covers \AtolOnline\Exceptions\AuthFailedException
|
||||||
* @throws AuthFailedException
|
* @throws AuthFailedException
|
||||||
* @throws EmptyLoginException
|
* @throws EmptyLoginException
|
||||||
@@ -249,7 +250,7 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
*/
|
*/
|
||||||
public function testGetToken(): void
|
public function testGetToken(): void
|
||||||
{
|
{
|
||||||
$client = new KktMonitor();
|
$client = new Monitor();
|
||||||
$this->assertNull($client->getToken());
|
$this->assertNull($client->getToken());
|
||||||
|
|
||||||
$this->skipIfMonitoringIsOffline();
|
$this->skipIfMonitoringIsOffline();
|
||||||
@@ -262,7 +263,7 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
* Тестирует возврат объекта последнего ответа от API
|
* Тестирует возврат объекта последнего ответа от API
|
||||||
*
|
*
|
||||||
* @depends testAuth
|
* @depends testAuth
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getResponse
|
* @covers \AtolOnline\Api\Monitor::getLastResponse
|
||||||
* @covers \AtolOnline\Exceptions\AuthFailedException
|
* @covers \AtolOnline\Exceptions\AuthFailedException
|
||||||
* @throws AuthFailedException
|
* @throws AuthFailedException
|
||||||
* @throws EmptyLoginException
|
* @throws EmptyLoginException
|
||||||
@@ -276,17 +277,17 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
$this->skipIfMonitoringIsOffline();
|
$this->skipIfMonitoringIsOffline();
|
||||||
$client = $this->newTestClient();
|
$client = $this->newTestClient();
|
||||||
$client->auth();
|
$client->auth();
|
||||||
$this->assertIsSameClass(KktResponse::class, $client->getResponse());
|
$this->assertIsSameClass(AtolResponse::class, $client->getLastResponse());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Мониторинг] Тестирует получение данных о всех ККТ
|
* [Мониторинг] Тестирует получение данных о всех ККТ
|
||||||
*
|
*
|
||||||
* @depends testAuth
|
* @depends testAuth
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getMainEndpoint
|
* @covers \AtolOnline\Api\Monitor::getMainEndpoint
|
||||||
* @covers \AtolOnline\Api\AtolClient::getUrlToMethod
|
* @covers \AtolOnline\Api\AtolClient::getUrlToMethod
|
||||||
* @covers \AtolOnline\Api\KktMonitor::fetchAll
|
* @covers \AtolOnline\Api\Monitor::fetchAll
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getAll
|
* @covers \AtolOnline\Api\Monitor::getAll
|
||||||
* @covers \AtolOnline\Exceptions\AuthFailedException
|
* @covers \AtolOnline\Exceptions\AuthFailedException
|
||||||
* @throws AuthFailedException
|
* @throws AuthFailedException
|
||||||
* @throws EmptyLoginException
|
* @throws EmptyLoginException
|
||||||
@@ -301,7 +302,8 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
$client = $this->newTestClient();
|
$client = $this->newTestClient();
|
||||||
$client->auth();
|
$client->auth();
|
||||||
$kkts = $client->getAll();
|
$kkts = $client->getAll();
|
||||||
$this->assertNotEmpty($client->getResponse()->getContent());
|
$sss = $kkts->where('deviceNumber', 'KKT014034');
|
||||||
|
$this->assertNotEmpty($client->getLastResponse()->getContent());
|
||||||
$this->assertIsCollection($kkts);
|
$this->assertIsCollection($kkts);
|
||||||
$this->assertTrue($kkts->count() > 0);
|
$this->assertTrue($kkts->count() > 0);
|
||||||
$this->assertIsSameClass(Kkt::class, $kkts->random());
|
$this->assertIsSameClass(Kkt::class, $kkts->random());
|
||||||
@@ -311,10 +313,10 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
* [Мониторинг] Тестирует получение данных о конкретной ККТ
|
* [Мониторинг] Тестирует получение данных о конкретной ККТ
|
||||||
*
|
*
|
||||||
* @depends testAuth
|
* @depends testAuth
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getMainEndpoint
|
* @covers \AtolOnline\Api\Monitor::getMainEndpoint
|
||||||
* @covers \AtolOnline\Api\AtolClient::getUrlToMethod
|
* @covers \AtolOnline\Api\AtolClient::getUrlToMethod
|
||||||
* @covers \AtolOnline\Api\KktMonitor::fetchOne
|
* @covers \AtolOnline\Api\Monitor::fetchOne
|
||||||
* @covers \AtolOnline\Api\KktMonitor::getOne
|
* @covers \AtolOnline\Api\Monitor::getOne
|
||||||
* @covers \AtolOnline\Entities\Kkt::__construct
|
* @covers \AtolOnline\Entities\Kkt::__construct
|
||||||
* @covers \AtolOnline\Entities\Kkt::__get
|
* @covers \AtolOnline\Entities\Kkt::__get
|
||||||
* @covers \AtolOnline\Entities\Kkt::jsonSerialize
|
* @covers \AtolOnline\Entities\Kkt::jsonSerialize
|
||||||
@@ -327,6 +329,7 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
* @throws TooLongPasswordException
|
* @throws TooLongPasswordException
|
||||||
* @throws EmptyMonitorDataException
|
* @throws EmptyMonitorDataException
|
||||||
* @throws NotEnoughMonitorDataException
|
* @throws NotEnoughMonitorDataException
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function testMonitorGetOne(): void
|
public function testMonitorGetOne(): void
|
||||||
{
|
{
|
||||||
@@ -335,9 +338,9 @@ class KktMonitorTest extends BasicTestCase
|
|||||||
$client->auth();
|
$client->auth();
|
||||||
$serial_number = $client->getAll()->first()->serialNumber;
|
$serial_number = $client->getAll()->first()->serialNumber;
|
||||||
$kkt = $client->getOne($serial_number);
|
$kkt = $client->getOne($serial_number);
|
||||||
$this->assertNotEmpty($client->getResponse());
|
$this->assertNotEmpty($client->getLastResponse());
|
||||||
$this->assertIsSameClass(Kkt::class, $kkt);
|
$this->assertIsSameClass(Kkt::class, $kkt);
|
||||||
$this->assertAtolable($kkt);
|
$this->assertIsAtolable($kkt);
|
||||||
$this->assertNotNull($kkt->serialNumber);
|
$this->assertNotNull($kkt->serialNumber);
|
||||||
$this->assertEquals($serial_number, $kkt->serialNumber);
|
$this->assertEquals($serial_number, $kkt->serialNumber);
|
||||||
}
|
}
|
||||||
@@ -11,9 +11,39 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace AtolOnline\Tests;
|
namespace AtolOnline\Tests;
|
||||||
|
|
||||||
|
use AtolOnline\Collections\EntityCollection;
|
||||||
|
use AtolOnline\Collections\Items;
|
||||||
|
use AtolOnline\Collections\Payments;
|
||||||
|
use AtolOnline\Collections\Vats;
|
||||||
|
use AtolOnline\Entities\Client;
|
||||||
|
use AtolOnline\Entities\Company;
|
||||||
|
use AtolOnline\Entities\Correction;
|
||||||
|
use AtolOnline\Entities\CorrectionInfo;
|
||||||
use AtolOnline\Entities\Entity;
|
use AtolOnline\Entities\Entity;
|
||||||
|
use AtolOnline\Entities\Item;
|
||||||
|
use AtolOnline\Entities\Payment;
|
||||||
|
use AtolOnline\Entities\Receipt;
|
||||||
|
use AtolOnline\Entities\Vat;
|
||||||
|
use AtolOnline\Enums\CorrectionTypes;
|
||||||
|
use AtolOnline\Enums\PaymentTypes;
|
||||||
|
use AtolOnline\Enums\SnoTypes;
|
||||||
|
use AtolOnline\Enums\VatTypes;
|
||||||
|
use AtolOnline\Exceptions\EmptyCorrectionNumberException;
|
||||||
|
use AtolOnline\Exceptions\EmptyItemNameException;
|
||||||
|
use AtolOnline\Exceptions\EmptyItemsException;
|
||||||
|
use AtolOnline\Exceptions\InvalidCorrectionDateException;
|
||||||
|
use AtolOnline\Exceptions\InvalidEntityInCollectionException;
|
||||||
|
use AtolOnline\Exceptions\InvalidEnumValueException;
|
||||||
|
use AtolOnline\Exceptions\NegativeItemPriceException;
|
||||||
|
use AtolOnline\Exceptions\NegativeItemQuantityException;
|
||||||
|
use AtolOnline\Exceptions\NegativePaymentSumException;
|
||||||
|
use AtolOnline\Exceptions\TooHighItemPriceException;
|
||||||
|
use AtolOnline\Exceptions\TooHighPaymentSumException;
|
||||||
|
use AtolOnline\Exceptions\TooLongItemNameException;
|
||||||
|
use AtolOnline\Exceptions\TooManyException;
|
||||||
use AtolOnline\Helpers;
|
use AtolOnline\Helpers;
|
||||||
use GuzzleHttp\Client;
|
use Exception;
|
||||||
|
use GuzzleHttp\Client as GuzzleClient;
|
||||||
use GuzzleHttp\Exception\GuzzleException;
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
@@ -23,6 +53,10 @@ use PHPUnit\Framework\TestCase;
|
|||||||
*/
|
*/
|
||||||
class BasicTestCase extends TestCase
|
class BasicTestCase extends TestCase
|
||||||
{
|
{
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Методы для управления тестами, использующими тестовый АТОЛ API
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Проверяет наличие подключения к ресурсу по URL
|
* Проверяет наличие подключения к ресурсу по URL
|
||||||
*
|
*
|
||||||
@@ -33,7 +67,7 @@ class BasicTestCase extends TestCase
|
|||||||
protected function ping(string $url, int $code): bool
|
protected function ping(string $url, int $code): bool
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$result = (new Client([
|
$result = (new GuzzleClient([
|
||||||
'http_errors' => false,
|
'http_errors' => false,
|
||||||
'timeout' => 3,
|
'timeout' => 3,
|
||||||
]))->request('GET', $url);
|
]))->request('GET', $url);
|
||||||
@@ -63,17 +97,26 @@ class BasicTestCase extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Дополнительные ассерты
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует является ли объект приводимым к json-строке согласно схеме АТОЛ Онлайн
|
* Тестирует является ли объект приводимым к json-строке согласно схеме АТОЛ Онлайн
|
||||||
*
|
*
|
||||||
* @param Entity $entity
|
* @param Entity|EntityCollection $entity
|
||||||
* @param array|null $json_structure
|
* @param array|null $json_structure
|
||||||
* @covers \AtolOnline\Entities\Entity::jsonSerialize
|
|
||||||
* @covers \AtolOnline\Entities\Entity::__toString
|
* @covers \AtolOnline\Entities\Entity::__toString
|
||||||
|
* @covers \AtolOnline\Entities\Entity::toArray
|
||||||
|
* @covers \AtolOnline\Entities\Entity::jsonSerialize
|
||||||
|
* @covers \AtolOnline\Collections\EntityCollection::jsonSerialize
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function assertAtolable(Entity $entity, ?array $json_structure = null): void
|
public function assertIsAtolable(Entity|EntityCollection $entity, ?array $json_structure = null): void
|
||||||
{
|
{
|
||||||
$this->assertIsArray($entity->jsonSerialize());
|
$this->assertIsArray($entity->jsonSerialize());
|
||||||
|
$this->assertIsArray($entity->toArray());
|
||||||
|
$this->assertEquals($entity->jsonSerialize(), $entity->toArray());
|
||||||
$this->assertIsString((string)$entity);
|
$this->assertIsString((string)$entity);
|
||||||
$this->assertJson((string)$entity);
|
$this->assertJson((string)$entity);
|
||||||
if (!is_null($json_structure)) {
|
if (!is_null($json_structure)) {
|
||||||
@@ -81,68 +124,134 @@ class BasicTestCase extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Ассерты проверки наследования
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует идентичность двух классов
|
* Тестирует идентичность двух классов
|
||||||
*
|
*
|
||||||
* @param object|string $expected
|
* @param object|string $expected Ожидаемый класс
|
||||||
* @param object|string $actual
|
* @param object|string $actual Фактический класс
|
||||||
*/
|
*/
|
||||||
public function assertIsSameClass(object|string $expected, object|string $actual): void
|
public function assertIsSameClass(object|string $expected, object|string $actual): void
|
||||||
{
|
{
|
||||||
$this->assertTrue(Helpers::isSameClass($expected, $actual));
|
$this->assertTrue($this->checkisSameClass($expected, $actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет идентичность двух классов
|
||||||
|
*
|
||||||
|
* @param object|string $class1
|
||||||
|
* @param object|string $class2
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function checkisSameClass(object|string $class1, object|string $class2): bool
|
||||||
|
{
|
||||||
|
return (is_object($class1) ? $class1::class : $class1)
|
||||||
|
=== (is_object($class2) ? $class2::class : $class2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует наследование класса (объекта) от указанных классов
|
* Тестирует наследование класса (объекта) от указанных классов
|
||||||
*
|
*
|
||||||
* @param object|string $class
|
* @param array $expected Массив ожидаемых имён классов-родителей
|
||||||
* @param string[] $parents
|
* @param object|string $actual Объект или имя класса для проверки
|
||||||
*/
|
*/
|
||||||
public function assertExtendsClasses(object|string $class, array $parents): void
|
public function assertExtendsClasses(array $expected, object|string $actual): void
|
||||||
{
|
{
|
||||||
$this->assertTrue(Helpers::checkExtendsClasses($class, $parents));
|
$this->assertTrue($this->checkExtendsClasses($expected, $actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет наследование класса (объекта) от указанных классов
|
||||||
|
*
|
||||||
|
* @param string[] $parents Имена классов-родителей
|
||||||
|
* @param object|string $class Объект или имя класса для проверки
|
||||||
|
*/
|
||||||
|
private function checkExtendsClasses(array $parents, object|string $class): bool
|
||||||
|
{
|
||||||
|
return !empty(array_intersect($parents, is_object($class) ? class_parents($class) : [$class]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует имплементацию классом (объектом) указанных интерфейсов
|
* Тестирует имплементацию классом (объектом) указанных интерфейсов
|
||||||
*
|
*
|
||||||
* @param object|string $class
|
* @param string[] $expected Массив ожидаемых имён интерфейсов
|
||||||
* @param string[] $interfaces
|
* @param object|string $actual Объект или имя класса для проверки
|
||||||
*/
|
*/
|
||||||
public function assertImplementsInterfaces(object|string $class, array $interfaces): void
|
public function assertImplementsInterfaces(array $expected, object|string $actual): void
|
||||||
{
|
{
|
||||||
$this->assertTrue(Helpers::checkImplementsInterfaces($class, $interfaces));
|
$this->assertTrue($this->checkImplementsInterfaces($expected, $actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет имплементацию классом (объектом) указанных интерфейсов
|
||||||
|
*
|
||||||
|
* @param string[] $interfaces Имена классов-интерфейсов
|
||||||
|
* @param object|string $class Объект или имя класса для проверки
|
||||||
|
* @see https://www.php.net/manual/ru/function.class-implements.php
|
||||||
|
*/
|
||||||
|
private function checkImplementsInterfaces(array $interfaces, object|string $class): bool
|
||||||
|
{
|
||||||
|
return !empty(array_intersect($interfaces, is_object($class) ? class_implements($class) : [$class]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует использование классом (объектом) указанных трейтов
|
* Тестирует использование классом (объектом) указанных трейтов
|
||||||
*
|
*
|
||||||
* @param object|string $class
|
* @param string[] $expected Массив ожидаемых имён трейтов
|
||||||
* @param string[] $traits
|
* @param object|string $actual Объект или имя класса для проверки
|
||||||
*/
|
*/
|
||||||
public function assertUsesTraits(object|string $class, array $traits): void
|
public function assertUsesTraits(array $expected, object|string $actual): void
|
||||||
{
|
{
|
||||||
$this->assertTrue(Helpers::checkUsesTraits($traits, $class));
|
$this->assertTrue($this->checkUsesTraits($expected, $actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет использование классом (объектом) указанных трейтов (исключает родителей)
|
||||||
|
*
|
||||||
|
* @param string[] $traits Массив ожидаемых имён трейтов
|
||||||
|
* @param object|string $class Объект или имя класса для проверки
|
||||||
|
* @return bool
|
||||||
|
* @see https://www.php.net/manual/ru/function.class-uses.php#110752
|
||||||
|
*/
|
||||||
|
private function checkUsesTraits(array $traits, object|string $class): bool
|
||||||
|
{
|
||||||
|
$found_traits = [];
|
||||||
|
$check_class = is_object($class) ? $class::class : $class;
|
||||||
|
do {
|
||||||
|
$found_traits = array_merge(class_uses($check_class, true), $found_traits);
|
||||||
|
} while ($check_class = get_parent_class($check_class));
|
||||||
|
foreach ($found_traits as $trait => $same) {
|
||||||
|
$found_traits = array_merge(class_uses($trait, true), $found_traits);
|
||||||
|
}
|
||||||
|
return !empty(array_intersect(array_unique($found_traits), $traits));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тестирует, является ли объект коллекцией
|
* Тестирует, является ли объект коллекцией
|
||||||
*
|
*
|
||||||
* @param mixed $expected
|
* @param mixed $value
|
||||||
*/
|
*/
|
||||||
public function assertIsCollection(mixed $expected): void
|
public function assertIsCollection(mixed $value): void
|
||||||
{
|
{
|
||||||
$this->assertIsObject($expected);
|
$this->assertIsObject($value);
|
||||||
$this->assertIsIterable($expected);
|
$this->assertIsIterable($value);
|
||||||
$this->assertIsSameClass($expected, Collection::class);
|
$this->assertTrue(
|
||||||
|
$this->checkisSameClass(Collection::class, $value) ||
|
||||||
|
$this->checkExtendsClasses([Collection::class], $value)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Провайдеры данных для прогона тестов
|
||||||
//------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Провайдер строк, которые приводятся к null
|
* Провайдер строк, которые приводятся к null
|
||||||
*
|
*
|
||||||
* @return array<array<string|null>>
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function providerNullableStrings(): array
|
public function providerNullableStrings(): array
|
||||||
{
|
{
|
||||||
@@ -222,4 +331,121 @@ class BasicTestCase extends TestCase
|
|||||||
['abc.def@mail#archive.com'],
|
['abc.def@mail#archive.com'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Генераторы тестовых объектов
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерирует массив тестовых объектов предметов расчёта
|
||||||
|
*
|
||||||
|
* @param int $count
|
||||||
|
* @return Item[]
|
||||||
|
* @throws EmptyItemNameException
|
||||||
|
* @throws NegativeItemPriceException
|
||||||
|
* @throws NegativeItemQuantityException
|
||||||
|
* @throws TooHighItemPriceException
|
||||||
|
* @throws TooLongItemNameException
|
||||||
|
* @throws TooManyException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function generateItemObjects(int $count = 1): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
for ($i = 0; $i < abs($count); ++$i) {
|
||||||
|
$result[] = new Item(Helpers::randomStr(), random_int(1, 100), random_int(1, 10));
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерирует массив тестовых объектов оплаты
|
||||||
|
*
|
||||||
|
* @param int $count
|
||||||
|
* @return Payment[]
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function generatePaymentObjects(int $count = 1): array
|
||||||
|
{
|
||||||
|
$types = PaymentTypes::toArray();
|
||||||
|
$result = [];
|
||||||
|
for ($i = 0; $i < abs($count); ++$i) {
|
||||||
|
$result[] = new Payment(
|
||||||
|
array_values($types)[random_int(min($types), max($types))],
|
||||||
|
random_int(1, 100) * 2 / 3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерирует массив тестовых объектов ставок НДС
|
||||||
|
*
|
||||||
|
* @param int $count
|
||||||
|
* @return Vat[]
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function generateVatObjects(int $count = 1): array
|
||||||
|
{
|
||||||
|
$types = VatTypes::toArray();
|
||||||
|
$result = [];
|
||||||
|
for ($i = 0; $i < abs($count); ++$i) {
|
||||||
|
$result[] = new Vat(
|
||||||
|
array_values($types)[random_int(0, count($types) - 1)],
|
||||||
|
random_int(1, 100) * 2 / 3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает валидный тестовый объект чека прихода
|
||||||
|
*
|
||||||
|
* @return Receipt
|
||||||
|
* @throws EmptyItemNameException
|
||||||
|
* @throws EmptyItemsException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws NegativeItemPriceException
|
||||||
|
* @throws NegativeItemQuantityException
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
|
* @throws TooHighItemPriceException
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws TooLongItemNameException
|
||||||
|
* @throws TooManyException
|
||||||
|
*/
|
||||||
|
protected function newReceipt(): Receipt
|
||||||
|
{
|
||||||
|
return new Receipt(
|
||||||
|
new Client('John Doe', 'john@example.com', '+79501234567', '1234567890'),
|
||||||
|
new Company('company@example.com', SnoTypes::OSN, '1234567890', 'https://example.com'),
|
||||||
|
new Items($this->generateItemObjects(2)),
|
||||||
|
new Payments($this->generatePaymentObjects())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает валидный тестовый объект чека
|
||||||
|
*
|
||||||
|
* @return Correction
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
* @throws InvalidEnumValueException
|
||||||
|
* @throws NegativePaymentSumException
|
||||||
|
* @throws TooHighPaymentSumException
|
||||||
|
* @throws EmptyCorrectionNumberException
|
||||||
|
* @throws InvalidCorrectionDateException
|
||||||
|
*/
|
||||||
|
protected function newCorrection(): Correction
|
||||||
|
{
|
||||||
|
return new Correction(
|
||||||
|
new Company('company@example.com', SnoTypes::OSN, '1234567890', 'https://example.com'),
|
||||||
|
new CorrectionInfo(CorrectionTypes::SELF, '01.01.2021', Helpers::randomStr()),
|
||||||
|
new Payments($this->generatePaymentObjects(2)),
|
||||||
|
new Vats($this->generateVatObjects(2)),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
69
tests/AtolOnline/Tests/Collections/ItemsTest.php
Normal file
69
tests/AtolOnline/Tests/Collections/ItemsTest.php
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
|
||||||
|
*
|
||||||
|
* This code is licensed under MIT.
|
||||||
|
* Этот код распространяется по лицензии MIT.
|
||||||
|
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AtolOnline\Tests\Collections;
|
||||||
|
|
||||||
|
use AtolOnline\{
|
||||||
|
Collections\Items,
|
||||||
|
Constants\Constraints,
|
||||||
|
Tests\BasicTestCase};
|
||||||
|
use AtolOnline\Exceptions\{
|
||||||
|
EmptyItemNameException,
|
||||||
|
EmptyItemsException,
|
||||||
|
InvalidEntityInCollectionException,
|
||||||
|
NegativeItemPriceException,
|
||||||
|
NegativeItemQuantityException,
|
||||||
|
TooHighItemPriceException,
|
||||||
|
TooLongItemNameException,
|
||||||
|
TooManyException,
|
||||||
|
TooManyItemsException};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Набор тестов для проверки работы класса коллекции предметов расчёта
|
||||||
|
*/
|
||||||
|
class ItemsTest extends BasicTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Тестирует выброс исключения при установке слишком большого количества предметов расчёта
|
||||||
|
*
|
||||||
|
* @covers \AtolOnline\Collections\EntityCollection
|
||||||
|
* @covers \AtolOnline\Collections\EntityCollection::checkCount
|
||||||
|
* @covers \AtolOnline\Collections\EntityCollection::checkItemsClasses
|
||||||
|
* @covers \AtolOnline\Collections\EntityCollection::jsonSerialize
|
||||||
|
* @covers \AtolOnline\Exceptions\TooManyItemsException
|
||||||
|
* @throws EmptyItemNameException
|
||||||
|
* @throws NegativeItemPriceException
|
||||||
|
* @throws NegativeItemQuantityException
|
||||||
|
* @throws TooHighItemPriceException
|
||||||
|
* @throws TooLongItemNameException
|
||||||
|
* @throws TooManyException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
*/
|
||||||
|
public function testTooManyItemsException()
|
||||||
|
{
|
||||||
|
$this->expectException(TooManyItemsException::class);
|
||||||
|
(new Items($this->generateItemObjects(Constraints::MAX_COUNT_DOC_ITEMS + 1)))->jsonSerialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тестирует выброс исключения при установке нулевого количества предметов расчёта
|
||||||
|
*
|
||||||
|
* @covers \AtolOnline\Collections\EntityCollection
|
||||||
|
* @covers \AtolOnline\Collections\EntityCollection::checkCount
|
||||||
|
* @covers \AtolOnline\Collections\EntityCollection::checkItemsClasses
|
||||||
|
* @covers \AtolOnline\Collections\EntityCollection::jsonSerialize
|
||||||
|
* @covers \AtolOnline\Exceptions\EmptyItemsException
|
||||||
|
* @throws InvalidEntityInCollectionException
|
||||||
|
*/
|
||||||
|
public function testEmptyItemsException()
|
||||||
|
{
|
||||||
|
$this->expectException(EmptyItemsException::class);
|
||||||
|
(new Items([]))->jsonSerialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user