orangedata 0.0.1 → 0.0.2
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/.gitignore +1 -0
- data/.rubocop.yml +71 -0
- data/.travis.yml +1 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +1 -1
- data/README.md +18 -17
- data/bin/console +1 -0
- data/lib/orange_data/credentials.rb +67 -33
- data/lib/orange_data/receipt.rb +15 -13
- data/lib/orange_data/transport.rb +17 -22
- data/lib/orange_data/version.rb +5 -1
- data/lib/orange_data.rb +1 -1
- data/lib/orangedata.rb +2 -0
- data/orangedata.gemspec +9 -6
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2dde9cd360d680c7c81b2daa172585325a888a57
|
|
4
|
+
data.tar.gz: fc2569d5d679490fb5315873fd94c3e26a8fc8af
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b62936f69fd98b21c29ba5eb028206aa1ea8a8d073262acba0dc3aaef7ee86a7a49f5237d8deaed690391e4b0a541679f1b6899583e23102e7da100522531560
|
|
7
|
+
data.tar.gz: f1b7e6ef44e611925d8a3147b27df7b7413be86bb9c686b329d171dd25fe4ece1028b55e1aea2de59d5712541f8e034596adaf509709f758d13dca3621baace7
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
# DefaultFormatter: fuubar
|
|
3
|
+
# TargetRubyVersion: 2.1
|
|
4
|
+
TargetRubyVersion: 2.3
|
|
5
|
+
Exclude:
|
|
6
|
+
- 'spec/fixtures/**/*'
|
|
7
|
+
- 'tmp/**/*'
|
|
8
|
+
|
|
9
|
+
Gemspec/RequiredRubyVersion:
|
|
10
|
+
Enabled: false
|
|
11
|
+
|
|
12
|
+
Metrics/LineLength:
|
|
13
|
+
Max: 120
|
|
14
|
+
|
|
15
|
+
Metrics/BlockLength:
|
|
16
|
+
Exclude:
|
|
17
|
+
- 'spec/**/*'
|
|
18
|
+
|
|
19
|
+
Metrics/MethodLength:
|
|
20
|
+
Max: 20
|
|
21
|
+
|
|
22
|
+
Metrics/AbcSize:
|
|
23
|
+
Max: 50
|
|
24
|
+
|
|
25
|
+
Metrics/CyclomaticComplexity:
|
|
26
|
+
Max: 50
|
|
27
|
+
|
|
28
|
+
Metrics/PerceivedComplexity:
|
|
29
|
+
Max: 50
|
|
30
|
+
|
|
31
|
+
Style/StringLiterals:
|
|
32
|
+
Enabled: false
|
|
33
|
+
# EnforcedStyle: double_quotes
|
|
34
|
+
|
|
35
|
+
Style/RedundantReturn:
|
|
36
|
+
Enabled: false
|
|
37
|
+
|
|
38
|
+
Layout/SpaceBeforeBlockBraces:
|
|
39
|
+
EnforcedStyle: no_space
|
|
40
|
+
|
|
41
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
|
42
|
+
EnforcedStyle: no_space
|
|
43
|
+
|
|
44
|
+
Layout/SpaceAfterColon:
|
|
45
|
+
Enabled: false
|
|
46
|
+
|
|
47
|
+
Layout/SpaceAroundOperators:
|
|
48
|
+
Enabled: false
|
|
49
|
+
|
|
50
|
+
Layout/EndAlignment:
|
|
51
|
+
EnforcedStyleAlignWith: variable
|
|
52
|
+
|
|
53
|
+
Layout/SpaceInsideBlockBraces:
|
|
54
|
+
SpaceBeforeBlockParameters: false
|
|
55
|
+
|
|
56
|
+
Layout/EmptyLinesAroundBlockBody:
|
|
57
|
+
Exclude:
|
|
58
|
+
- 'spec/**/*'
|
|
59
|
+
|
|
60
|
+
Layout/EmptyLinesAroundModuleBody:
|
|
61
|
+
Enabled: false
|
|
62
|
+
# EnforcedStyle: empty_lines_except_namespace
|
|
63
|
+
Layout/EmptyLinesAroundClassBody:
|
|
64
|
+
Enabled: false
|
|
65
|
+
# EnforcedStyle: empty_lines_except_namespace
|
|
66
|
+
|
|
67
|
+
Style/AsciiComments:
|
|
68
|
+
Enabled: false
|
|
69
|
+
|
|
70
|
+
Style/TrailingCommaInHashLiteral:
|
|
71
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
source "https://rubygems.org"
|
|
2
4
|
|
|
3
|
-
git_source(:github)
|
|
5
|
+
git_source(:github){|repo_name| "https://github.com/#{repo_name}" }
|
|
4
6
|
|
|
5
7
|
# All dependencies are in orangedata.gemspec
|
|
6
8
|
gemspec
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Orangedata Client
|
|
2
2
|
|
|
3
|
+
[](https://badge.fury.io/rb/orangedata)
|
|
4
|
+
[](https://travis-ci.org/Vasfed/orangedata)
|
|
5
|
+
|
|
3
6
|
A ruby client for orangedata.ru service.
|
|
4
7
|
Target service is pretty local to RU, so parts of readme will be in russian.
|
|
5
8
|
|
|
@@ -28,7 +31,7 @@ gem 'orangedata'
|
|
|
28
31
|
|
|
29
32
|
## Использование
|
|
30
33
|
|
|
31
|
-
Для тестового окружения ключики в комплекте - [credentials_test.yml](lib/credentials_test.yml), собрано из родного `File_for_test.zip`, доступны как `OrangeData::Credentials.default_test`
|
|
34
|
+
Для тестового окружения ключики в комплекте - [credentials_test.yml](lib/orange_data/credentials_test.yml), собрано из родного `File_for_test.zip`, доступны как `OrangeData::Credentials.default_test`
|
|
32
35
|
|
|
33
36
|
```ruby
|
|
34
37
|
transport = OrangeData::Transport.new("https://apip.orangedata.ru:2443/api/v2/", OrangeData::Credentials.default_test)
|
|
@@ -83,28 +86,26 @@ gem 'orangedata'
|
|
|
83
86
|
Предполагается, что всякие договоры и прочая фискализация уже успешно пройдена и у вас есть доступ
|
|
84
87
|
к ЛК orangedata.
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
В [ЛК в разделе интеграций](https://lk.orangedata.ru/lk/integrations/direct) запрашиваем сертификат (шаг 3, первый шаг не нужен, а данные для второго получатся ниже), распаковываем полученный zip-архив и натравливаем туда генератор:
|
|
87
90
|
|
|
88
91
|
```ruby
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
#=> возвращает публичный ключ в том виде, который хочет ЛК OrangeData:
|
|
93
|
-
# "<RSAKeyValue><Modulus>(многабукв)==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"
|
|
94
|
-
|
|
95
|
-
File.open("my_production.yml", "wt"){|f| f.write YAML.dump(c.to_hash) }
|
|
96
|
-
# (на выходе - yml с приватным ключом и паролем к нему, который надо сохранить и беречь)
|
|
97
|
-
|
|
98
|
-
# повторно взять публичный ключ можно так:
|
|
99
|
-
credentials = OrangeData::Credentials.from_hash(YAML.load_file('my_production.yml'))
|
|
100
|
-
credentials.signature_public_xml
|
|
101
|
-
```
|
|
92
|
+
c = OrangeData::Credentials.read_certs_from_pack('~/Downloads/1234567890', title:'My production', cert_key_pass:'1234') # cert_key_pass берем из readme_v2.txt, но есть подозрение что он у всех 1234
|
|
93
|
+
# Generated public signature key: <RSAKeyValue>...</Exponent></RSAKeyValue>
|
|
94
|
+
File.open("my_production.yml", "wt"){|f| f.write c.to_yaml }
|
|
102
95
|
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
# опционально на маке копируем публичный ключ в буфер обмена:
|
|
97
|
+
system("echo '#{c.signature_public_xml}' | pbcopy")
|
|
98
|
+
```
|
|
105
99
|
|
|
106
100
|
Если все прошло гладко - теперь у вас есть файлик `my_production.yml` со всеми реквизитами доступа к продакшн-кассе. Обращаться с ним стоит как и с любой другой очень чувствительной информацией, например не стоит коммитить его (ну или как минимум, убрать из него поля `signature_key_pass` и `certificate_key_pass` и хранить отдельно)
|
|
107
101
|
|
|
102
|
+
Дальше публичный ключ с предыдущего шага отправляется в ЛК, там его сохряняем, "подключаем интеграцию", и пользуемся:
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
transport = OrangeData::Transport.new(OrangeData::Transport::DEFAULT_PRODUCTION_API_URL, OrangeData::Credentials.from_hash(YAML.load('my_production.yml')))
|
|
106
|
+
transport.post_document # и далее по тексту, осторожно - не пробейте лишние чеки во время проверок
|
|
107
|
+
```
|
|
108
|
+
|
|
108
109
|
## Разработка
|
|
109
110
|
|
|
110
111
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/bin/console
CHANGED
|
@@ -3,27 +3,26 @@
|
|
|
3
3
|
require "openssl"
|
|
4
4
|
require "base64"
|
|
5
5
|
require "securerandom"
|
|
6
|
+
require "yaml"
|
|
6
7
|
|
|
7
|
-
# wrapper for keys/certs used for connection auth
|
|
8
8
|
module OrangeData
|
|
9
|
+
# wrapper for keys/certs used for connection auth
|
|
9
10
|
class Credentials
|
|
10
11
|
|
|
11
12
|
# nodoc
|
|
12
13
|
module KeyEncoding
|
|
14
|
+
|
|
13
15
|
refine OpenSSL::PKey::RSA do
|
|
14
16
|
def to_xml
|
|
15
17
|
h_params = to_hash
|
|
16
18
|
h = { 'Modulus' => :n, 'Exponent' => :e }
|
|
17
|
-
if private?
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
})
|
|
21
|
-
end
|
|
22
|
-
"<RSAKeyValue>#{h.map{|(k,v)| "<#{k}>#{h_params[v.to_s]}</#{k}>"}.join('')}</RSAKeyValue>"
|
|
19
|
+
h.merge!('P' => :p, 'Q' => :q, 'DP' => :dmp1, 'DQ' => :dmq1, 'InverseQ' => :iqmp, 'D' => :d) if private?
|
|
20
|
+
|
|
21
|
+
"<RSAKeyValue>#{h.map{|(k, v)| "<#{k}>#{h_params[v.to_s]}</#{k}>" }.join('')}</RSAKeyValue>"
|
|
23
22
|
end
|
|
24
23
|
|
|
25
24
|
def to_hash
|
|
26
|
-
params.map{|k,v| v != 0 && [k, Base64.strict_encode64(v.to_s(2))] || nil}.compact.to_h
|
|
25
|
+
params.map{|k, v| v != 0 && [k, Base64.strict_encode64(v.to_s(2))] || nil }.compact.to_h
|
|
27
26
|
end
|
|
28
27
|
end
|
|
29
28
|
|
|
@@ -31,7 +30,7 @@ module OrangeData
|
|
|
31
30
|
def from_xml(xml)
|
|
32
31
|
require "rexml/document"
|
|
33
32
|
kv = REXML::Document.new(xml).elements['RSAKeyValue']
|
|
34
|
-
raise ArgumentError, 'no RSAKeyValue in xml' unless kv
|
|
33
|
+
raise ArgumentError, 'no RSAKeyValue in xml' unless kv && kv.name == 'RSAKeyValue'
|
|
35
34
|
|
|
36
35
|
mapping = {
|
|
37
36
|
"Modulus"=>:n, "Exponent"=>:e,
|
|
@@ -39,27 +38,28 @@ module OrangeData
|
|
|
39
38
|
"DP"=>:dmp1, "DQ"=>:dmq1, "InverseQ"=>:iqmp
|
|
40
39
|
}
|
|
41
40
|
from_hash(
|
|
42
|
-
kv.elements.each_with_object({}){|k,h| h[mapping[k.name]] = k.text if mapping[k.name] }
|
|
41
|
+
kv.elements.each_with_object({}){|k, h| h[mapping[k.name]] = k.text if mapping[k.name] }
|
|
43
42
|
)
|
|
44
43
|
end
|
|
45
44
|
|
|
46
|
-
def from_hash
|
|
45
|
+
def from_hash(hash)
|
|
47
46
|
OpenSSL::PKey::RSA.new.tap do |key|
|
|
48
|
-
key.params.keys.each
|
|
49
|
-
if(v = hash[param] || hash[param.to_sym])
|
|
47
|
+
key.params.keys.each do |param|
|
|
48
|
+
if (v = hash[param] || hash[param.to_sym])
|
|
50
49
|
key.send(:"#{param}=", OpenSSL::BN.new(Base64.decode64(v), 2))
|
|
51
50
|
end
|
|
52
|
-
|
|
51
|
+
end
|
|
53
52
|
end
|
|
54
53
|
end
|
|
55
54
|
end
|
|
55
|
+
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
using KeyEncoding
|
|
59
59
|
|
|
60
60
|
attr_accessor :signature_key_name, :signature_key, :certificate, :certificate_key, :title
|
|
61
61
|
|
|
62
|
-
def initialize
|
|
62
|
+
def initialize(signature_key_name:nil, signature_key:nil, certificate:nil, certificate_key:nil, title:nil)
|
|
63
63
|
raise ArgumentError, "Signature key should be a private key" if signature_key && !signature_key.private?
|
|
64
64
|
raise ArgumentError, "Certificate key should be a private key" if certificate_key && !certificate_key.private?
|
|
65
65
|
@signature_key_name = signature_key_name
|
|
@@ -71,16 +71,18 @@ module OrangeData
|
|
|
71
71
|
|
|
72
72
|
def valid?
|
|
73
73
|
signature_key_name &&
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
signature_key && signature_key.private? &&
|
|
75
|
+
certificate && certificate_key && certificate_key.private?
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
-
def self.from_hash
|
|
78
|
+
def self.from_hash(creds)
|
|
79
79
|
key = nil
|
|
80
80
|
if creds[:signature_key]
|
|
81
|
-
key = if creds[:signature_key].is_a?(
|
|
81
|
+
key = if creds[:signature_key].is_a?(OpenSSL::PKey::RSA)
|
|
82
|
+
creds[:signature_key]
|
|
83
|
+
elsif creds[:signature_key].is_a?(Hash)
|
|
82
84
|
OpenSSL::PKey::RSA.from_hash(creds[:signature_key])
|
|
83
|
-
elsif creds[:signature_key].start_with?('<')
|
|
85
|
+
elsif creds[:signature_key].is_a?(String) && creds[:signature_key].start_with?('<')
|
|
84
86
|
OpenSSL::PKey::RSA.from_xml(creds[:signature_key])
|
|
85
87
|
else
|
|
86
88
|
OpenSSL::PKey::RSA.new(creds[:signature_key], creds[:signature_key_pass])
|
|
@@ -90,7 +92,8 @@ module OrangeData
|
|
|
90
92
|
signature_key_name: creds[:signature_key_name],
|
|
91
93
|
signature_key: key,
|
|
92
94
|
certificate: creds[:certificate] && OpenSSL::X509::Certificate.new(creds[:certificate]),
|
|
93
|
-
certificate_key: creds[:certificate_key] &&
|
|
95
|
+
certificate_key: creds[:certificate_key] &&
|
|
96
|
+
OpenSSL::PKey::RSA.new(creds[:certificate_key], creds[:certificate_key_pass]),
|
|
94
97
|
title: creds[:title]
|
|
95
98
|
)
|
|
96
99
|
end
|
|
@@ -106,19 +109,19 @@ module OrangeData
|
|
|
106
109
|
{
|
|
107
110
|
title: title,
|
|
108
111
|
signature_key_name: signature_key_name,
|
|
109
|
-
signature_key: signature_key
|
|
110
|
-
certificate: certificate
|
|
111
|
-
certificate_key: certificate_key
|
|
112
|
+
signature_key: signature_key && signature_key.to_pem(OpenSSL::Cipher.new("aes-128-cbc"), key_pass),
|
|
113
|
+
certificate: certificate && certificate.to_pem,
|
|
114
|
+
certificate_key: certificate_key && certificate_key.to_pem(OpenSSL::Cipher.new("aes-128-cbc"), key_pass),
|
|
112
115
|
}.tap do |h|
|
|
113
116
|
h.delete(:title) if !title || title == ''
|
|
114
117
|
if save_pass
|
|
115
|
-
h[:certificate_key_pass] = key_pass
|
|
116
|
-
h[:signature_key_pass] = key_pass
|
|
118
|
+
h[:certificate_key_pass] = key_pass if certificate && key_pass
|
|
119
|
+
h[:signature_key_pass] = key_pass if signature_key && key_pass
|
|
117
120
|
end
|
|
118
121
|
end
|
|
119
122
|
end
|
|
120
123
|
|
|
121
|
-
def self.from_json
|
|
124
|
+
def self.from_json(json)
|
|
122
125
|
require 'json'
|
|
123
126
|
from_hash(JSON.parse(json, symbolize_names: true))
|
|
124
127
|
end
|
|
@@ -127,19 +130,51 @@ module OrangeData
|
|
|
127
130
|
to_hash(key_pass:key_pass, save_pass:save_pass).to_json
|
|
128
131
|
end
|
|
129
132
|
|
|
133
|
+
def to_yaml(key_pass:nil, save_pass:false)
|
|
134
|
+
to_hash(key_pass:key_pass, save_pass:save_pass).to_yaml
|
|
135
|
+
end
|
|
136
|
+
|
|
130
137
|
def inspect
|
|
131
138
|
info_fields = {
|
|
132
139
|
title: (title || 'untitled').inspect,
|
|
133
140
|
key_name: signature_key_name.inspect,
|
|
134
|
-
|
|
135
|
-
}.map{|(k,v)| "#{k}=#{v}"}.join(' ')
|
|
141
|
+
}
|
|
136
142
|
|
|
137
|
-
|
|
143
|
+
if certificate && (subject_name = certificate.subject.to_a.select{|ent| ent.first == 'O' }.first)
|
|
144
|
+
info_fields[:certificate] = %Q("#{(subject_name[1] || 'unknown').gsub('"', '\"')}")
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
"#<#{self.class.name}:#{object_id} #{info_fields.map{|(k, v)| "#{k}=#{v}" }.join(' ')}>"
|
|
138
148
|
end
|
|
139
149
|
|
|
140
150
|
def generate_signature_key!(key_length=2048)
|
|
141
151
|
self.signature_key = OpenSSL::PKey::RSA.new(key_length)
|
|
142
|
-
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def self.read_certs_from_pack(path, signature_key_name:nil, cert_key_pass:nil, title:nil)
|
|
155
|
+
path = File.expand_path(path)
|
|
156
|
+
client_cert = Dir.glob(path + '/*.{crt}').select{|f| File.file?(f.sub(/.crt\z/, '.key'))}
|
|
157
|
+
raise 'Expect to find exactly one <num>.crt with corresponding <num>.key file' unless client_cert.size == 1
|
|
158
|
+
client_cert = client_cert.first
|
|
159
|
+
|
|
160
|
+
# private_key_test.xml || rsa_\d+_private_key.xml
|
|
161
|
+
xmls = Dir.glob(path + '/*.{xml}').select{|f| f =~ /private/}
|
|
162
|
+
signature_key = if xmls.size == 1
|
|
163
|
+
File.read(xmls.first)
|
|
164
|
+
else
|
|
165
|
+
OpenSSL::PKey::RSA.new(2048).tap{|k|
|
|
166
|
+
puts "Generated public signature key: #{k.public_key.to_xml}"
|
|
167
|
+
}
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
from_hash(
|
|
171
|
+
title: title || "Generated from #{File.basename(path)}",
|
|
172
|
+
signature_key_name: signature_key_name || File.basename(client_cert).gsub(/\..*/, ''),
|
|
173
|
+
certificate: File.read(client_cert),
|
|
174
|
+
certificate_key: File.read(client_cert.sub(/.crt\z/, '.key')),
|
|
175
|
+
certificate_key_pass: cert_key_pass,
|
|
176
|
+
signature_key: signature_key,
|
|
177
|
+
)
|
|
143
178
|
end
|
|
144
179
|
|
|
145
180
|
# публичная часть ключа подписи в формате пригодном для отдачи в ЛК
|
|
@@ -149,8 +184,7 @@ module OrangeData
|
|
|
149
184
|
|
|
150
185
|
# ключи для тествого окружения
|
|
151
186
|
def self.default_test
|
|
152
|
-
|
|
153
|
-
from_hash(YAML.load_file(File.expand_path('../credentials_test.yml', __FILE__)))
|
|
187
|
+
from_hash(YAML.load_file(File.expand_path('credentials_test.yml', __dir__)))
|
|
154
188
|
end
|
|
155
189
|
|
|
156
190
|
end
|
data/lib/orange_data/receipt.rb
CHANGED
|
@@ -2,22 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
module OrangeData
|
|
4
4
|
|
|
5
|
+
# main class for receipt
|
|
5
6
|
class Receipt
|
|
7
|
+
|
|
6
8
|
attr_accessor :id, :inn, :group, :key_name
|
|
7
9
|
|
|
8
|
-
def initialize
|
|
10
|
+
def initialize(id:SecureRandom.uuid, inn:, group:nil, key_name:nil)
|
|
9
11
|
@id = id
|
|
10
12
|
@inn = inn
|
|
11
13
|
@group = group
|
|
12
14
|
@key_name = key_name
|
|
13
15
|
yield self if block_given?
|
|
14
16
|
end
|
|
17
|
+
|
|
15
18
|
end
|
|
16
19
|
|
|
20
|
+
# nodoc
|
|
17
21
|
class ReceiptContent
|
|
18
22
|
|
|
23
|
+
# for agent type bit mask
|
|
19
24
|
module AgentTypeSerializer
|
|
20
|
-
AGENT_TYPE_BITS = {
|
|
25
|
+
AGENT_TYPE_BITS = { # 1057 (в чеках/БСО должно соответствовать отчету о (пере)регистрации ККТ)
|
|
21
26
|
bank_payment_agent: (1 << 0), # банковский платежный агент
|
|
22
27
|
bank_payment_subagent: (1 << 1), # банковский платежный субагент
|
|
23
28
|
payment_agent: (1 << 2), # платежный агент
|
|
@@ -27,19 +32,18 @@ module OrangeData
|
|
|
27
32
|
other_agent: (1 << 6), # иной агент
|
|
28
33
|
}.freeze
|
|
29
34
|
|
|
30
|
-
def self.load
|
|
35
|
+
def self.load(data)
|
|
31
36
|
data = data.to_i
|
|
32
|
-
AGENT_TYPE_BITS.
|
|
37
|
+
AGENT_TYPE_BITS.reject{|(_, v)| (data & v).zero? }.map(&:first)
|
|
33
38
|
end
|
|
34
39
|
|
|
35
|
-
def self.dump
|
|
40
|
+
def self.dump(val)
|
|
36
41
|
val = [val] unless val.is_a?(Array)
|
|
37
|
-
val.map{|v| AGENT_TYPE_BITS[v] || raise
|
|
42
|
+
val.map{|v| AGENT_TYPE_BITS[v] || raise("unknown agent_type #{v}") }.reduce(:|)
|
|
38
43
|
end
|
|
39
44
|
end
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
RECEIPT_TYPES = { # 1054:
|
|
46
|
+
RECEIPT_TYPES = { # 1054:
|
|
43
47
|
|
|
44
48
|
}.freeze
|
|
45
49
|
|
|
@@ -55,11 +59,9 @@ module OrangeData
|
|
|
55
59
|
return_expense: 4 # Возврат расхода
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
}.freeze
|
|
61
63
|
|
|
62
|
-
def initialize
|
|
64
|
+
def initialize(_type)
|
|
63
65
|
@positions = []
|
|
64
66
|
@payments = []
|
|
65
67
|
end
|
|
@@ -68,7 +70,7 @@ module OrangeData
|
|
|
68
70
|
AgentTypeSerializer.load(@agent_type)
|
|
69
71
|
end
|
|
70
72
|
|
|
71
|
-
def agent_type=
|
|
73
|
+
def agent_type=(val)
|
|
72
74
|
@agent_type = AgentTypeSerializer.dump(val)
|
|
73
75
|
end
|
|
74
76
|
|
|
@@ -5,22 +5,20 @@ require 'base64'
|
|
|
5
5
|
require 'faraday'
|
|
6
6
|
require 'faraday_middleware'
|
|
7
7
|
|
|
8
|
-
# handles low-level http requests to orangedata, including auth
|
|
9
8
|
module OrangeData
|
|
9
|
+
# handles low-level http requests to orangedata, including auth
|
|
10
10
|
class Transport
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
DEFAULT_TEST_API_URL = "https://apip.orangedata.ru:2443/api/v2/"
|
|
13
|
+
DEFAULT_PRODUCTION_API_URL = "https://api.orangedata.ru:12003/api/v2/"
|
|
14
|
+
|
|
15
|
+
def initialize(api_url=DEFAULT_TEST_API_URL, credentials=Credentials.default_test)
|
|
13
16
|
raise ArgumentError, "Need full credentials for connection" unless credentials.valid?
|
|
14
17
|
@credentials = credentials
|
|
15
18
|
@api_url = api_url
|
|
16
19
|
end
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
# production: https://api.orangedata.ru:12003/api/v2/
|
|
20
|
-
# test: https://apip.orangedata.ru:2443/api/v2/
|
|
21
|
-
"https://apip.orangedata.ru:2443/api/v2/"
|
|
22
|
-
end
|
|
23
|
-
|
|
21
|
+
# middleware for request signatures
|
|
24
22
|
class RequestSignatureMiddleware < Faraday::Middleware
|
|
25
23
|
def initialize(app, signature_key)
|
|
26
24
|
@app = app
|
|
@@ -53,11 +51,11 @@ module OrangeData
|
|
|
53
51
|
end
|
|
54
52
|
end
|
|
55
53
|
|
|
56
|
-
def raw_post
|
|
54
|
+
def raw_post(method, data)
|
|
57
55
|
transport.post(method, data)
|
|
58
56
|
end
|
|
59
57
|
|
|
60
|
-
def post_entity
|
|
58
|
+
def post_entity(sub_url, data)
|
|
61
59
|
res = raw_post(sub_url, data)
|
|
62
60
|
|
|
63
61
|
case res.status
|
|
@@ -74,7 +72,7 @@ module OrangeData
|
|
|
74
72
|
end
|
|
75
73
|
end
|
|
76
74
|
|
|
77
|
-
def get_entity
|
|
75
|
+
def get_entity(sub_url)
|
|
78
76
|
res = transport.get(sub_url)
|
|
79
77
|
|
|
80
78
|
case res.status
|
|
@@ -90,16 +88,13 @@ module OrangeData
|
|
|
90
88
|
# Below actual methods from api
|
|
91
89
|
|
|
92
90
|
def ping
|
|
93
|
-
res = transport.get(''){|r|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return res.status == 200 && res.body == "Nebula.Api v2"
|
|
98
|
-
rescue StandardError => e
|
|
91
|
+
res = transport.get(''){|r| r.headers['Accept'] = 'text/plain' }
|
|
92
|
+
res.status == 200 && res.body == "Nebula.Api v2"
|
|
93
|
+
rescue StandardError => _e
|
|
99
94
|
return false
|
|
100
95
|
end
|
|
101
96
|
|
|
102
|
-
def post_document_validate
|
|
97
|
+
def post_document_validate(data)
|
|
103
98
|
res = raw_post 'validateDocument', data
|
|
104
99
|
|
|
105
100
|
case res.status
|
|
@@ -114,19 +109,19 @@ module OrangeData
|
|
|
114
109
|
end
|
|
115
110
|
end
|
|
116
111
|
|
|
117
|
-
def post_document
|
|
112
|
+
def post_document(data)
|
|
118
113
|
post_entity 'documents', data
|
|
119
114
|
end
|
|
120
115
|
|
|
121
|
-
def get_document
|
|
116
|
+
def get_document(inn, document_id)
|
|
122
117
|
get_entity "documents/#{inn}/status/#{document_id}"
|
|
123
118
|
end
|
|
124
119
|
|
|
125
|
-
def post_correction
|
|
120
|
+
def post_correction(data)
|
|
126
121
|
post_entity 'corrections', data
|
|
127
122
|
end
|
|
128
123
|
|
|
129
|
-
def get_correction
|
|
124
|
+
def get_correction(inn, document_id)
|
|
130
125
|
get_entity "corrections/#{inn}/status/#{document_id}"
|
|
131
126
|
end
|
|
132
127
|
|
data/lib/orange_data/version.rb
CHANGED
data/lib/orange_data.rb
CHANGED
data/lib/orangedata.rb
CHANGED
data/orangedata.gemspec
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
|
|
2
|
-
lib = File.expand_path("
|
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
5
|
require "orange_data/version"
|
|
5
6
|
|
|
@@ -9,25 +10,27 @@ Gem::Specification.new do |spec|
|
|
|
9
10
|
spec.authors = ["Vasily Fedoseyev"]
|
|
10
11
|
spec.email = ["vasilyfedoseyev@gmail.com"]
|
|
11
12
|
|
|
12
|
-
spec.summary =
|
|
13
|
-
spec.description =
|
|
13
|
+
spec.summary = "Ruby client for orangedata.ru service"
|
|
14
|
+
spec.description = "Ruby client for orangedata.ru service"
|
|
14
15
|
spec.homepage = "https://github.com/Vasfed/orangedata"
|
|
15
16
|
spec.license = "MIT"
|
|
16
17
|
|
|
17
|
-
spec.files = Dir.chdir(File.expand_path('
|
|
18
|
-
`git ls-files -z`.split("\x0").reject
|
|
18
|
+
spec.files = Dir.chdir(File.expand_path('.', __dir__)) do
|
|
19
|
+
`git ls-files -z`.split("\x0").reject{|f| f.match(%r{^(test|spec|features)/}) }
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
# spec.bindir = "exe"
|
|
22
23
|
# spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
23
24
|
spec.require_paths = ["lib"]
|
|
24
25
|
|
|
26
|
+
# spec.required_ruby_version = ">=2.1"
|
|
27
|
+
|
|
25
28
|
spec.add_dependency "faraday", ">=0.15"
|
|
26
29
|
spec.add_dependency "faraday_middleware"
|
|
27
30
|
|
|
28
31
|
spec.add_development_dependency "bundler", "~> 1.16"
|
|
29
32
|
spec.add_development_dependency "rake", "~> 10.0"
|
|
30
33
|
spec.add_development_dependency "rspec"
|
|
31
|
-
spec.add_development_dependency "webmock"
|
|
32
34
|
spec.add_development_dependency "rubocop"
|
|
35
|
+
spec.add_development_dependency "webmock"
|
|
33
36
|
end
|
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.2
|
|
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-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -81,7 +81,7 @@ dependencies:
|
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: rubocop
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
87
|
- - ">="
|
|
@@ -95,7 +95,7 @@ dependencies:
|
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '0'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
98
|
+
name: webmock
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
101
|
- - ">="
|
|
@@ -117,6 +117,7 @@ extra_rdoc_files: []
|
|
|
117
117
|
files:
|
|
118
118
|
- ".gitignore"
|
|
119
119
|
- ".rspec"
|
|
120
|
+
- ".rubocop.yml"
|
|
120
121
|
- ".travis.yml"
|
|
121
122
|
- Gemfile
|
|
122
123
|
- Gemfile.lock
|