orangedata 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +37 -2
- data/lib/orange_data/credentials.rb +12 -10
- data/lib/orange_data/generated_attributes.rb +127 -0
- data/lib/orange_data/receipt.rb +15 -138
- data/lib/orange_data/schema_definitions.yml +8 -1
- data/lib/orange_data/transport.rb +2 -2
- data/lib/orange_data/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f4b1c0d05572781e1ae1550991a896a7d81b9f2
|
4
|
+
data.tar.gz: c3773260bb588960809e57153343ff187bdd90f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0fa8f50e4f9326ffca33ef0a5841cacbe2cc32a2573a6f380c47159aa9c8c21a9246a970cbc85dbad0ae6d9a0eb858eef1bb4eadfc2d6c55e551a90a7f41d40b
|
7
|
+
data.tar.gz: 8527fb6abb8a3a7bb0c9eb2aecbc40b239141b0517738091a01ab7d87e193abbd486b8eb2587f9cf52832ed43cd0afeb5530236a377b2d1fcc76b57e3b95922a
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
orangedata (0.0.
|
4
|
+
orangedata (0.0.5)
|
5
5
|
faraday (>= 0.15)
|
6
6
|
faraday_middleware
|
7
7
|
|
@@ -15,7 +15,7 @@ GEM
|
|
15
15
|
safe_yaml (~> 1.0.0)
|
16
16
|
diff-lcs (1.3)
|
17
17
|
docile (1.3.1)
|
18
|
-
faraday (0.15.
|
18
|
+
faraday (0.15.3)
|
19
19
|
multipart-post (>= 1.2, < 3)
|
20
20
|
faraday_middleware (0.12.2)
|
21
21
|
faraday (>= 0.7.4, < 1.0)
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Orangedata Client
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/orangedata.svg)](https://badge.fury.io/rb/orangedata)
|
4
|
+
![Gem downloads](https://img.shields.io/gem/dt/orangedata.svg)
|
4
5
|
[![Build Status](https://travis-ci.org/Vasfed/orangedata.svg?branch=master)](https://travis-ci.org/Vasfed/orangedata)
|
5
6
|
|
6
7
|
A ruby client for orangedata.ru service.
|
@@ -11,7 +12,7 @@ Note: This is a Work-in-progress. API might change in the future.
|
|
11
12
|
Умеет:
|
12
13
|
- собственно транспорт с подписью запросов
|
13
14
|
- сгенерировать ключ сразу в нужном виде
|
14
|
-
-
|
15
|
+
- маппинг для данных генерируется на базе приведенного в человеческий вид официального json-schema-описания
|
15
16
|
|
16
17
|
## Установка
|
17
18
|
|
@@ -31,7 +32,10 @@ gem 'orangedata'
|
|
31
32
|
|
32
33
|
## Использование
|
33
34
|
|
34
|
-
Для тестового окружения ключики в комплекте - [credentials_test.yml](lib/orange_data/credentials_test.yml), собрано из родного `File_for_test.zip`, доступны как `OrangeData::Credentials.default_test
|
35
|
+
Для тестового окружения ключики в комплекте - [credentials_test.yml](lib/orange_data/credentials_test.yml), собрано из родного `File_for_test.zip`, доступны как `OrangeData::Credentials.default_test`.
|
36
|
+
Получение ключей для продакшна описано ниже.
|
37
|
+
|
38
|
+
### Пробитие чека
|
35
39
|
|
36
40
|
```ruby
|
37
41
|
transport = OrangeData::Transport.new("https://apip.orangedata.ru:2443/api/v2/", OrangeData::Credentials.default_test)
|
@@ -77,6 +81,37 @@ gem 'orangedata'
|
|
77
81
|
# => "t=20181026T2021&s=50.0&fn=9999078900001341&i=3243&fp=301645583&n=1"
|
78
82
|
```
|
79
83
|
|
84
|
+
### Чек коррекции
|
85
|
+
Пока не понятно, почему в API не все значения поля tax соответствуют цифрам в `taxNSum`, поэтому коррекцию, видимо, лучше бить через саппорт или подобным образом.
|
86
|
+
|
87
|
+
Но поддержка в маппинге есть:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
transport = OrangeData::Transport.new("https://apip.orangedata.ru:2443/api/v2/", OrangeData::Credentials.default_test)
|
91
|
+
correction = OrangeData::Correction.income(inn:"123456789012", id:"12345678990"){|c|
|
92
|
+
c.correction_type = :prescribed
|
93
|
+
c.assign_attributes(
|
94
|
+
description: "НЕ ХОЧЕТСЯ НО НАДО",
|
95
|
+
cause_document_date: "2017-08-10T00:00:00", cause_document_number: "ФЗ-54",
|
96
|
+
total_sum: 17.25,
|
97
|
+
sum_cash: 1.23, sum_card: 2.34,
|
98
|
+
sum_prepaid: 5.67, sum_credit: 4.56, sum_counterclaim: 3.45,
|
99
|
+
|
100
|
+
vat_18: 1.34, vat_10: 2.34, vat_0: 3.34,
|
101
|
+
vat_not_charged: 4.34, vat_18_118: 5.34, vat_10_110: 6.34,
|
102
|
+
taxation_system: :simplified,
|
103
|
+
|
104
|
+
automat_number: "123456789",
|
105
|
+
settlement_address: "г.Москва, Красная площадь, д.1",
|
106
|
+
settlement_place: "Палата No6",
|
107
|
+
)
|
108
|
+
}
|
109
|
+
transport.post_correction(correction)
|
110
|
+
# wait some time
|
111
|
+
res = transport.get_correction(correction.inn, correction.id)
|
112
|
+
```
|
113
|
+
|
114
|
+
|
80
115
|
### Получаем сертификаты
|
81
116
|
|
82
117
|
Предполагается, что всякие договоры и прочая фискализация уже успешно пройдена и у вас есть доступ
|
@@ -97,10 +97,10 @@ module OrangeData
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def ==(other)
|
100
|
-
return false unless %i[signature_key_name title].all?{|m|
|
100
|
+
return false unless %i[signature_key_name title].all?{|m| send(m) == other.send(m) }
|
101
101
|
# certificates/keys cannot be compared directly, so dump
|
102
102
|
%i[signature_key certificate certificate_key].all?{|m|
|
103
|
-
c1 =
|
103
|
+
c1 = send(m)
|
104
104
|
c2 = other.send(m)
|
105
105
|
c1 == c2 || (c1 && c2 && c1.to_der == c2.to_der)
|
106
106
|
}
|
@@ -112,7 +112,7 @@ module OrangeData
|
|
112
112
|
signature_key_name: creds[:signature_key_name],
|
113
113
|
signature_key: OpenSSL::PKey::RSA.load_from(creds[:signature_key], creds[:signature_key_pass]),
|
114
114
|
certificate: creds[:certificate] && OpenSSL::X509::Certificate.new(creds[:certificate]),
|
115
|
-
certificate_key: OpenSSL::PKey::RSA.load_from(creds[:certificate_key], creds[:certificate_key_pass])
|
115
|
+
certificate_key: OpenSSL::PKey::RSA.load_from(creds[:certificate_key], creds[:certificate_key_pass])
|
116
116
|
)
|
117
117
|
end
|
118
118
|
|
@@ -127,9 +127,11 @@ module OrangeData
|
|
127
127
|
{
|
128
128
|
title: title,
|
129
129
|
signature_key_name: signature_key_name,
|
130
|
-
signature_key: signature_key &&
|
130
|
+
signature_key: signature_key &&
|
131
|
+
signature_key.to_pem(key_pass && OpenSSL::Cipher.new("aes-128-cbc"), key_pass),
|
131
132
|
certificate: certificate && certificate.to_pem,
|
132
|
-
certificate_key: certificate_key &&
|
133
|
+
certificate_key: certificate_key &&
|
134
|
+
certificate_key.to_pem(key_pass && OpenSSL::Cipher.new("aes-128-cbc"), key_pass),
|
133
135
|
}.tap do |h|
|
134
136
|
h.delete(:title) if !title || title == ''
|
135
137
|
if save_pass
|
@@ -159,7 +161,7 @@ module OrangeData
|
|
159
161
|
}
|
160
162
|
|
161
163
|
if certificate && (subject_name = certificate.subject.to_a.select{|ent| ent.first == 'O' }.first)
|
162
|
-
info_fields[:certificate] = %
|
164
|
+
info_fields[:certificate] = %("#{(subject_name[1] || 'unknown').gsub('"', '\"')}")
|
163
165
|
end
|
164
166
|
|
165
167
|
"#<#{self.class.name}:#{object_id} #{info_fields.map{|(k, v)| "#{k}=#{v}" }.join(' ')}>"
|
@@ -167,7 +169,7 @@ module OrangeData
|
|
167
169
|
|
168
170
|
DEFAULT_KEY_LENGTH = 2048
|
169
171
|
|
170
|
-
#deprecated
|
172
|
+
# deprecated
|
171
173
|
def generate_signature_key!(key_length=DEFAULT_KEY_LENGTH)
|
172
174
|
self.signature_key = self.class.generate_signature_key(key_length)
|
173
175
|
end
|
@@ -179,13 +181,13 @@ module OrangeData
|
|
179
181
|
|
180
182
|
def self.read_certs_from_pack(path, signature_key_name:nil, cert_key_pass:nil, title:nil, signature_key:nil)
|
181
183
|
path = File.expand_path(path)
|
182
|
-
client_cert = Dir.glob(path + '/*.{crt}').select{|f| File.file?(f.sub(/.crt\z/, '.key'))}
|
184
|
+
client_cert = Dir.glob(path + '/*.{crt}').select{|f| File.file?(f.sub(/.crt\z/, '.key')) }
|
183
185
|
raise 'Expect to find exactly one <num>.crt with corresponding <num>.key file' unless client_cert.size == 1
|
184
186
|
client_cert = client_cert.first
|
185
187
|
|
186
188
|
unless signature_key
|
187
189
|
# private_key_test.xml || rsa_\d+_private_key.xml
|
188
|
-
xmls = Dir.glob(path + '/*.{xml}').select{|f| f =~ /private/}
|
190
|
+
xmls = Dir.glob(path + '/*.{xml}').select{|f| f =~ /private/ }
|
189
191
|
signature_key = if xmls.size == 1
|
190
192
|
File.read(xmls.first)
|
191
193
|
else
|
@@ -200,7 +202,7 @@ module OrangeData
|
|
200
202
|
certificate: File.read(client_cert),
|
201
203
|
certificate_key: File.read(client_cert.sub(/.crt\z/, '.key')),
|
202
204
|
certificate_key_pass: cert_key_pass,
|
203
|
-
signature_key: signature_key
|
205
|
+
signature_key: signature_key
|
204
206
|
)
|
205
207
|
end
|
206
208
|
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module OrangeData
|
7
|
+
|
8
|
+
unless "".respond_to?(:underscore)
|
9
|
+
# taken from ActiveSupport
|
10
|
+
module StringExt
|
11
|
+
refine String do
|
12
|
+
def underscore
|
13
|
+
self.gsub(/::/, '/').
|
14
|
+
gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
|
15
|
+
gsub(/([a-z\d])([A-Z])/, '\1_\2').
|
16
|
+
tr("-", "_").
|
17
|
+
downcase
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
using StringExt
|
22
|
+
end
|
23
|
+
|
24
|
+
module GeneratedAttributes
|
25
|
+
def self.from_schema(klass, schema)
|
26
|
+
klass.class_eval{
|
27
|
+
extend GeneratedAttributes
|
28
|
+
generate_accessors_from_schema(schema)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
def generate_accessors_from_schema(schema)
|
34
|
+
plain_types = %w[integer string number]
|
35
|
+
schema["properties"].each_pair do |property, info|
|
36
|
+
property_name = info["x-name"] || property.underscore
|
37
|
+
|
38
|
+
if plain_types.include?(info["type"])
|
39
|
+
if info["x-enum"]
|
40
|
+
inverse_map = info["x-enum"].map{|k, v| [v['val'], k.to_sym] }.to_h
|
41
|
+
define_method(property_name){
|
42
|
+
return nil if @payload[property].nil?
|
43
|
+
inverse_map[@payload[property]] ||
|
44
|
+
raise("unknown value #{@payload[property].inspect} for field #{property}")
|
45
|
+
}
|
46
|
+
define_method(:"#{property_name}="){|val|
|
47
|
+
unless val.nil?
|
48
|
+
val = (info["x-enum"][val.to_s] ||
|
49
|
+
raise(ArgumentError, "unknown value #{val.inspect} for property #{property}")
|
50
|
+
)["val"]
|
51
|
+
end
|
52
|
+
@payload[property] = val
|
53
|
+
}
|
54
|
+
|
55
|
+
elsif info["x-bitfield"]
|
56
|
+
bitmap = info["x-bitfield"].map{|k, v| [k.to_sym, 1 << v['bit']] }.to_h
|
57
|
+
# TODO: return wrapper so that :<< etc will work
|
58
|
+
define_method(property_name){
|
59
|
+
return nil if @payload[property].nil?
|
60
|
+
data = @payload[property].to_i
|
61
|
+
# FIXME: unknown bits will be silently lost
|
62
|
+
bitmap.reject{|_, v| (data & v).zero? }.map(&:first)
|
63
|
+
}
|
64
|
+
define_method(:"#{property_name}="){|val|
|
65
|
+
unless val.nil?
|
66
|
+
val = [val] unless val.is_a?(Array)
|
67
|
+
val = val.map{|v| bitmap[v] || raise(ArgumentError, "unknown value #{v.inspect} for property #{property}") }.reduce(:|)
|
68
|
+
end
|
69
|
+
@payload[property] = val
|
70
|
+
}
|
71
|
+
else
|
72
|
+
# primitive
|
73
|
+
define_method(property_name){ @payload[property] }
|
74
|
+
define_method(:"#{property_name}="){|val| @payload[property] = val }
|
75
|
+
end
|
76
|
+
elsif info["type"] == 'array'
|
77
|
+
if info["items"] && plain_types.include?(info["items"]["type"])
|
78
|
+
define_method(property_name){ @payload[property] }
|
79
|
+
define_method(:"#{property_name}="){|val|
|
80
|
+
val = [val] unless val.is_a?(Array)
|
81
|
+
@payload[property] = val
|
82
|
+
}
|
83
|
+
else
|
84
|
+
# ref?
|
85
|
+
end
|
86
|
+
else
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
if info["x-alias"]
|
91
|
+
alias_method "#{info['x-alias']}", property_name
|
92
|
+
alias_method "#{info['x-alias']}=", "#{property_name}="
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# base class for semi-generated classes
|
99
|
+
class PayloadContent
|
100
|
+
def initialize(payload={})
|
101
|
+
@payload = payload
|
102
|
+
end
|
103
|
+
|
104
|
+
def assign_attributes(options)
|
105
|
+
options.each_pair{|k, v|
|
106
|
+
setter = :"#{k}="
|
107
|
+
send(setter, v)
|
108
|
+
}
|
109
|
+
# for chaining:
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
def ==(other)
|
114
|
+
self.class == other.class && to_hash == other.to_hash
|
115
|
+
# @payload == other.instance_variable_get(:@payload)
|
116
|
+
end
|
117
|
+
|
118
|
+
def to_hash
|
119
|
+
@payload
|
120
|
+
end
|
121
|
+
|
122
|
+
def to_json(*args)
|
123
|
+
to_hash.to_json(*args)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
data/lib/orange_data/receipt.rb
CHANGED
@@ -2,25 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'yaml'
|
4
4
|
require 'json'
|
5
|
+
require_relative "generated_attributes"
|
5
6
|
|
6
7
|
module OrangeData
|
7
8
|
|
8
9
|
PAYLOAD_SCHEMA = YAML.load_file(File.expand_path('schema_definitions.yml', __dir__)).freeze
|
9
10
|
|
10
|
-
# taken from ActiveSupport
|
11
|
-
module StringExt
|
12
|
-
refine String do
|
13
|
-
def underscore
|
14
|
-
self.gsub(/::/, '/').
|
15
|
-
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
16
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
17
|
-
tr("-", "_").
|
18
|
-
downcase
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
using StringExt unless "".respond_to?(:underscore)
|
23
|
-
|
24
11
|
# main class for receipt/correction
|
25
12
|
class Document
|
26
13
|
|
@@ -51,7 +38,7 @@ module OrangeData
|
|
51
38
|
@content = ReceiptContent.new(content || {})
|
52
39
|
super
|
53
40
|
end
|
54
|
-
PAYLOAD_SCHEMA["definitions"]["CheckContent"]["properties"]["type"]["x-enum"].each_pair do |slug,
|
41
|
+
PAYLOAD_SCHEMA["definitions"]["CheckContent"]["properties"]["type"]["x-enum"].each_pair do |slug, _info|
|
55
42
|
define_singleton_method(slug) do |**args, &block|
|
56
43
|
new(**args, &block).tap{|doc|
|
57
44
|
doc.content.type = slug
|
@@ -60,105 +47,8 @@ module OrangeData
|
|
60
47
|
end
|
61
48
|
end
|
62
49
|
|
63
|
-
module GeneratedAttributes
|
64
|
-
def self.from_schema klass, schema
|
65
|
-
klass.class_eval{
|
66
|
-
extend GeneratedAttributes
|
67
|
-
generate_accessors_from_schema(schema)
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
protected
|
72
|
-
def generate_accessors_from_schema schema
|
73
|
-
plain_types = %w[integer string number]
|
74
|
-
schema["properties"].each_pair do |property, info|
|
75
|
-
if plain_types.include?(info["type"])
|
76
|
-
if info["x-enum"]
|
77
|
-
inverse_map = info["x-enum"].map{|k,v| [v['val'], k.to_sym]}.to_h
|
78
|
-
define_method(property.underscore){
|
79
|
-
return nil if @payload[property].nil?
|
80
|
-
inverse_map[@payload[property]] || "unknown value #{@payload[property].inspect} for field #{property}"
|
81
|
-
}
|
82
|
-
define_method(:"#{property.underscore}="){|val|
|
83
|
-
unless val.nil?
|
84
|
-
val = (info["x-enum"][val.to_s] || raise(ArgumentError, "unknown value #{val.inspect} for property #{property}"))["val"]
|
85
|
-
end
|
86
|
-
@payload[property] = val
|
87
|
-
}
|
88
|
-
|
89
|
-
elsif info["x-bitfield"]
|
90
|
-
bitmap = info["x-bitfield"].map{|k,v| [k.to_sym, 1 << v['bit']]}.to_h
|
91
|
-
# TODO: return wrapper so that :<< etc will work
|
92
|
-
define_method(property.underscore){
|
93
|
-
return nil if @payload[property].nil?
|
94
|
-
data = @payload[property].to_i
|
95
|
-
# FIXME: unknown bits will be silently lost
|
96
|
-
bitmap.reject{|_,v| (data & v).zero? }.map(&:first)
|
97
|
-
}
|
98
|
-
define_method(:"#{property.underscore}="){|val|
|
99
|
-
unless val.nil?
|
100
|
-
val = [val] unless val.is_a?(Array)
|
101
|
-
val = val.map{|v| bitmap[v] || raise(ArgumentError, "unknown value #{v.inspect} for property #{property}") }.reduce(:|)
|
102
|
-
end
|
103
|
-
@payload[property] = val
|
104
|
-
}
|
105
|
-
else
|
106
|
-
# primitive
|
107
|
-
define_method(property.underscore){ @payload[property] }
|
108
|
-
define_method(:"#{property.underscore}="){|val| @payload[property] = val }
|
109
|
-
end
|
110
|
-
elsif info["type"] == 'array'
|
111
|
-
if info["items"] && plain_types.include?(info["items"]["type"])
|
112
|
-
define_method(property.underscore){ @payload[property] }
|
113
|
-
define_method(:"#{property.underscore}="){|val|
|
114
|
-
val = [val] unless val.is_a?(Array)
|
115
|
-
@payload[property] = val
|
116
|
-
}
|
117
|
-
else
|
118
|
-
# ref?
|
119
|
-
end
|
120
|
-
else
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
if info["x-alias"]
|
125
|
-
# alias_method "#{info["x-alias"]}", property.underscore
|
126
|
-
alias_method "#{info["x-alias"]}=", "#{property.underscore}="
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
# base class for semi-generated classes
|
133
|
-
class PayloadContent
|
134
|
-
def initialize payload={}
|
135
|
-
@payload = payload
|
136
|
-
end
|
137
|
-
|
138
|
-
def assign_attributes options
|
139
|
-
options.each_pair{|k,v|
|
140
|
-
setter = :"#{k}="
|
141
|
-
send(setter, v) if respond_to?(setter)
|
142
|
-
}
|
143
|
-
# for chaining:
|
144
|
-
self
|
145
|
-
end
|
146
|
-
|
147
|
-
def ==(other)
|
148
|
-
self.class == other.class && @payload == other.instance_variable_get(:@payload)
|
149
|
-
end
|
150
|
-
|
151
|
-
def to_hash
|
152
|
-
@payload
|
153
|
-
end
|
154
|
-
|
155
|
-
def to_json(*args)
|
156
|
-
to_hash.to_json(*args)
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
50
|
class ReceiptContent < PayloadContent
|
161
|
-
def initialize
|
51
|
+
def initialize(payload={})
|
162
52
|
@payload = payload || {}
|
163
53
|
# TODO: import...
|
164
54
|
# TODO: taxationSystem default in checkclose
|
@@ -201,14 +91,14 @@ module OrangeData
|
|
201
91
|
self
|
202
92
|
end
|
203
93
|
|
204
|
-
def set_additional_user_attribute
|
94
|
+
def set_additional_user_attribute(**options)
|
205
95
|
@additional_user_attribute = AdditionalUserAttribute.new.assign_attributes(options)
|
206
96
|
end
|
207
97
|
|
208
98
|
|
209
99
|
|
210
100
|
class Position < PayloadContent
|
211
|
-
def initialize
|
101
|
+
def initialize(payload={})
|
212
102
|
@payload = payload
|
213
103
|
@supplier_info = SupplierInfo.new(@payload['supplierInfo']) if @payload['supplierInfo']
|
214
104
|
@agent_info = AgentInfo.new(@payload['agentInfo']) if @payload['agentInfo']
|
@@ -221,12 +111,12 @@ module OrangeData
|
|
221
111
|
}
|
222
112
|
end
|
223
113
|
|
224
|
-
def set_supplier_info
|
114
|
+
def set_supplier_info(**options)
|
225
115
|
@supplier_info = SupplierInfo.new.assign_attributes(options)
|
226
116
|
self
|
227
117
|
end
|
228
118
|
|
229
|
-
def set_agent_info
|
119
|
+
def set_agent_info(**options)
|
230
120
|
@agent_info = AgentInfo.new.assign_attributes(options)
|
231
121
|
self
|
232
122
|
end
|
@@ -237,30 +127,18 @@ module OrangeData
|
|
237
127
|
end
|
238
128
|
|
239
129
|
class AgentInfo < PayloadContent
|
240
|
-
def initialize payload={}
|
241
|
-
@payload = payload
|
242
|
-
end
|
243
|
-
def to_hash
|
244
|
-
@payload
|
245
|
-
end
|
246
130
|
GeneratedAttributes.from_schema(self, PAYLOAD_SCHEMA["definitions"]["AgentInfo"])
|
247
131
|
end
|
248
132
|
|
249
133
|
class SupplierInfo < PayloadContent
|
250
|
-
def initialize payload={}
|
251
|
-
@payload = payload
|
252
|
-
end
|
253
|
-
def to_hash
|
254
|
-
@payload
|
255
|
-
end
|
256
134
|
GeneratedAttributes.from_schema(self, PAYLOAD_SCHEMA["definitions"]["SupplierInfo"])
|
257
135
|
end
|
258
136
|
|
259
137
|
class CheckClose < PayloadContent
|
260
|
-
def initialize
|
138
|
+
def initialize(payload={})
|
261
139
|
payload ||= {}
|
262
140
|
@payload = payload
|
263
|
-
@payments = (payload['payments'] || []).map{|p| Payment.new(p)}
|
141
|
+
@payments = (payload['payments'] || []).map{|p| Payment.new(p) }
|
264
142
|
end
|
265
143
|
|
266
144
|
def to_hash
|
@@ -289,7 +167,7 @@ module OrangeData
|
|
289
167
|
end
|
290
168
|
|
291
169
|
class ReceiptResult < PayloadContent
|
292
|
-
def initialize
|
170
|
+
def initialize(payload)
|
293
171
|
@payload = payload
|
294
172
|
@content = ReceiptContent.new(@payload["content"])
|
295
173
|
end
|
@@ -303,13 +181,12 @@ module OrangeData
|
|
303
181
|
GeneratedAttributes.from_schema(self, PAYLOAD_SCHEMA["definitions"]["CheckStatusViewModel[CheckContent]"])
|
304
182
|
|
305
183
|
def qr_code_content
|
306
|
-
# С живого чека: t=20180518T220500&s=975.88&fn=8710000101125654&i=99456&fp=1250448795&n=1
|
307
184
|
# Пример: t=20150720T1638&s=9999999.00&fn=000110000105&i=12345678&fp=123456&n=2
|
308
185
|
{
|
309
186
|
# - t=<date/time - дата и время осуществления расчета в формате ГГГГММДДТЧЧММ>
|
310
|
-
t:
|
187
|
+
t: processed_at.gsub(/:\d{2}\z/, '').gsub(/[^0-9T]/, ''),
|
311
188
|
# - s=<сумма расчета в рублях и копейках, разделенных точкой>
|
312
|
-
s: content.check_close.payments.inject(0.0){|d, p| d + p.amount},
|
189
|
+
s: content.check_close.payments.inject(0.0){|d, p| d + p.amount },
|
313
190
|
# - fn=<заводской номер фискального накопителя>
|
314
191
|
fn: fs_number,
|
315
192
|
# - i=<порядковый номер фискального документа, нулями не дополняется>
|
@@ -317,7 +194,7 @@ module OrangeData
|
|
317
194
|
# - fp=<фискальный признак документа, нулями не дополняется>
|
318
195
|
fp: fp,
|
319
196
|
# - n=<признак расчета>.
|
320
|
-
n: content.raw_type,
|
197
|
+
n: content.raw_type,
|
321
198
|
}.map{|k, v| "#{k}=#{v}" }.join('&')
|
322
199
|
end
|
323
200
|
end
|
@@ -329,7 +206,7 @@ module OrangeData
|
|
329
206
|
@content = CorrectionContent.new(content || {})
|
330
207
|
super
|
331
208
|
end
|
332
|
-
PAYLOAD_SCHEMA["definitions"]["CorrectionContent"]["properties"]["type"]["x-enum"].each_pair do |slug,
|
209
|
+
PAYLOAD_SCHEMA["definitions"]["CorrectionContent"]["properties"]["type"]["x-enum"].each_pair do |slug, _info|
|
333
210
|
define_singleton_method(slug) do |**args, &block|
|
334
211
|
new(**args, &block).tap{|doc|
|
335
212
|
doc.content.type = slug
|
@@ -343,7 +220,7 @@ module OrangeData
|
|
343
220
|
end
|
344
221
|
|
345
222
|
class CorrectionResult < PayloadContent
|
346
|
-
def initialize
|
223
|
+
def initialize(payload)
|
347
224
|
@payload = payload || {}
|
348
225
|
@content = CorrectionContent.new(@payload["content"] || {})
|
349
226
|
end
|
@@ -605,38 +605,45 @@ definitions:
|
|
605
605
|
type: number
|
606
606
|
automatNumber:
|
607
607
|
description: Номер автомата
|
608
|
+
x-comment: Только для вендинга
|
608
609
|
x-tag-id: 1036
|
609
610
|
type: string
|
610
611
|
settlementAddress:
|
611
612
|
description: Адрес расчетов
|
613
|
+
x-comment: Только для вендинга
|
612
614
|
x-tag-id: 1009
|
613
615
|
type: string
|
614
616
|
settlementPlace:
|
615
617
|
description: Место расчетов
|
618
|
+
x-comment: Только для вендинга
|
616
619
|
x-tag-id: 1187
|
617
620
|
type: string
|
618
621
|
cashSum:
|
622
|
+
x-name: sum_cash
|
619
623
|
format: double
|
620
624
|
description: Сумма по чеку (БСО) наличными
|
621
625
|
x-tag-id: 1031
|
622
626
|
type: number
|
623
627
|
eCashSum:
|
624
|
-
x-
|
628
|
+
x-name: sum_card
|
625
629
|
format: double
|
626
630
|
description: Сумма по чеку (БСО) электронными
|
627
631
|
x-tag-id: 1081
|
628
632
|
type: number
|
629
633
|
prepaymentSum:
|
634
|
+
x-name: sum_prepaid
|
630
635
|
format: double
|
631
636
|
description: Сумма по чеку (БСО) предоплатой (зачетом аванса и (или) предыдущих платежей)
|
632
637
|
x-tag-id: 1215
|
633
638
|
type: number
|
634
639
|
postpaymentSum:
|
640
|
+
x-name: sum_credit
|
635
641
|
format: double
|
636
642
|
description: Сумма по чеку (БСО) постоплатой (в кредит)
|
637
643
|
x-tag-id: 1216
|
638
644
|
type: number
|
639
645
|
otherPaymentTypeSum:
|
646
|
+
x-name: sum_counterclaim
|
640
647
|
format: double
|
641
648
|
description: Сумма по чеку (БСО) встречным предоставлением
|
642
649
|
x-tag-id: 1217
|
@@ -73,7 +73,7 @@ module OrangeData
|
|
73
73
|
when 409
|
74
74
|
raise "Conflict"
|
75
75
|
when 400
|
76
|
-
raise "Invalid doc: #{res.body[
|
76
|
+
raise "Invalid doc: #{res.body['errors'] || res.body}"
|
77
77
|
when 503
|
78
78
|
if res.headers['Retry-After']
|
79
79
|
raise "Document queue full, retry in #{res.headers['Retry-After']}"
|
@@ -89,7 +89,7 @@ module OrangeData
|
|
89
89
|
when 200
|
90
90
|
return res.body
|
91
91
|
when 400
|
92
|
-
raise "Cannot get doc: #{res.body[
|
92
|
+
raise "Cannot get doc: #{res.body['errors'] || res.body}"
|
93
93
|
when 401
|
94
94
|
raise 'Unauthorized'
|
95
95
|
end
|
data/lib/orange_data/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: orangedata
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vasily Fedoseyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-10-
|
11
|
+
date: 2018-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -157,6 +157,7 @@ files:
|
|
157
157
|
- lib/orange_data.rb
|
158
158
|
- lib/orange_data/credentials.rb
|
159
159
|
- lib/orange_data/credentials_test.yml
|
160
|
+
- lib/orange_data/generated_attributes.rb
|
160
161
|
- lib/orange_data/receipt.rb
|
161
162
|
- lib/orange_data/schema_definitions.yml
|
162
163
|
- lib/orange_data/transport.rb
|