fiscalizer 0.0.12 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.rspec +2 -0
- data/Gemfile +0 -4
- data/LICENSE.txt +1 -1
- data/README.md +187 -171
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/doc/Tehnicka specifikacija za korisnike 1.4.pdf +0 -0
- data/fiscalizer.gemspec +14 -13
- data/lib/fiscalizer.rb +33 -4
- data/lib/fiscalizer/constants.rb +11 -0
- data/lib/fiscalizer/data_objects/echo.rb +10 -0
- data/lib/fiscalizer/data_objects/fee.rb +18 -0
- data/lib/fiscalizer/data_objects/invoice.rb +79 -0
- data/lib/fiscalizer/data_objects/office.rb +41 -0
- data/lib/fiscalizer/{tax.rb → data_objects/tax.rb} +3 -5
- data/lib/fiscalizer/deserializers/base.rb +58 -0
- data/lib/fiscalizer/deserializers/echo.rb +13 -0
- data/lib/fiscalizer/deserializers/invoice.rb +9 -0
- data/lib/fiscalizer/deserializers/office.rb +6 -0
- data/lib/fiscalizer/fiscalizer.rb +36 -152
- data/lib/fiscalizer/fiscalizers/base.rb +54 -0
- data/lib/fiscalizer/fiscalizers/echo.rb +13 -0
- data/lib/fiscalizer/fiscalizers/invoice.rb +24 -0
- data/lib/fiscalizer/fiscalizers/office.rb +15 -0
- data/lib/fiscalizer/serializers/base.rb +58 -0
- data/lib/fiscalizer/serializers/echo.rb +21 -0
- data/lib/fiscalizer/serializers/invoice.rb +92 -0
- data/lib/fiscalizer/serializers/office.rb +85 -0
- data/lib/fiscalizer/serializers/signature.rb +62 -0
- data/lib/fiscalizer/serializers/tax.rb +81 -0
- data/lib/fiscalizer/services/request_sender.rb +68 -0
- data/lib/fiscalizer/services/security_code_generator.rb +29 -0
- data/lib/fiscalizer/version.rb +1 -1
- data/spec/fiscalizer_spec.rb +119 -0
- data/spec/spec_helper.rb +9 -0
- metadata +67 -39
- data/doc/README.md +0 -3
- data/doc/Tehnicka_specifikacija_za_korisnike_1.2.pdf +0 -0
- data/example/README.md +0 -25
- data/example/echo_P12.rb +0 -13
- data/example/echo_public_and_private_keys.rb +0 -16
- data/example/invoice_fiscalization_passing_arguments.rb +0 -44
- data/example/invoice_fiscalization_passing_object.rb +0 -48
- data/example/office_fiscalization_passing_arguments.rb +0 -22
- data/example/office_fiscalization_passing_object.rb +0 -26
- data/lib/README.md +0 -0
- data/lib/fiscalizer/README.md +0 -9
- data/lib/fiscalizer/communication.rb +0 -305
- data/lib/fiscalizer/echo.rb +0 -11
- data/lib/fiscalizer/fee.rb +0 -20
- data/lib/fiscalizer/invoice.rb +0 -190
- data/lib/fiscalizer/office.rb +0 -66
- data/lib/fiscalizer/response.rb +0 -124
- data/test/README.md +0 -13
- data/test/test_echo.rb +0 -20
- data/test/test_fee +0 -64
- data/test/test_fiscalizer.rb +0 -222
- data/test/test_fiscalizer_communication.rb +0 -28
- data/test/test_invoice.rb +0 -11
- data/test/test_office.rb +0 -11
- data/test/test_tax.rb +0 -89
@@ -0,0 +1,68 @@
|
|
1
|
+
class Fiscalizer
|
2
|
+
class RequestSender
|
3
|
+
include Constants
|
4
|
+
|
5
|
+
def initialize(app_cert, password, timeout, demo, ca_cert_path)
|
6
|
+
@app_cert = app_cert
|
7
|
+
@password = password
|
8
|
+
@timeout = timeout
|
9
|
+
@demo = demo
|
10
|
+
@ca_cert_path = ca_cert_path
|
11
|
+
|
12
|
+
prepare_net_http
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :app_cert, :password, :timeout, :demo, :ca_cert_path
|
16
|
+
|
17
|
+
def send(message)
|
18
|
+
request.content_type = 'application/xml'
|
19
|
+
request.body = message
|
20
|
+
http.request(request)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def http
|
26
|
+
@http ||= Net::HTTP.new(uri.host, uri.port)
|
27
|
+
end
|
28
|
+
|
29
|
+
def uri
|
30
|
+
@uri ||= URI.parse(fiscalization_url)
|
31
|
+
end
|
32
|
+
|
33
|
+
def fiscalization_url
|
34
|
+
demo ? DEMO_URL : PROD_URL
|
35
|
+
end
|
36
|
+
|
37
|
+
def request
|
38
|
+
@request ||= Net::HTTP::Post.new(uri.request_uri)
|
39
|
+
end
|
40
|
+
|
41
|
+
def prepare_net_http
|
42
|
+
http.read_timeout = timeout
|
43
|
+
http.use_ssl = true
|
44
|
+
http.cert_store = OpenSSL::X509::Store.new
|
45
|
+
http.cert_store.set_default_paths
|
46
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
47
|
+
add_trusted_certificates
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_trusted_certificates
|
51
|
+
# u produkcijskom okruzenju, trusted CA certifikat se nalazi u
|
52
|
+
# istom fileu kao i public i private key
|
53
|
+
# taj file ima ekstenziju .p12 (npr. FISKAL_1.p12)
|
54
|
+
production_certificates.each do |certificate|
|
55
|
+
http.cert_store.add_cert(certificate)
|
56
|
+
end
|
57
|
+
|
58
|
+
# u testnom okruzenju, treba dodati 2 trusted CA certifikata
|
59
|
+
# ta 2 certifikata se nalaze u jednom .pem fileu (npr. fina_ca.pem)
|
60
|
+
http.cert_store.add_file(ca_cert_path) unless ca_cert_path.nil? || ca_cert_path == ''
|
61
|
+
end
|
62
|
+
|
63
|
+
def production_certificates
|
64
|
+
return [] if app_cert.ca_certs.nil?
|
65
|
+
app_cert.ca_certs
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Fiscalizer
|
2
|
+
class SecurityCodeGenerator
|
3
|
+
def initialize(invoice, private_key)
|
4
|
+
@invoice = invoice
|
5
|
+
@private_key = private_key
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :invoice, :private_key
|
9
|
+
|
10
|
+
def call
|
11
|
+
invoice.security_code = md5_digest
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def md5_digest
|
17
|
+
Digest::MD5.hexdigest(signed_code)
|
18
|
+
end
|
19
|
+
|
20
|
+
def signed_code
|
21
|
+
OpenSSL::PKey::RSA.new(private_key).sign(OpenSSL::Digest::SHA1.new, unsigned_code)
|
22
|
+
end
|
23
|
+
|
24
|
+
def unsigned_code
|
25
|
+
invoice.pin + invoice.time_issued_str(' ') + invoice.issued_number.to_s +
|
26
|
+
invoice.issued_office.to_s + invoice.issued_machine.to_s + invoice.summed_total_str
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/fiscalizer/version.rb
CHANGED
@@ -0,0 +1,119 @@
|
|
1
|
+
describe Fiscalizer do
|
2
|
+
let(:ca_cert_path) { ENV['FISCALIZER_CA_CERT_PATH'] }
|
3
|
+
let(:app_cert_path) { ENV['FISCALIZER_APP_CERT_PATH'] }
|
4
|
+
let(:password) { ENV['FISCALIZER_PASSWORD'] }
|
5
|
+
let(:pin) { ENV['FISCALIZER_PIN'] }
|
6
|
+
let(:timeout) { 3 }
|
7
|
+
|
8
|
+
let(:fiscalizer) do
|
9
|
+
Fiscalizer.new(
|
10
|
+
app_cert_path: app_cert_path,
|
11
|
+
password: password,
|
12
|
+
demo: true,
|
13
|
+
ca_cert_path: ca_cert_path,
|
14
|
+
timeout: timeout
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'echo' do
|
19
|
+
it 'should respond with a success' do
|
20
|
+
response = fiscalizer.echo('test')
|
21
|
+
expect(response.success?).to be(true)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'invoice' do
|
26
|
+
let(:invoice) do
|
27
|
+
Fiscalizer::Invoice.new(
|
28
|
+
uuid: SecureRandom.uuid,
|
29
|
+
time_sent: Time.now,
|
30
|
+
pin: pin,
|
31
|
+
in_vat_system: true,
|
32
|
+
time_issued: Time.now - 3600,
|
33
|
+
consistance_mark: 'P',
|
34
|
+
issued_number: '1',
|
35
|
+
issued_office: 'Pm2',
|
36
|
+
issued_machine: '3',
|
37
|
+
summed_total: 250.0,
|
38
|
+
payment_method: 'K',
|
39
|
+
operator_pin: '12345678900',
|
40
|
+
subsequent_delivery: false
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
before do
|
45
|
+
tax = Fiscalizer::Tax.new(base: 100.0, rate: 25.0, name: 'PDV')
|
46
|
+
invoice.tax_vat << tax
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'valid' do
|
50
|
+
it 'should return JIR' do
|
51
|
+
response = fiscalizer.fiscalize_invoice(invoice)
|
52
|
+
|
53
|
+
expect(response.errors?).to be(false)
|
54
|
+
expect(invoice.security_code).not_to be(nil)
|
55
|
+
expect(response.unique_identifier).not_to be(nil)
|
56
|
+
expect(response.uuid).not_to be(nil)
|
57
|
+
expect(response.processed_at).not_to be(nil)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'invalid' do
|
62
|
+
let(:pin) { '00000000000' }
|
63
|
+
|
64
|
+
it 'should return error' do
|
65
|
+
response = fiscalizer.fiscalize_invoice(invoice)
|
66
|
+
expect(response.errors?).to be(true)
|
67
|
+
expect(invoice.security_code).not_to be(nil)
|
68
|
+
expect(response.unique_identifier).to be(nil)
|
69
|
+
expect(response.errors.first[:code]).to eq('s005')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'timeout error' do
|
74
|
+
let(:timeout) { 0 }
|
75
|
+
|
76
|
+
it 'should raise read timeout error' do
|
77
|
+
expect { fiscalizer.fiscalize_invoice(invoice) }.to raise_error(Net::ReadTimeout)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'office' do
|
83
|
+
let(:office) do
|
84
|
+
Fiscalizer::Office.new(
|
85
|
+
uuid: SecureRandom.uuid,
|
86
|
+
time_sent: Time.now,
|
87
|
+
pin: pin,
|
88
|
+
office_label: 'Poslovnica1',
|
89
|
+
adress_street_name: 'Adresa',
|
90
|
+
adress_house_num: '42',
|
91
|
+
adress_house_num_addendum: 'AD',
|
92
|
+
adress_post_num: '10000',
|
93
|
+
adress_settlement: 'Block 25-C',
|
94
|
+
adress_township: 'Zagreb',
|
95
|
+
office_time: 'Pon-Pet: 8:00-16:00',
|
96
|
+
take_effect_date: Time.now + 3600 * 24 * 7
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'valid' do
|
101
|
+
it 'should fiscalize office' do
|
102
|
+
response = fiscalizer.fiscalize_office(office)
|
103
|
+
expect(response.errors?).to be(false)
|
104
|
+
expect(response.uuid).not_to be(nil)
|
105
|
+
expect(response.processed_at).not_to be(nil)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'invalid' do
|
110
|
+
let(:pin) { '00000000000' }
|
111
|
+
|
112
|
+
it 'should return error' do
|
113
|
+
response = fiscalizer.fiscalize_office(office)
|
114
|
+
expect(response.errors?).to be(true)
|
115
|
+
expect(response.errors.first[:code]).to eq('s005')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'fiscalizer'
|
2
|
+
require 'pathname'
|
3
|
+
require 'pry'
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
7
|
+
|
8
|
+
root_path = Pathname.new(File.expand_path('../', File.dirname(__FILE__)))
|
9
|
+
Dir[root_path.join('spec/support/**/*.rb')].each { |f| require f }
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fiscalizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stanko Krtalić Rusendić
|
8
|
+
- Vladimir Rosančić
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2017-01-19 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: nokogiri
|
@@ -66,50 +67,83 @@ dependencies:
|
|
66
67
|
- - "~>"
|
67
68
|
- !ruby/object:Gem::Version
|
68
69
|
version: '10.3'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: pry
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rspec
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
69
98
|
description: Automatic fiscalization
|
70
99
|
email:
|
71
|
-
- stanko.krtalic
|
72
|
-
|
100
|
+
- stanko.krtalic@gmail.com
|
101
|
+
- vladimir.rosancic@infinum.hr
|
102
|
+
executables:
|
103
|
+
- console
|
104
|
+
- setup
|
73
105
|
extensions: []
|
74
106
|
extra_rdoc_files: []
|
75
107
|
files:
|
76
108
|
- ".gitignore"
|
109
|
+
- ".rspec"
|
77
110
|
- Gemfile
|
78
111
|
- LICENSE.txt
|
79
112
|
- README.md
|
80
113
|
- Rakefile
|
114
|
+
- bin/console
|
115
|
+
- bin/setup
|
81
116
|
- doc/FiskalizacijaSchema.xsd
|
82
|
-
- doc/
|
83
|
-
- doc/Tehnicka_specifikacija_za_korisnike_1.2.pdf
|
117
|
+
- doc/Tehnicka specifikacija za korisnike 1.4.pdf
|
84
118
|
- doc/fiskalizacija_faq_v2.1_objava.pdf
|
85
|
-
- example/README.md
|
86
|
-
- example/echo_P12.rb
|
87
|
-
- example/echo_public_and_private_keys.rb
|
88
|
-
- example/invoice_fiscalization_passing_arguments.rb
|
89
|
-
- example/invoice_fiscalization_passing_object.rb
|
90
|
-
- example/office_fiscalization_passing_arguments.rb
|
91
|
-
- example/office_fiscalization_passing_object.rb
|
92
119
|
- fiscalizer.gemspec
|
93
|
-
- lib/README.md
|
94
120
|
- lib/fiscalizer.rb
|
95
|
-
- lib/fiscalizer/
|
96
|
-
- lib/fiscalizer/
|
97
|
-
- lib/fiscalizer/
|
98
|
-
- lib/fiscalizer/
|
121
|
+
- lib/fiscalizer/constants.rb
|
122
|
+
- lib/fiscalizer/data_objects/echo.rb
|
123
|
+
- lib/fiscalizer/data_objects/fee.rb
|
124
|
+
- lib/fiscalizer/data_objects/invoice.rb
|
125
|
+
- lib/fiscalizer/data_objects/office.rb
|
126
|
+
- lib/fiscalizer/data_objects/tax.rb
|
127
|
+
- lib/fiscalizer/deserializers/base.rb
|
128
|
+
- lib/fiscalizer/deserializers/echo.rb
|
129
|
+
- lib/fiscalizer/deserializers/invoice.rb
|
130
|
+
- lib/fiscalizer/deserializers/office.rb
|
99
131
|
- lib/fiscalizer/fiscalizer.rb
|
100
|
-
- lib/fiscalizer/
|
101
|
-
- lib/fiscalizer/
|
102
|
-
- lib/fiscalizer/
|
103
|
-
- lib/fiscalizer/
|
132
|
+
- lib/fiscalizer/fiscalizers/base.rb
|
133
|
+
- lib/fiscalizer/fiscalizers/echo.rb
|
134
|
+
- lib/fiscalizer/fiscalizers/invoice.rb
|
135
|
+
- lib/fiscalizer/fiscalizers/office.rb
|
136
|
+
- lib/fiscalizer/serializers/base.rb
|
137
|
+
- lib/fiscalizer/serializers/echo.rb
|
138
|
+
- lib/fiscalizer/serializers/invoice.rb
|
139
|
+
- lib/fiscalizer/serializers/office.rb
|
140
|
+
- lib/fiscalizer/serializers/signature.rb
|
141
|
+
- lib/fiscalizer/serializers/tax.rb
|
142
|
+
- lib/fiscalizer/services/request_sender.rb
|
143
|
+
- lib/fiscalizer/services/security_code_generator.rb
|
104
144
|
- lib/fiscalizer/version.rb
|
105
|
-
-
|
106
|
-
-
|
107
|
-
- test/test_fee
|
108
|
-
- test/test_fiscalizer.rb
|
109
|
-
- test/test_fiscalizer_communication.rb
|
110
|
-
- test/test_invoice.rb
|
111
|
-
- test/test_office.rb
|
112
|
-
- test/test_tax.rb
|
145
|
+
- spec/fiscalizer_spec.rb
|
146
|
+
- spec/spec_helper.rb
|
113
147
|
homepage: https://github.com/infinum/fiscalizer
|
114
148
|
licenses:
|
115
149
|
- MIT
|
@@ -130,17 +164,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
164
|
version: '0'
|
131
165
|
requirements: []
|
132
166
|
rubyforge_project:
|
133
|
-
rubygems_version: 2.5.1
|
167
|
+
rubygems_version: 2.4.5.1
|
134
168
|
signing_key:
|
135
169
|
specification_version: 4
|
136
170
|
summary: A gem that automatically handles fiscalization
|
137
171
|
test_files:
|
138
|
-
-
|
139
|
-
-
|
140
|
-
- test/test_fee
|
141
|
-
- test/test_fiscalizer.rb
|
142
|
-
- test/test_fiscalizer_communication.rb
|
143
|
-
- test/test_invoice.rb
|
144
|
-
- test/test_office.rb
|
145
|
-
- test/test_tax.rb
|
172
|
+
- spec/fiscalizer_spec.rb
|
173
|
+
- spec/spec_helper.rb
|
146
174
|
has_rdoc:
|
data/doc/README.md
DELETED
Binary file
|
data/example/README.md
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
# Examples
|
2
|
-
|
3
|
-
### echo_12
|
4
|
-
|
5
|
-
Demonstrates how to create a Fiscalizer object with a P12 certificate. How to make an echo request and check for, and print, errors.
|
6
|
-
|
7
|
-
### echo_public_and_private_keys
|
8
|
-
|
9
|
-
Demonstrates how to create a Fiscalizer object from public and private keys and a certificate.
|
10
|
-
|
11
|
-
### invoice_fiscalization_passing_object
|
12
|
-
|
13
|
-
Demonstrates how to ceate an Invoice object and fiscalize it. It also demonstrates how to create tax and fee objects and add them to the invoice object.
|
14
|
-
|
15
|
-
### invoice_fiscalization_passing_arguments
|
16
|
-
|
17
|
-
Demonstrates how to create an invoice object and fiscalize ti by passing argumentst to the fiscalize_invoice method.
|
18
|
-
|
19
|
-
### fiscalize_office
|
20
|
-
|
21
|
-
Demonstrates how to create and fiscalize an office object.
|
22
|
-
|
23
|
-
### fiscalize_office
|
24
|
-
|
25
|
-
Demonstrates how to create and fiscalize an office space, by passing arguments.
|
data/example/echo_P12.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
fiscal = Fiscalizer.new certificate_p12_path: "/path/to/FISKAL 1.p12",
|
2
|
-
password: "12345678"
|
3
|
-
echo_response = fiscal.echo text: "It's mearly a flesh wound!"
|
4
|
-
|
5
|
-
if echo_response.errors?
|
6
|
-
puts "There were some nasty errors!"
|
7
|
-
echo_response.errors.each do |error_code, error_message|
|
8
|
-
puts " " + error_code + " : " + error_message
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
puts "The server returned: " + echo_response.response
|
13
|
-
puts "The echo request was successful! Great success!" if echo_response.echo?
|
@@ -1,16 +0,0 @@
|
|
1
|
-
fiscal = Fiscalizer.new url: "https://cistest.apis-it.hr:8449/FiskalizacijaServiceTest",
|
2
|
-
key_public_path: "/path/to/fiskal1.cert",
|
3
|
-
key_private_path: "/path/to/privateKey.key",
|
4
|
-
certificate_path: "/path/to/democacert.pem",
|
5
|
-
certificate_issued_by: "OU=DEMO,O=FINA,C=HR"
|
6
|
-
echo_response = fiscal.echo text: "It's mearly a flesh wound!"
|
7
|
-
|
8
|
-
if echo_response.errors?
|
9
|
-
puts "There were some nasty errors!"
|
10
|
-
echo_response.errors.each do |error_code, error_message|
|
11
|
-
puts " " + error_code + " : " + error_message
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
puts "The server returned: " + echo_response.response
|
16
|
-
puts "The echo request was successful! Great success!" if echo_response.echo?
|