atol 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -1
- data/Gemfile.lock +4 -4
- data/README.md +80 -58
- data/atol-rb.gemspec +1 -1
- data/lib/atol/config.rb +2 -1
- data/lib/atol/errors.rb +3 -0
- data/lib/atol/request/post_document/correction/body.rb +35 -0
- data/lib/atol/request/post_document/correction/v5/body.rb +130 -0
- data/lib/atol/request/post_document/item/body.rb +13 -71
- data/lib/atol/request/post_document/item/v4/body.rb +98 -0
- data/lib/atol/request/post_document/item/v5/body.rb +101 -0
- data/lib/atol/request/post_document/payment.rb +41 -0
- data/lib/atol/request/post_document/sell/body.rb +41 -42
- data/lib/atol/request/post_document.rb +5 -1
- data/lib/atol/version.rb +7 -2
- metadata +9 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 17a1f879f910bd053721385602bc4e3c158dc10625534db847d78bdb54ee75e4
|
|
4
|
+
data.tar.gz: 8408f2c974e2e49c3dd89745e942cc06375fbcbf050d843015fdd17d8839eae4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 05c52df6c9b2bfcd04c47a09a2e71f1e1eec304809cba41c1e858431c6a141eeca774191ebd8488c88a97225dad0a3524af12d9bc018d0c66a29a0a279b81698
|
|
7
|
+
data.tar.gz: 5e034691a9b942dab227b3c2341b1379aebe787d6b71b9eee895387c8caee014e17da56a1588b2479d9852c21e5fe5646ef2ef7bcb15fc26141e4be7bdc90c37
|
data/.rubocop.yml
CHANGED
|
@@ -11,4 +11,6 @@ Metrics/LineLength:
|
|
|
11
11
|
|
|
12
12
|
Metrics/ParameterLists:
|
|
13
13
|
Exclude:
|
|
14
|
-
- lib/atol/request/post_document/item/body.rb
|
|
14
|
+
- lib/atol/request/post_document/item/body.rb
|
|
15
|
+
- lib/atol/request/post_document/sell/body.rb
|
|
16
|
+
- lib/atol/request/post_document/correction/v5/body.rb
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
atol (
|
|
4
|
+
atol (1.1.0)
|
|
5
5
|
anyway_config (~> 1.0)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
@@ -9,7 +9,7 @@ GEM
|
|
|
9
9
|
specs:
|
|
10
10
|
addressable (2.5.2)
|
|
11
11
|
public_suffix (>= 2.0.2, < 4.0)
|
|
12
|
-
anyway_config (1.
|
|
12
|
+
anyway_config (1.4.4)
|
|
13
13
|
ast (2.4.1)
|
|
14
14
|
coveralls (0.8.21)
|
|
15
15
|
json (>= 1.8, < 3)
|
|
@@ -22,7 +22,7 @@ GEM
|
|
|
22
22
|
diff-lcs (1.3)
|
|
23
23
|
docile (1.1.5)
|
|
24
24
|
hashdiff (0.3.7)
|
|
25
|
-
json (2.1
|
|
25
|
+
json (2.18.1)
|
|
26
26
|
parallel (1.19.2)
|
|
27
27
|
parser (2.7.1.4)
|
|
28
28
|
ast (~> 2.4.1)
|
|
@@ -77,7 +77,7 @@ PLATFORMS
|
|
|
77
77
|
|
|
78
78
|
DEPENDENCIES
|
|
79
79
|
atol!
|
|
80
|
-
bundler (~> 1.
|
|
80
|
+
bundler (~> 2.1.4)
|
|
81
81
|
coveralls
|
|
82
82
|
rake (~> 13.0)
|
|
83
83
|
rspec (~> 3.0)
|
data/README.md
CHANGED
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
##### Совместимость
|
|
11
11
|
|
|
12
|
-
Для корректной работы необходим интерпретатор Руби версии
|
|
13
|
-
|
|
12
|
+
Для корректной работы необходим интерпретатор Руби версии ~> 3.0.0. Пакет работает с версиями протокола [v4](http://atol.online/api_v4) и [v5](http://atol.online/api_v5) (см. настройку ATOL_API_URL).
|
|
14
13
|
|
|
15
14
|
## Использование
|
|
16
15
|
|
|
@@ -26,58 +25,10 @@ gem 'atol'
|
|
|
26
25
|
```
|
|
27
26
|
$ bundle install
|
|
28
27
|
```
|
|
29
|
-
### Конфигурация
|
|
30
|
-
|
|
31
|
-
Для обращения к сервису необходимы данные учетной записи.
|
|
32
|
-
|
|
33
|
-
При инициализации приложение попытается найти необходимые параметры в константе `ENV`.
|
|
34
|
-
|
|
35
|
-
Для корректной работы потребуются следующие переменные окружения.
|
|
36
|
-
|
|
37
|
-
**Все переменные являются обязательными**.
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
# .env
|
|
41
|
-
ATOL_INN=123456789010
|
|
42
|
-
ATOL_LOGIN=example-login
|
|
43
|
-
ATOL_PASSWORD=example-password
|
|
44
|
-
ATOL_PAYMENT_ADDRESS="г. Москва, ул. Ленина, д.1 к.2"
|
|
45
|
-
ATOL_GROUP_CODE=example-group-code
|
|
46
|
-
ATOL_DEFAULT_SNO=esn
|
|
47
|
-
ATOL_DEFAULT_TAX=vat18
|
|
48
|
-
ATOL_CALLBACK_URL=https://www.example.com/callback_path
|
|
49
|
-
ATOL_COMPANY_EMAIL=example@email.com
|
|
50
|
-
ATOL_DEFAULT_PAYMENT_TYPE=1
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Значения `ATOL_INN`, `ATOL_LOGIN`, `ATOL_PASSWORD`, `ATOL_PAYMENT_ADDRESS` и `ATOL_GROUP_CODE` вы получаете при регистрации в сервисе.
|
|
54
|
-
|
|
55
|
-
`ATOL_DEFAULT_SNO` - система налогообложения. Возможные значения:
|
|
56
|
-
1) "osn" – общая СН;
|
|
57
|
-
2) "usn_income" – упрощенная СН (доходы);
|
|
58
|
-
3) "usn_income_outcome" – упрощенная СН (доходы минус расходы);
|
|
59
|
-
4) "envd" – единый налог на вмененный доход;
|
|
60
|
-
5) "esn" – единый сельскохозяйственный налог;
|
|
61
|
-
6) "patent" – патентная СН.
|
|
62
|
-
|
|
63
|
-
`ATOL_DEFAULT_TAX` - номер налога в ККТ. Возможные значения:
|
|
64
|
-
1) "none" – без НДС;
|
|
65
|
-
2) "vat0" – НДС по ставке 0%;
|
|
66
|
-
3) "vat10" – НДС чека по ставке 10%;
|
|
67
|
-
4) "vat18" – НДС чека по ставке 18%;
|
|
68
|
-
5) "vat110" – НДС чека по расчетной ставке 10/110;
|
|
69
|
-
6) "vat118" – НДС чека по расчетной ставке 18/118.
|
|
70
|
-
|
|
71
|
-
`ATOL_CALLBACK_URL` - адрес, по которому сервис будет отправлять информацию после создания чека.
|
|
72
|
-
|
|
73
|
-
`ATOL_DEFAULT_PAYMENT_TYPE` - вид оплаты. Возможные значения:
|
|
74
|
-
1) "1" – электронный;
|
|
75
|
-
2) "2" – "9" – расширенные типы оплаты. Для каждого фискального типа оплаты можно указать расширенный тип оплаты.
|
|
76
|
-
|
|
77
|
-
`ATOL_COMPANY_EMAIL` - адрес электронной почты вашей компании.
|
|
78
|
-
|
|
79
28
|
### Конфигурация в инициализаторе
|
|
80
29
|
|
|
30
|
+
Для обращения к сервису необходимы данные учетной записи. `login`, `password` и `group_code`
|
|
31
|
+
|
|
81
32
|
Для Rails-приложений так же можно создать файл инициализации и задать параметры непосредственно в коде:
|
|
82
33
|
|
|
83
34
|
```ruby
|
|
@@ -88,13 +39,15 @@ Rails.application.config.after_initialize do
|
|
|
88
39
|
config.inn = '123456789010'
|
|
89
40
|
config.login = 'example-login'
|
|
90
41
|
config.password = 'example-password'
|
|
91
|
-
config.payment_address = 'г. Москва, ул. Ленина, д.1 к.2'
|
|
42
|
+
config.payment_address = 'г. Москва, ул. Ленина, д.1 к.2' # тэг 1187
|
|
92
43
|
config.group_code = 'example-group-code'
|
|
93
|
-
config.default_sno = 'esn'
|
|
44
|
+
config.default_sno = 'esn' # тэг 1055
|
|
94
45
|
config.default_tax = 'vat18'
|
|
95
46
|
config.callback_url = 'https://www.example.com/callback_path'
|
|
96
47
|
config.company_email = 'example@email.com'
|
|
97
|
-
config.default_payment_type = '1'
|
|
48
|
+
config.default_payment_type = '1' # тэг 1031
|
|
49
|
+
config.api_url = 'https://online.atol.ru/possystem/v5' # по умолчанию 'https://online.atol.ru/possystem/v4' ФФД 1.05
|
|
50
|
+
config.internet = true # тэг 1125, по умолчанию false
|
|
98
51
|
end
|
|
99
52
|
end
|
|
100
53
|
```
|
|
@@ -151,8 +104,7 @@ body = Atol::Request::PostDocument::Sell::Body.new(
|
|
|
151
104
|
email: 'example@example.com',
|
|
152
105
|
items: [
|
|
153
106
|
...
|
|
154
|
-
]
|
|
155
|
-
agent_info_type: 'bank_paying_agent'
|
|
107
|
+
]
|
|
156
108
|
).to_json
|
|
157
109
|
```
|
|
158
110
|
|
|
@@ -160,6 +112,8 @@ body = Atol::Request::PostDocument::Sell::Body.new(
|
|
|
160
112
|
|
|
161
113
|
Массив `items` должен включать в себя объекты, которые так же соответствуют схеме.
|
|
162
114
|
|
|
115
|
+
#### Items для версии V4
|
|
116
|
+
|
|
163
117
|
Для создания `items` можно использовать класс `Atol::Request::PostDocument::Item::Body`.
|
|
164
118
|
|
|
165
119
|
Его конструктор принимает обязательные аргументы `name`, `price`, `payment_method`, `payment_object` и опциональные `quantity` (по умолчанию 1), `supplier_info_inn`, `supplier_info_name`, `agent_info_type` (тег ФФД - 1222).
|
|
@@ -197,7 +151,7 @@ item = Atol::Request::PostDocument::Item::Body.new(
|
|
|
197
151
|
Тогда создание всего тела запроса будет выглядеть так:
|
|
198
152
|
|
|
199
153
|
```ruby
|
|
200
|
-
|
|
154
|
+
Atol::Request::PostDocument::Sell::Body.new(
|
|
201
155
|
external_id: 123,
|
|
202
156
|
email: 'example@example.com',
|
|
203
157
|
items: [
|
|
@@ -271,8 +225,76 @@ body = Atol::Request::PostDocument::Sell::Body.new(
|
|
|
271
225
|
"timestamp":"06.02.2018 12:35:00",
|
|
272
226
|
"external_id":123
|
|
273
227
|
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### Items для версии V5
|
|
231
|
+
|
|
232
|
+
Создается как в v4 только
|
|
233
|
+
|
|
234
|
+
- Добавлено обязательное поле `measure`
|
|
235
|
+
- Добавлено обязательное поле `vat`
|
|
236
|
+
- Изменен тип поля `payment_object` на int
|
|
237
|
+
|
|
238
|
+
Доступные значения для `measure`
|
|
274
239
|
|
|
275
240
|
```
|
|
241
|
+
0, 10, 11, 12, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51, 70, 71, 72, 73, 80, 81, 82, 83, 255
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
`vat` имеет вид объекта, пример
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
{ type: 'none' }
|
|
248
|
+
```
|
|
249
|
+
Доступные type для vat
|
|
250
|
+
`none vat0 vat5 vat7 vat10 vat22 vat105 vat107 vat110 vat20 vat120 vat122`
|
|
251
|
+
|
|
252
|
+
Доступные значения для `payment_object`
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
#### Кастомные payments
|
|
259
|
+
|
|
260
|
+
По умолчанию `Sell::Body` формирует один платёж с типом из конфигурации (`default_payment_type`) и суммой, равной итогу позиций. Если нужны другие виды оплаты (например, зачёт аванса — тег 1215, тип `2`), можно передать массив объектов `Atol::Request::PostDocument::Payment` явно. Сумма платежей должна совпадать с итогом позиций, иначе конструктор бросит `Atol::PaymentsTotalMismatchError`.
|
|
261
|
+
|
|
262
|
+
```ruby
|
|
263
|
+
payments = [
|
|
264
|
+
Atol::Request::PostDocument::Payment.new(
|
|
265
|
+
type: Atol::Request::PostDocument::Payment::PREPAID_TYPE,
|
|
266
|
+
sum: 200.0
|
|
267
|
+
)
|
|
268
|
+
]
|
|
269
|
+
Atol::Request::PostDocument::Sell::Body.new(
|
|
270
|
+
external_id: 123,
|
|
271
|
+
email: 'example@example.com',
|
|
272
|
+
items: [item],
|
|
273
|
+
payments: payments
|
|
274
|
+
).to_json
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Виды оплаты (`type`) — константы класса `Atol::Request::PostDocument::Payment`: `CASH_TYPE` наличные (1031), `CASHLESS_TYPE` безналичный (1081), `PREPAID_TYPE` предоплата/зачёт аванса (1215), `POSTPAID_TYPE` постоплата/кредит (1216), `COUNTER_PROVISION_TYPE` встречное предоставление (1217), `EXTENDED_5_TYPE`–`EXTENDED_9_TYPE` расширенные.
|
|
278
|
+
|
|
279
|
+
#### Чек коррекции для версии V5
|
|
280
|
+
|
|
281
|
+
Для тела чека коррекции используется класс `Atol::Request::PostDocument::Correction::Body` — он выбирает реализацию по `config.api_url`, как и `Item::Body`. Реализован только ФФД 1.2 (`Correction::V5::Body`, операции `sell_refund_correction`, `sell_correction` и т.п.); для v4-эндпоинта (ФФД 1.05) тело коррекции не реализовано и конструктор бросит `Atol::Request::PostDocument::Correction::Body::BadApiUrlError`.
|
|
282
|
+
|
|
283
|
+
Обязательные аргументы: `external_id`, `items`, `correction_type` (`self` или `instruction`) и `base_date` (дата корректируемого расчёта в формате `dd.mm.yyyy`, тег 1178), а также хотя бы один контакт клиента — `phone` или `email`. Необязательные: `base_number` — номер документа-основания (тег 1179, не более 32 байт); `additional_check_props` — дополнительный реквизит чека/БСО (тег 1192, не более 16 байт); и `payments` (как и в `Sell::Body`, при отсутствии формируется один платёж из `default_payment_type` с суммой, равной итогу позиций; переданная сумма платежей должна совпадать с итогом позиций).
|
|
284
|
+
|
|
285
|
+
```ruby
|
|
286
|
+
body = Atol::Request::PostDocument::Correction::Body.new(
|
|
287
|
+
external_id: 123,
|
|
288
|
+
email: 'example@example.com',
|
|
289
|
+
items: [...],
|
|
290
|
+
correction_type: 'self',
|
|
291
|
+
base_date: '01.01.2026',
|
|
292
|
+
base_number: '12345'
|
|
293
|
+
).to_json
|
|
294
|
+
|
|
295
|
+
Atol::Transaction::PostDocument.new(operation: :sell_refund_correction, token: token, body: body).call
|
|
296
|
+
```
|
|
297
|
+
|
|
276
298
|
#### Отправка документа
|
|
277
299
|
|
|
278
300
|
Когда токен и тело запроса составлены, остается только сделать post-запрос.
|
data/atol-rb.gemspec
CHANGED
|
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
|
|
26
26
|
spec.add_dependency 'anyway_config', '~> 1.0'
|
|
27
27
|
|
|
28
|
-
spec.add_development_dependency 'bundler', '~> 1.
|
|
28
|
+
spec.add_development_dependency 'bundler', '~> 2.1.4'
|
|
29
29
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
30
30
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
31
31
|
spec.add_development_dependency 'rubocop', '~> 0.90'
|
data/lib/atol/config.rb
CHANGED
|
@@ -15,9 +15,10 @@ module Atol
|
|
|
15
15
|
:default_tax,
|
|
16
16
|
:callback_url,
|
|
17
17
|
:company_email,
|
|
18
|
+
internet: false,
|
|
18
19
|
req_tries_number: 3,
|
|
19
20
|
default_payment_type: 1,
|
|
20
21
|
http_client: Net::HTTP,
|
|
21
|
-
api_url:
|
|
22
|
+
api_url: Atol::Version::V4
|
|
22
23
|
end
|
|
23
24
|
end
|
data/lib/atol/errors.rb
CHANGED
|
@@ -18,6 +18,9 @@ module Atol
|
|
|
18
18
|
class StateMissingUuidError < StandardError; end
|
|
19
19
|
class StateNotFoundError < StandardError; end
|
|
20
20
|
class ZeroItemQuantityError < StandardError; end
|
|
21
|
+
class BadPaymentError < StandardError; end
|
|
22
|
+
class EmptyPaymentsError < StandardError; end
|
|
23
|
+
class PaymentsTotalMismatchError < StandardError; end
|
|
21
24
|
|
|
22
25
|
ERRORS = Hash[
|
|
23
26
|
0 => BadJSONError,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Atol
|
|
4
|
+
module Request
|
|
5
|
+
class PostDocument
|
|
6
|
+
module Correction
|
|
7
|
+
class Body
|
|
8
|
+
BadApiUrlError = Class.new(StandardError)
|
|
9
|
+
|
|
10
|
+
attr_reader :instance
|
|
11
|
+
|
|
12
|
+
def initialize(**kwargs)
|
|
13
|
+
config = kwargs[:config] || Atol.config
|
|
14
|
+
@instance = case config.api_url
|
|
15
|
+
when Atol::Version::V5, Atol::Version::V5_TEST
|
|
16
|
+
Atol::Request::PostDocument::Correction::V5::Body.new(**kwargs)
|
|
17
|
+
when Atol::Version::V4, Atol::Version::V4_TEST
|
|
18
|
+
raise BadApiUrlError, 'correction body for the v4 api is not implemented'
|
|
19
|
+
else
|
|
20
|
+
raise BadApiUrlError
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_h
|
|
25
|
+
instance.to_h
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_json(*args)
|
|
29
|
+
instance.to_json(*args)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'atol/errors'
|
|
4
|
+
require 'atol/request/post_document/payment'
|
|
5
|
+
|
|
6
|
+
module Atol
|
|
7
|
+
module Request
|
|
8
|
+
class PostDocument
|
|
9
|
+
module Correction
|
|
10
|
+
module V5
|
|
11
|
+
class Body
|
|
12
|
+
class BadCorrectionTypeError < StandardError; end
|
|
13
|
+
class BadCorrectionBaseDateError < StandardError; end
|
|
14
|
+
class BadCorrectionBaseNumberError < StandardError; end
|
|
15
|
+
class BadAdditionalCheckPropsError < StandardError; end
|
|
16
|
+
|
|
17
|
+
CORRECTION_TYPES = %w[self instruction].freeze
|
|
18
|
+
BASE_DATE_FORMAT = /\A\d{2}\.\d{2}\.\d{4}\z/
|
|
19
|
+
BASE_NUMBER_MAX_BYTESIZE = 32
|
|
20
|
+
ADDITIONAL_CHECK_PROPS_MAX_BYTESIZE = 16
|
|
21
|
+
|
|
22
|
+
def initialize(external_id:, items:, correction_type:, base_date:, phone: '', email: '',
|
|
23
|
+
payments: nil, base_number: nil, additional_check_props: nil, config: nil, **options)
|
|
24
|
+
raise(Atol::EmptyClientContactError) if phone.empty? && email.empty?
|
|
25
|
+
raise(Atol::EmptySellItemsError) if items.empty?
|
|
26
|
+
raise(BadCorrectionTypeError) unless CORRECTION_TYPES.include?(correction_type)
|
|
27
|
+
raise(BadCorrectionBaseDateError) unless base_date.to_s.match?(BASE_DATE_FORMAT)
|
|
28
|
+
raise(BadCorrectionBaseNumberError) if base_number && base_number.to_s.bytesize > BASE_NUMBER_MAX_BYTESIZE
|
|
29
|
+
if additional_check_props && additional_check_props.to_s.bytesize > ADDITIONAL_CHECK_PROPS_MAX_BYTESIZE
|
|
30
|
+
raise(BadAdditionalCheckPropsError)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
total = items.sum { |item| item[:sum] }
|
|
34
|
+
validate_payments!(payments, total)
|
|
35
|
+
|
|
36
|
+
@config = config || Atol.config
|
|
37
|
+
@external_id = external_id
|
|
38
|
+
@phone = phone
|
|
39
|
+
@email = email
|
|
40
|
+
@items = items
|
|
41
|
+
@correction_type = correction_type
|
|
42
|
+
@base_date = base_date
|
|
43
|
+
@base_number = base_number
|
|
44
|
+
@additional_check_props = additional_check_props
|
|
45
|
+
@total = total
|
|
46
|
+
@payments = payments
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_h
|
|
50
|
+
build_body.clone
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_json(*_args)
|
|
54
|
+
build_body.to_json
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
attr_reader :config, :external_id, :phone, :email, :items, :payments,
|
|
60
|
+
:correction_type, :base_date, :base_number, :additional_check_props, :total
|
|
61
|
+
|
|
62
|
+
def validate_payments!(payments, total)
|
|
63
|
+
return if payments.nil?
|
|
64
|
+
|
|
65
|
+
raise(Atol::EmptyPaymentsError) if payments.empty?
|
|
66
|
+
raise(Atol::BadPaymentError) if payments.any? { |payment| !payment.is_a?(Payment) }
|
|
67
|
+
raise(Atol::PaymentsTotalMismatchError) unless payments.sum(&:sum).round(2) == total.round(2)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def build_body
|
|
71
|
+
{
|
|
72
|
+
external_id: external_id,
|
|
73
|
+
correction: correction,
|
|
74
|
+
service: service,
|
|
75
|
+
timestamp: Time.now.strftime(Atol::TIMESTAMP_FORMAT)
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def correction
|
|
80
|
+
result = {
|
|
81
|
+
client: client,
|
|
82
|
+
company: company,
|
|
83
|
+
correction_info: correction_info,
|
|
84
|
+
items: items,
|
|
85
|
+
payments: build_payments,
|
|
86
|
+
total: total,
|
|
87
|
+
internet: config.internet
|
|
88
|
+
}
|
|
89
|
+
result[:additional_check_props] = additional_check_props if additional_check_props
|
|
90
|
+
|
|
91
|
+
result
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def client
|
|
95
|
+
result = {}
|
|
96
|
+
result[:email] = email unless email.empty?
|
|
97
|
+
result[:phone] = phone unless phone.empty?
|
|
98
|
+
|
|
99
|
+
result
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def company
|
|
103
|
+
{
|
|
104
|
+
inn: config.inn.to_s,
|
|
105
|
+
sno: config.default_sno,
|
|
106
|
+
payment_address: config.payment_address,
|
|
107
|
+
email: config.company_email
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def build_payments
|
|
112
|
+
(payments || [Payment.new(type: config.default_payment_type, sum: total)]).map(&:to_h)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def service
|
|
116
|
+
config.callback_url ? { callback_url: config.callback_url } : {}
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def correction_info
|
|
120
|
+
info = { type: correction_type, base_date: base_date }
|
|
121
|
+
info[:base_number] = base_number if base_number
|
|
122
|
+
|
|
123
|
+
info
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -1,86 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'atol/errors'
|
|
4
|
-
|
|
5
3
|
module Atol
|
|
6
4
|
module Request
|
|
7
5
|
class PostDocument
|
|
8
6
|
module Item
|
|
9
7
|
class Body
|
|
10
|
-
|
|
11
|
-
BadPaymentObjectError = Class.new(StandardError)
|
|
12
|
-
|
|
13
|
-
PAYMENT_METHODS = [
|
|
14
|
-
'full_prepayment', 'prepayment', 'advance', 'full_payment',
|
|
15
|
-
'partial_payment', 'credit', 'credit_payment'
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
PAYMENT_OBJECTS = [
|
|
19
|
-
'commodity', 'excise', 'job', 'service', 'gambling_bet', 'gambling_prize',
|
|
20
|
-
'lottery', 'lottery_prize', 'intellectual_activity', 'payment', 'agent_commission',
|
|
21
|
-
'composite', 'another'
|
|
22
|
-
]
|
|
8
|
+
BadApiUrlError = Class.new(StandardError)
|
|
23
9
|
|
|
24
|
-
|
|
25
|
-
:agent_info_type, :supplier_info_inn, :supplier_info_name
|
|
10
|
+
attr_reader :instance
|
|
26
11
|
|
|
27
|
-
def initialize(
|
|
28
|
-
|
|
29
|
-
|
|
12
|
+
def initialize(**kwargs)
|
|
13
|
+
config = kwargs[:config] || Atol.config
|
|
14
|
+
@instance = case config.api_url
|
|
15
|
+
when Atol::Version::V4, Atol::Version::V4_TEST
|
|
16
|
+
Atol::Request::PostDocument::Item::V4::Body.new(**kwargs)
|
|
17
|
+
when Atol::Version::V5, Atol::Version::V5_TEST
|
|
18
|
+
Atol::Request::PostDocument::Item::V5::Body.new(**kwargs)
|
|
19
|
+
else
|
|
20
|
+
raise BadApiUrlError
|
|
21
|
+
end
|
|
30
22
|
end
|
|
31
23
|
|
|
32
24
|
def to_h
|
|
33
|
-
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def to_json(*_args)
|
|
37
|
-
body.to_json
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
private
|
|
41
|
-
|
|
42
|
-
def setup_attributes(config, name, price, quantity, payment_method, payment_object, options)
|
|
43
|
-
self.config = config || Atol.config
|
|
44
|
-
self.name = name
|
|
45
|
-
self.price = price.to_f
|
|
46
|
-
self.quantity = quantity.to_f
|
|
47
|
-
self.payment_method = payment_method.to_s
|
|
48
|
-
self.payment_object = payment_object.to_s
|
|
49
|
-
self.agent_info_type = options[:agent_info_type].to_s
|
|
50
|
-
self.supplier_info_inn = options[:supplier_info_inn].to_s
|
|
51
|
-
self.supplier_info_name = options[:supplier_info_name].to_s
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def validate_attributes
|
|
55
|
-
raise Atol::ZeroItemQuantityError if quantity.to_f.zero?
|
|
56
|
-
raise BadPaymentMethodError unless PAYMENT_METHODS.include?(payment_method)
|
|
57
|
-
raise BadPaymentObjectError unless PAYMENT_OBJECTS.include?(payment_object)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def agent_info
|
|
61
|
-
return if agent_info_type.nil? || agent_info_type.empty?
|
|
62
|
-
|
|
63
|
-
{ agent_info: { type: agent_info_type } }
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def supplier_info
|
|
67
|
-
return if supplier_info_inn.nil? || supplier_info_inn.empty? || agent_info.nil?
|
|
68
|
-
|
|
69
|
-
info = { inn: supplier_info_inn, name: supplier_info_name }
|
|
70
|
-
filtered_info = info.reject { |_key, value| value&.empty? }
|
|
71
|
-
{ supplier_info: filtered_info } unless filtered_info.empty?
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def body
|
|
75
|
-
@body ||= {
|
|
76
|
-
name: name,
|
|
77
|
-
price: price,
|
|
78
|
-
quantity: quantity,
|
|
79
|
-
sum: (price * quantity).round(2),
|
|
80
|
-
tax: config.default_tax,
|
|
81
|
-
payment_method: payment_method,
|
|
82
|
-
payment_object: payment_object
|
|
83
|
-
}.merge(supplier_info.to_h, agent_info.to_h)
|
|
25
|
+
instance.to_h
|
|
84
26
|
end
|
|
85
27
|
end
|
|
86
28
|
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'atol/errors'
|
|
4
|
+
|
|
5
|
+
module Atol
|
|
6
|
+
module Request
|
|
7
|
+
class PostDocument
|
|
8
|
+
module Item
|
|
9
|
+
module V4
|
|
10
|
+
class Body
|
|
11
|
+
BadPaymentMethodError = Class.new(StandardError)
|
|
12
|
+
BadPaymentObjectError = Class.new(StandardError)
|
|
13
|
+
|
|
14
|
+
PAYMENT_METHODS = %w[
|
|
15
|
+
full_prepayment prepayment advance full_payment
|
|
16
|
+
partial_payment credit credit_payment
|
|
17
|
+
].freeze
|
|
18
|
+
|
|
19
|
+
PAYMENT_OBJECTS = %w[
|
|
20
|
+
commodity excise job service gambling_bet gambling_prize
|
|
21
|
+
lottery lottery_prize intellectual_activity payment agent_commission
|
|
22
|
+
composite another
|
|
23
|
+
].freeze
|
|
24
|
+
|
|
25
|
+
attr_accessor :config,
|
|
26
|
+
:name,
|
|
27
|
+
:price,
|
|
28
|
+
:quantity,
|
|
29
|
+
:payment_method,
|
|
30
|
+
:payment_object,
|
|
31
|
+
:agent_info_type,
|
|
32
|
+
:supplier_info_inn,
|
|
33
|
+
:supplier_info_name
|
|
34
|
+
|
|
35
|
+
def initialize(config: nil, name:, price:, quantity: 1, payment_method:, payment_object:, **options)
|
|
36
|
+
setup_attributes(config, name, price, quantity, payment_method, payment_object, options)
|
|
37
|
+
validate_attributes
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def to_h
|
|
41
|
+
body.clone
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_json(*_args)
|
|
45
|
+
body.to_json
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def setup_attributes(config, name, price, quantity, payment_method, payment_object, options)
|
|
51
|
+
self.config = config || Atol.config
|
|
52
|
+
self.name = name
|
|
53
|
+
self.price = price.to_f
|
|
54
|
+
self.quantity = quantity.to_f
|
|
55
|
+
self.payment_method = payment_method.to_s
|
|
56
|
+
self.payment_object = payment_object.to_s
|
|
57
|
+
self.agent_info_type = options[:agent_info_type].to_s
|
|
58
|
+
self.supplier_info_inn = options[:supplier_info_inn].to_s
|
|
59
|
+
self.supplier_info_name = options[:supplier_info_name].to_s
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def validate_attributes
|
|
63
|
+
raise Atol::ZeroItemQuantityError if quantity.to_f.zero?
|
|
64
|
+
raise BadPaymentMethodError unless PAYMENT_METHODS.include?(payment_method)
|
|
65
|
+
raise BadPaymentObjectError unless PAYMENT_OBJECTS.include?(payment_object)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def agent_info
|
|
69
|
+
return if agent_info_type.nil? || agent_info_type.empty?
|
|
70
|
+
|
|
71
|
+
{ agent_info: { type: agent_info_type } }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def supplier_info
|
|
75
|
+
return if supplier_info_inn.nil? || supplier_info_inn.empty? || agent_info.nil?
|
|
76
|
+
|
|
77
|
+
info = { inn: supplier_info_inn, name: supplier_info_name }
|
|
78
|
+
filtered_info = info.reject { |_key, value| value&.empty? }
|
|
79
|
+
{ supplier_info: filtered_info } unless filtered_info.empty?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def body
|
|
83
|
+
@body ||= {
|
|
84
|
+
name: name,
|
|
85
|
+
price: price,
|
|
86
|
+
quantity: quantity,
|
|
87
|
+
sum: (price * quantity).round(2),
|
|
88
|
+
tax: config.default_tax,
|
|
89
|
+
payment_method: payment_method,
|
|
90
|
+
payment_object: payment_object
|
|
91
|
+
}.merge(supplier_info.to_h, agent_info.to_h)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'atol/errors'
|
|
4
|
+
|
|
5
|
+
module Atol
|
|
6
|
+
module Request
|
|
7
|
+
class PostDocument
|
|
8
|
+
module Item
|
|
9
|
+
module V5
|
|
10
|
+
class Body
|
|
11
|
+
BadPaymentMethodError = Class.new(StandardError)
|
|
12
|
+
BadPaymentObjectError = Class.new(StandardError)
|
|
13
|
+
BadMeasureError = Class.new(StandardError)
|
|
14
|
+
BadVatTypeError = Class.new(StandardError)
|
|
15
|
+
|
|
16
|
+
# https://atol-kassa.ru/wp-content/nfiles/files/ATOL/kassa/АТОЛ%20Онлайн%20-%20Описание%20протокола%20v5%20(ФФД%201.2).pdf
|
|
17
|
+
|
|
18
|
+
PAYMENT_METHODS = %w[full_prepayment prepayment advance full_payment partial_payment credit credit_payment].freeze
|
|
19
|
+
PAYMENT_OBJECTS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].freeze
|
|
20
|
+
MEASURE = [0, 10, 11, 12, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51, 70, 71, 72, 73, 80, 81, 82, 83, 255].freeze
|
|
21
|
+
VAT_TYPES = %w[none vat0 vat5 vat7 vat10 vat22 vat105 vat107 vat110 vat20 vat120 vat122].freeze
|
|
22
|
+
|
|
23
|
+
attr_accessor :name,
|
|
24
|
+
:price,
|
|
25
|
+
:quantity,
|
|
26
|
+
:payment_method,
|
|
27
|
+
:payment_object,
|
|
28
|
+
:agent_info_type,
|
|
29
|
+
:supplier_info_inn,
|
|
30
|
+
:supplier_info_name,
|
|
31
|
+
:measure,
|
|
32
|
+
:vat
|
|
33
|
+
|
|
34
|
+
def initialize(name:, price:, quantity: 1, payment_method:, payment_object:, measure:, vat:, **options)
|
|
35
|
+
setup_attributes(name, price, quantity, payment_method, payment_object, measure, vat, options)
|
|
36
|
+
validate_attributes
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_h
|
|
40
|
+
body.clone
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_json(*_args)
|
|
44
|
+
body.to_json
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def setup_attributes(name, price, quantity, payment_method, payment_object, measure, vat, options)
|
|
50
|
+
self.name = name
|
|
51
|
+
self.price = price.to_f
|
|
52
|
+
self.quantity = quantity.to_f
|
|
53
|
+
self.payment_method = payment_method.to_s
|
|
54
|
+
self.payment_object = payment_object
|
|
55
|
+
self.agent_info_type = options[:agent_info_type].to_s
|
|
56
|
+
self.supplier_info_inn = options[:supplier_info_inn].to_s
|
|
57
|
+
self.supplier_info_name = options[:supplier_info_name].to_s
|
|
58
|
+
self.measure = measure
|
|
59
|
+
self.vat = vat
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def validate_attributes
|
|
63
|
+
raise Atol::ZeroItemQuantityError if quantity.to_f.zero?
|
|
64
|
+
raise BadPaymentMethodError unless PAYMENT_METHODS.include?(payment_method)
|
|
65
|
+
raise BadPaymentObjectError unless PAYMENT_OBJECTS.include?(payment_object)
|
|
66
|
+
raise BadMeasureError unless MEASURE.include?(measure)
|
|
67
|
+
raise BadVatTypeError unless VAT_TYPES.include?(vat&.[](:type))
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def agent_info
|
|
71
|
+
return if agent_info_type.nil? || agent_info_type.empty?
|
|
72
|
+
|
|
73
|
+
{ agent_info: { type: agent_info_type } }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def supplier_info
|
|
77
|
+
return if supplier_info_inn.nil? || supplier_info_inn.empty? || agent_info.nil?
|
|
78
|
+
|
|
79
|
+
info = { inn: supplier_info_inn, name: supplier_info_name }
|
|
80
|
+
filtered_info = info.reject { |_key, value| value&.empty? }
|
|
81
|
+
{ supplier_info: filtered_info } unless filtered_info.empty?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def body
|
|
85
|
+
@body ||= {
|
|
86
|
+
name: name,
|
|
87
|
+
price: price,
|
|
88
|
+
quantity: quantity,
|
|
89
|
+
sum: (price * quantity).round(2),
|
|
90
|
+
payment_method: payment_method,
|
|
91
|
+
payment_object: payment_object,
|
|
92
|
+
measure: measure,
|
|
93
|
+
vat: vat
|
|
94
|
+
}.merge(supplier_info.to_h, agent_info.to_h)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'atol/errors'
|
|
4
|
+
|
|
5
|
+
module Atol
|
|
6
|
+
module Request
|
|
7
|
+
class PostDocument
|
|
8
|
+
class Payment
|
|
9
|
+
CASH_TYPE = 0 # наличные
|
|
10
|
+
CASHLESS_TYPE = 1 # безналичный
|
|
11
|
+
PREPAID_TYPE = 2 # предоплата/зачёт аванса (тег 1215)
|
|
12
|
+
POSTPAID_TYPE = 3 # постоплата/кредит
|
|
13
|
+
COUNTER_PROVISION_TYPE = 4 # встречное предоставление
|
|
14
|
+
EXTENDED_5_TYPE = 5 # расширенный тип оплаты 5
|
|
15
|
+
EXTENDED_6_TYPE = 6 # расширенный тип оплаты 6
|
|
16
|
+
EXTENDED_7_TYPE = 7 # расширенный тип оплаты 7
|
|
17
|
+
EXTENDED_8_TYPE = 8 # расширенный тип оплаты 8
|
|
18
|
+
EXTENDED_9_TYPE = 9 # расширенный тип оплаты 9
|
|
19
|
+
|
|
20
|
+
TYPES = [
|
|
21
|
+
CASH_TYPE, CASHLESS_TYPE, PREPAID_TYPE, POSTPAID_TYPE, COUNTER_PROVISION_TYPE,
|
|
22
|
+
EXTENDED_5_TYPE, EXTENDED_6_TYPE, EXTENDED_7_TYPE, EXTENDED_8_TYPE, EXTENDED_9_TYPE
|
|
23
|
+
].freeze
|
|
24
|
+
|
|
25
|
+
attr_reader :type, :sum
|
|
26
|
+
|
|
27
|
+
def initialize(type:, sum:)
|
|
28
|
+
raise(Atol::BadPaymentError, 'not allowed type') unless TYPES.include?(type)
|
|
29
|
+
raise(Atol::BadPaymentError, 'sum must be zero or a positive number') unless sum.is_a?(Numeric) && sum >= 0
|
|
30
|
+
|
|
31
|
+
@type = type
|
|
32
|
+
@sum = sum
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_h
|
|
36
|
+
{ sum: sum, type: type }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -1,89 +1,88 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'atol/errors'
|
|
4
|
+
require 'atol/request/post_document/payment'
|
|
4
5
|
|
|
5
6
|
module Atol
|
|
6
7
|
module Request
|
|
7
8
|
class PostDocument
|
|
8
9
|
module Sell
|
|
9
10
|
class Body
|
|
10
|
-
def initialize(external_id:, phone: '', email: '', items:, config: nil, **options)
|
|
11
|
+
def initialize(external_id:, phone: '', email: '', items:, payments: nil, config: nil, **options)
|
|
11
12
|
raise(Atol::EmptyClientContactError) if phone.empty? && email.empty?
|
|
12
13
|
raise(Atol::EmptySellItemsError) if items.empty?
|
|
13
14
|
|
|
15
|
+
total = items.sum { |item| item[:sum] }
|
|
16
|
+
validate_payments!(payments, total)
|
|
17
|
+
|
|
14
18
|
@config = config || Atol.config
|
|
15
19
|
@external_id = external_id
|
|
16
20
|
@phone = phone
|
|
17
21
|
@email = email
|
|
18
22
|
@items = items
|
|
19
|
-
@
|
|
23
|
+
@total = total
|
|
24
|
+
@payments = payments
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
def to_h
|
|
23
|
-
|
|
28
|
+
build_body.clone
|
|
24
29
|
end
|
|
25
30
|
|
|
26
31
|
def to_json(*_args)
|
|
27
|
-
|
|
32
|
+
build_body.to_json
|
|
28
33
|
end
|
|
29
34
|
|
|
30
35
|
private
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
body_template.tap do |result|
|
|
34
|
-
receipt = result[:receipt]
|
|
35
|
-
client = receipt[:client]
|
|
37
|
+
attr_reader :config, :external_id, :phone, :email, :items, :payments, :total
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
def validate_payments!(payments, total)
|
|
40
|
+
return if payments.nil?
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
raise(Atol::EmptyPaymentsError) if payments.empty?
|
|
43
|
+
raise(Atol::BadPaymentError) if payments.any? { |payment| !payment.is_a?(Payment) }
|
|
44
|
+
raise(Atol::PaymentsTotalMismatchError) unless payments.sum(&:sum).round(2) == total.round(2)
|
|
43
45
|
end
|
|
44
46
|
|
|
45
|
-
def
|
|
47
|
+
def build_body
|
|
46
48
|
{
|
|
49
|
+
external_id: external_id,
|
|
47
50
|
receipt: {
|
|
48
|
-
client:
|
|
49
|
-
company:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
},
|
|
55
|
-
items: [],
|
|
56
|
-
payments: [
|
|
57
|
-
{
|
|
58
|
-
sum: 0,
|
|
59
|
-
type: @config.default_payment_type
|
|
60
|
-
}
|
|
61
|
-
]
|
|
51
|
+
client: client,
|
|
52
|
+
company: company,
|
|
53
|
+
items: items,
|
|
54
|
+
payments: build_payments,
|
|
55
|
+
total: total,
|
|
56
|
+
internet: config.internet
|
|
62
57
|
},
|
|
63
|
-
service:
|
|
58
|
+
service: service,
|
|
64
59
|
timestamp: Time.now.strftime(Atol::TIMESTAMP_FORMAT)
|
|
65
60
|
}
|
|
66
61
|
end
|
|
67
62
|
|
|
68
|
-
def
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
63
|
+
def client
|
|
64
|
+
result = {}
|
|
65
|
+
result[:email] = email unless email.empty?
|
|
66
|
+
result[:phone] = phone unless phone.empty?
|
|
72
67
|
|
|
73
|
-
|
|
74
|
-
receipt[:total] = receipt[:payments][0][:sum] = total
|
|
75
|
-
receipt[:items] = @items
|
|
76
|
-
add_agent_and_supplier_info(receipt)
|
|
68
|
+
result
|
|
77
69
|
end
|
|
78
70
|
|
|
79
|
-
def
|
|
80
|
-
|
|
71
|
+
def company
|
|
72
|
+
{
|
|
73
|
+
inn: config.inn.to_s,
|
|
74
|
+
sno: config.default_sno,
|
|
75
|
+
payment_address: config.payment_address,
|
|
76
|
+
email: config.company_email
|
|
77
|
+
}
|
|
78
|
+
end
|
|
81
79
|
|
|
82
|
-
|
|
80
|
+
def build_payments
|
|
81
|
+
(payments || [Payment.new(type: config.default_payment_type, sum: total)]).map(&:to_h)
|
|
83
82
|
end
|
|
84
83
|
|
|
85
|
-
def
|
|
86
|
-
|
|
84
|
+
def service
|
|
85
|
+
config.callback_url ? { callback_url: config.callback_url } : {}
|
|
87
86
|
end
|
|
88
87
|
end
|
|
89
88
|
end
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
require 'atol'
|
|
4
4
|
require 'atol/errors'
|
|
5
5
|
require 'atol/request/post_document/item/body'
|
|
6
|
+
require 'atol/request/post_document/item/v4/body'
|
|
7
|
+
require 'atol/request/post_document/item/v5/body'
|
|
6
8
|
require 'atol/request/post_document/sell/body'
|
|
9
|
+
require 'atol/request/post_document/correction/body'
|
|
10
|
+
require 'atol/request/post_document/correction/v5/body'
|
|
7
11
|
|
|
8
12
|
module Atol
|
|
9
13
|
module Request
|
|
10
14
|
class PostDocument
|
|
11
|
-
OPERATIONS = %i[sell sell_refund sell_correction buy buy_refund buy_correction].freeze
|
|
15
|
+
OPERATIONS = %i[sell sell_refund sell_correction sell_refund_correction buy buy_refund buy_correction buy_refund_correction].freeze
|
|
12
16
|
HEADERS = { 'Content-Type' => 'application/json; charset=utf-8' }.freeze
|
|
13
17
|
|
|
14
18
|
def initialize(operation:, token:, body:, config: nil, req_logger: nil, res_logger: nil)
|
data/lib/atol/version.rb
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Atol
|
|
4
4
|
module Version
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
V4 = 'https://online.atol.ru/possystem/v4'
|
|
6
|
+
V5 = 'https://online.atol.ru/possystem/v5'
|
|
7
|
+
|
|
8
|
+
V4_TEST = 'https://testonline.atol.ru/possystem/v4'
|
|
9
|
+
V5_TEST = 'https://testonline.atol.ru/possystem/v5'
|
|
10
|
+
|
|
11
|
+
LIB = '1.2.0'
|
|
7
12
|
end
|
|
8
13
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: atol
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GeorgeGorbanev
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-07-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: anyway_config
|
|
@@ -30,14 +30,14 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 2.1.4
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 2.1.4
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rake
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -119,7 +119,12 @@ files:
|
|
|
119
119
|
- lib/atol/request/get_document_state.rb
|
|
120
120
|
- lib/atol/request/get_token.rb
|
|
121
121
|
- lib/atol/request/post_document.rb
|
|
122
|
+
- lib/atol/request/post_document/correction/body.rb
|
|
123
|
+
- lib/atol/request/post_document/correction/v5/body.rb
|
|
122
124
|
- lib/atol/request/post_document/item/body.rb
|
|
125
|
+
- lib/atol/request/post_document/item/v4/body.rb
|
|
126
|
+
- lib/atol/request/post_document/item/v5/body.rb
|
|
127
|
+
- lib/atol/request/post_document/payment.rb
|
|
123
128
|
- lib/atol/request/post_document/sell/body.rb
|
|
124
129
|
- lib/atol/transaction.rb
|
|
125
130
|
- lib/atol/transaction/get_document_state.rb
|