afipws 0.2.0 → 1.0.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/Gemfile.lock +75 -25
- data/Guardfile +0 -16
- data/afipws.gemspec +6 -5
- data/lib/afipws.rb +0 -5
- data/lib/afipws/client.rb +5 -30
- data/lib/afipws/core_ext/hash.rb +0 -12
- data/lib/afipws/version.rb +1 -1
- data/lib/afipws/wsaa.rb +3 -3
- data/lib/afipws/wsfe.rb +2 -1
- data/spec/afipws/core_ext/hash_spec.rb +1 -22
- data/spec/afipws/type_conversions_spec.rb +1 -1
- data/spec/afipws/wsaa_spec.rb +5 -6
- data/spec/afipws/wsfe_spec.rb +147 -147
- data/spec/manual/test.rb +6 -12
- data/spec/spec_helper.rb +16 -3
- data/spec/support/matchers.rb +6 -32
- data/spec/support/savon_extensions.rb +39 -0
- metadata +43 -27
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f0430f1994cf2d6f6afe098bda447441df15f7bb
|
|
4
|
+
data.tar.gz: 519d1e3e5ea15497d131905c9b1e37e2959b26b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3fa823ccd4f74a535dce9893b9df3277a82f944789e8c75be937c4fc277afc32fdc6e9136359b13fab08c839b063a0bc71b34a89053eb448c3bc654babc5f756
|
|
7
|
+
data.tar.gz: 9a40c8d4855d4b0d5eb3ea0112c38f282213ecf727f1a3963026670fcd3f76f2fd433a535140eb7ae0a9d53b7011e20fad172e812e83095195c630608d3969f4
|
data/Gemfile.lock
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
afipws (0.
|
|
4
|
+
afipws (1.0.0)
|
|
5
5
|
activesupport
|
|
6
6
|
builder
|
|
7
7
|
httpclient
|
|
8
|
-
httpi (>= 2.4.2)
|
|
9
8
|
i18n
|
|
10
9
|
nokogiri
|
|
11
|
-
savon
|
|
10
|
+
savon (~> 2.11.0)
|
|
12
11
|
|
|
13
12
|
GEM
|
|
14
13
|
remote: http://rubygems.org/
|
|
@@ -18,57 +17,108 @@ GEM
|
|
|
18
17
|
i18n (~> 0.7)
|
|
19
18
|
minitest (~> 5.1)
|
|
20
19
|
tzinfo (~> 1.1)
|
|
21
|
-
|
|
20
|
+
akami (1.3.1)
|
|
21
|
+
gyoku (>= 0.4.0)
|
|
22
|
+
nokogiri
|
|
23
|
+
builder (3.2.2)
|
|
24
|
+
byebug (1.1.1)
|
|
25
|
+
columnize (~> 0.3.6)
|
|
26
|
+
debugger-linecache (~> 1.2.0)
|
|
27
|
+
coderay (1.1.1)
|
|
28
|
+
columnize (0.3.6)
|
|
22
29
|
concurrent-ruby (1.0.2)
|
|
23
|
-
|
|
24
|
-
diff-lcs (1.
|
|
25
|
-
|
|
30
|
+
debugger-linecache (1.2.0)
|
|
31
|
+
diff-lcs (1.2.5)
|
|
32
|
+
ffi (1.9.14)
|
|
33
|
+
formatador (0.2.5)
|
|
34
|
+
guard (2.14.0)
|
|
35
|
+
formatador (>= 0.2.4)
|
|
36
|
+
listen (>= 2.7, < 4.0)
|
|
37
|
+
lumberjack (~> 1.0)
|
|
38
|
+
nenv (~> 0.1)
|
|
39
|
+
notiffany (~> 0.0)
|
|
40
|
+
pry (>= 0.9.12)
|
|
41
|
+
shellany (~> 0.0)
|
|
42
|
+
thor (>= 0.18.1)
|
|
43
|
+
guard-rspec (4.3.1)
|
|
44
|
+
guard (~> 2.1)
|
|
45
|
+
rspec (>= 2.14, < 4.0)
|
|
46
|
+
gyoku (1.3.1)
|
|
26
47
|
builder (>= 2.1.2)
|
|
27
48
|
httpclient (2.8.2.4)
|
|
28
49
|
httpi (2.4.2)
|
|
29
50
|
rack
|
|
30
51
|
socksify
|
|
31
52
|
i18n (0.7.0)
|
|
53
|
+
listen (3.1.5)
|
|
54
|
+
rb-fsevent (~> 0.9, >= 0.9.4)
|
|
55
|
+
rb-inotify (~> 0.9, >= 0.9.7)
|
|
56
|
+
ruby_dep (~> 1.2)
|
|
57
|
+
lumberjack (1.0.10)
|
|
58
|
+
method_source (0.8.2)
|
|
32
59
|
mini_portile2 (2.1.0)
|
|
33
60
|
minitest (5.9.1)
|
|
34
61
|
mocha (0.9.10)
|
|
35
62
|
rake
|
|
63
|
+
nenv (0.3.0)
|
|
36
64
|
nokogiri (1.6.8)
|
|
37
65
|
mini_portile2 (~> 2.1.0)
|
|
38
66
|
pkg-config (~> 1.1.7)
|
|
67
|
+
nori (2.6.0)
|
|
68
|
+
notiffany (0.1.1)
|
|
69
|
+
nenv (~> 0.1)
|
|
70
|
+
shellany (~> 0.0)
|
|
39
71
|
pkg-config (1.1.7)
|
|
72
|
+
pry (0.10.4)
|
|
73
|
+
coderay (~> 1.1.0)
|
|
74
|
+
method_source (~> 0.8.1)
|
|
75
|
+
slop (~> 3.4)
|
|
76
|
+
pry-byebug (1.0.1)
|
|
77
|
+
byebug (~> 1.1.1)
|
|
78
|
+
pry (>= 0.9.10)
|
|
40
79
|
rack (2.0.1)
|
|
41
80
|
rake (10.4.2)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
rspec-
|
|
50
|
-
|
|
81
|
+
rb-fsevent (0.9.7)
|
|
82
|
+
rb-inotify (0.9.7)
|
|
83
|
+
ffi (>= 0.5.0)
|
|
84
|
+
rspec (2.14.1)
|
|
85
|
+
rspec-core (~> 2.14.0)
|
|
86
|
+
rspec-expectations (~> 2.14.0)
|
|
87
|
+
rspec-mocks (~> 2.14.0)
|
|
88
|
+
rspec-core (2.14.8)
|
|
89
|
+
rspec-expectations (2.14.5)
|
|
90
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
|
91
|
+
rspec-mocks (2.14.6)
|
|
92
|
+
ruby_dep (1.4.0)
|
|
93
|
+
savon (2.11.1)
|
|
94
|
+
akami (~> 1.2)
|
|
51
95
|
builder (>= 2.1.2)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
96
|
+
gyoku (~> 1.2)
|
|
97
|
+
httpi (~> 2.3)
|
|
98
|
+
nokogiri (>= 1.4.0)
|
|
99
|
+
nori (~> 2.4)
|
|
100
|
+
wasabi (~> 3.4)
|
|
101
|
+
shellany (0.0.1)
|
|
102
|
+
slop (3.6.0)
|
|
59
103
|
socksify (1.7.0)
|
|
104
|
+
thor (0.19.1)
|
|
60
105
|
thread_safe (0.3.5)
|
|
61
106
|
tzinfo (1.2.2)
|
|
62
107
|
thread_safe (~> 0.1)
|
|
108
|
+
wasabi (3.5.0)
|
|
109
|
+
httpi (~> 2.0)
|
|
110
|
+
nokogiri (>= 1.4.2)
|
|
63
111
|
|
|
64
112
|
PLATFORMS
|
|
65
113
|
ruby
|
|
66
114
|
|
|
67
115
|
DEPENDENCIES
|
|
68
116
|
afipws!
|
|
117
|
+
guard-rspec (~> 4.3.1)
|
|
118
|
+
mocha (~> 0.9.10)
|
|
119
|
+
pry-byebug
|
|
69
120
|
rake (~> 10.4.2)
|
|
70
|
-
rspec
|
|
71
|
-
savon_spec
|
|
121
|
+
rspec (~> 2.14.1)
|
|
72
122
|
|
|
73
123
|
BUNDLED WITH
|
|
74
124
|
1.12.3
|
data/Guardfile
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
# A sample Guardfile
|
|
2
|
-
# More info at https://github.com/guard/guard#readme
|
|
3
|
-
|
|
4
|
-
## Uncomment and set this to only include directories you want to watch
|
|
5
|
-
# directories %w(app lib config test spec features) \
|
|
6
|
-
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
|
7
|
-
|
|
8
|
-
## Note: if you are using the `directories` clause above and you are not
|
|
9
|
-
## watching the project directory ('.'), then you will want to move
|
|
10
|
-
## the Guardfile to a watched dir and symlink it back, e.g.
|
|
11
|
-
#
|
|
12
|
-
# $ mkdir config
|
|
13
|
-
# $ mv Guardfile config/
|
|
14
|
-
# $ ln -s config/Guardfile .
|
|
15
|
-
#
|
|
16
|
-
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
|
17
1
|
guard :rspec, cmd: 'rspec' do
|
|
18
2
|
watch(%r{^spec/.+_spec\.rb$})
|
|
19
3
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
data/afipws.gemspec
CHANGED
|
@@ -18,14 +18,15 @@ Gem::Specification.new do |s|
|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
19
|
s.require_paths = ["lib"]
|
|
20
20
|
|
|
21
|
-
s.add_development_dependency
|
|
22
|
-
s.add_development_dependency
|
|
23
|
-
s.add_development_dependency
|
|
21
|
+
s.add_development_dependency 'rspec', '~> 2.14.1'
|
|
22
|
+
s.add_development_dependency 'rake', '~> 10.4.2'
|
|
23
|
+
s.add_development_dependency 'mocha', '~> 0.9.10'
|
|
24
|
+
s.add_development_dependency 'guard-rspec', '~> 4.3.1'
|
|
25
|
+
s.add_development_dependency 'pry-byebug'
|
|
24
26
|
s.add_dependency "builder"
|
|
25
|
-
s.add_dependency "savon"
|
|
27
|
+
s.add_dependency "savon", '~> 2.11.0'
|
|
26
28
|
s.add_dependency "nokogiri"
|
|
27
29
|
s.add_dependency "activesupport"
|
|
28
30
|
s.add_dependency "i18n"
|
|
29
31
|
s.add_dependency "httpclient"
|
|
30
|
-
s.add_dependency "httpi", '>= 2.4.2'
|
|
31
32
|
end
|
data/lib/afipws.rb
CHANGED
data/lib/afipws/client.rb
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
module Afipws
|
|
2
2
|
class Client
|
|
3
|
-
def initialize
|
|
4
|
-
@client = Savon
|
|
5
|
-
wsdl.document = wsdl_url
|
|
6
|
-
http.auth.ssl.verify_mode = :none if env == :development # Esto está porque el certificado del WSAA había vencido durante las pruebas
|
|
7
|
-
http.auth.ssl.ssl_version = :SSLv3 if env == :development || Date.today >= Date.new(2016,11,1) # Esto es porque la afip cambió el algoritmo de cifrado de los certificados y sin esto no conectaba al WSFE. En el entorno de homologación ya está realizado el cambio pero en production recién el 1/11/2016.
|
|
8
|
-
end
|
|
3
|
+
def initialize savon_options
|
|
4
|
+
@client = Savon.client savon_options.reverse_merge(soap_version: 2)
|
|
9
5
|
end
|
|
10
6
|
|
|
11
7
|
def request action, body = nil
|
|
@@ -18,36 +14,15 @@ module Afipws
|
|
|
18
14
|
end
|
|
19
15
|
|
|
20
16
|
def raw_request action, body = nil
|
|
21
|
-
@client.
|
|
17
|
+
@client.call action, message: body
|
|
22
18
|
end
|
|
23
19
|
|
|
24
|
-
def
|
|
25
|
-
@client.
|
|
20
|
+
def operations
|
|
21
|
+
@client.operations
|
|
26
22
|
end
|
|
27
23
|
|
|
28
24
|
def method_missing method_sym, *args
|
|
29
25
|
request method_sym, *args
|
|
30
26
|
end
|
|
31
|
-
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
def add_ns_to_keys body
|
|
35
|
-
case body
|
|
36
|
-
when Hash
|
|
37
|
-
Hash[body.map { |k, v| ["#{namespace}:#{camelize(k)}", add_ns_to_keys(v)] }]
|
|
38
|
-
when Array
|
|
39
|
-
body.map { |x| add_ns_to_keys x }
|
|
40
|
-
else
|
|
41
|
-
body
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def namespace
|
|
46
|
-
:wsdl
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def camelize k
|
|
50
|
-
k.is_a?(String) ? k : k.to_s.camelize
|
|
51
|
-
end
|
|
52
27
|
end
|
|
53
28
|
end
|
data/lib/afipws/core_ext/hash.rb
CHANGED
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
module Afipws
|
|
2
2
|
module CoreExt
|
|
3
3
|
module Hash
|
|
4
|
-
def fetch_path path
|
|
5
|
-
path.split('/').drop(1).inject(self) do |hash, key|
|
|
6
|
-
if scan = key.scan(/\[[\d+]\]/).first
|
|
7
|
-
key.sub! scan, ''
|
|
8
|
-
idx = scan.scan(/\d+/).first.to_i
|
|
9
|
-
hash.respond_to?(:has_key?) && hash.has_key?(key) ? hash[key][idx] : break
|
|
10
|
-
else
|
|
11
|
-
hash.respond_to?(:has_key?) && hash.has_key?(key) ? hash[key] : break
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
4
|
def select_keys *keys
|
|
17
5
|
select { |k, _| keys.include? k }
|
|
18
6
|
end
|
data/lib/afipws/version.rb
CHANGED
data/lib/afipws/wsaa.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Afipws
|
|
|
15
15
|
@service = options[:service] || 'wsfe'
|
|
16
16
|
@ttl = options[:ttl] || 2400
|
|
17
17
|
@cuit = options[:cuit]
|
|
18
|
-
@client = Client.new WSDL[@env]
|
|
18
|
+
@client = Client.new Hash(options[:savon]).reverse_merge(wsdl: WSDL[@env])
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def generar_tra service, ttl
|
|
@@ -47,12 +47,12 @@ module Afipws
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def login
|
|
50
|
-
response = @client.raw_request :login_cms,
|
|
50
|
+
response = @client.raw_request :login_cms, in0: tra(@key, @cert, @service, @ttl)
|
|
51
51
|
ta = Nokogiri::XML(Nokogiri::XML(response.to_xml).text)
|
|
52
52
|
{ token: ta.css('token').text, sign: ta.css('sign').text,
|
|
53
53
|
generation_time: from_xsd_datetime(ta.css('generationTime').text),
|
|
54
54
|
expiration_time: from_xsd_datetime(ta.css('expirationTime').text) }
|
|
55
|
-
rescue Savon::
|
|
55
|
+
rescue Savon::SOAPFault => f
|
|
56
56
|
raise WSError, f.message
|
|
57
57
|
end
|
|
58
58
|
|
data/lib/afipws/wsfe.rb
CHANGED
|
@@ -15,7 +15,8 @@ module Afipws
|
|
|
15
15
|
def initialize options = {}
|
|
16
16
|
@env = (options[:env] || :test).to_sym
|
|
17
17
|
@wsaa = options[:wsaa] || WSAA.new(options.merge(service: 'wsfe'))
|
|
18
|
-
|
|
18
|
+
ssl_version = env == :development || Date.today >= Date.new(2016,11,1) ? :SSLv3 : :TLSv1
|
|
19
|
+
@client = Client.new Hash(options[:savon]).reverse_merge(wsdl: WSDL[@env], ssl_version: ssl_version, convert_request_keys_to: :camelcase)
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def dummy
|
|
@@ -1,27 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
1
|
+
require 'spec_helper'
|
|
3
2
|
|
|
4
3
|
describe Hash do
|
|
5
|
-
context "fetch_path" do
|
|
6
|
-
it "deberia aceptar un path como /../.. y retornar el value" do
|
|
7
|
-
hash = { '1' => 2, '3' => { '4' => '5', '6' => { '7' => '8' } } }
|
|
8
|
-
hash.fetch_path('/1').should == 2
|
|
9
|
-
hash.fetch_path('/1/2').should == nil
|
|
10
|
-
hash.fetch_path('/2').should == nil
|
|
11
|
-
hash.fetch_path('/3/4').should == '5'
|
|
12
|
-
hash.fetch_path('/3/6').should == { '7' => '8' }
|
|
13
|
-
hash.fetch_path('/3/6/7').should == '8'
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it "debería permitir acceder a values tipo array con subindice" do
|
|
17
|
-
hash = { '1' => [{ '2' => 3 }, { '4' => 5 }] }
|
|
18
|
-
hash.fetch_path('/1[0]/2').should == 3
|
|
19
|
-
hash.fetch_path('/1[1]/4').should == 5
|
|
20
|
-
hash.fetch_path('/1[0]').should == { '2' => 3 }
|
|
21
|
-
hash.fetch_path('/1[2]').should == nil
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
4
|
context "select_keys" do
|
|
26
5
|
it "debería tomar los values de las keys indicadas" do
|
|
27
6
|
hash = Hash[1, 2, 3, 4]
|
data/spec/afipws/wsaa_spec.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
1
|
+
require 'spec_helper'
|
|
3
2
|
|
|
4
3
|
describe Afipws::WSAA do
|
|
5
4
|
context "generación documento tra" do
|
|
@@ -30,9 +29,9 @@ describe Afipws::WSAA do
|
|
|
30
29
|
|
|
31
30
|
context "login" do
|
|
32
31
|
it "debería mandar el TRA al WS y obtener el TA" do
|
|
33
|
-
ws = Afipws::WSAA.new :
|
|
32
|
+
ws = Afipws::WSAA.new key: 'key', cert: 'cert'
|
|
34
33
|
ws.expects(:tra).with('key', 'cert', 'wsfe', 2400).returns('tra')
|
|
35
|
-
savon.expects(
|
|
34
|
+
savon.expects(:login_cms).with(message: {in0: 'tra'}).returns(fixture('login_cms/success'))
|
|
36
35
|
ta = ws.login
|
|
37
36
|
ta[:token].should == 'PD94='
|
|
38
37
|
ta[:sign].should == 'i9xDN='
|
|
@@ -42,8 +41,8 @@ describe Afipws::WSAA do
|
|
|
42
41
|
|
|
43
42
|
it "debería encapsular SOAP Faults" do
|
|
44
43
|
subject.stubs(:tra).returns('')
|
|
45
|
-
savon.
|
|
46
|
-
|
|
44
|
+
savon.expects(:login_cms).with(message: :any).returns(fixture('login_cms/fault'))
|
|
45
|
+
lambda { subject.login }.should raise_error Afipws::WSError, /CMS no es valido/
|
|
47
46
|
end
|
|
48
47
|
end
|
|
49
48
|
|
data/spec/afipws/wsfe_spec.rb
CHANGED
|
@@ -1,223 +1,222 @@
|
|
|
1
|
-
|
|
2
|
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
1
|
+
require 'spec_helper'
|
|
3
2
|
|
|
4
3
|
describe Afipws::WSFE do
|
|
5
|
-
let :
|
|
6
|
-
|
|
7
|
-
wsaa.stubs :login => { :token => 't', :sign => 's', :expiration_time => 12.hours.from_now }
|
|
8
|
-
Afipws::WSFE.new :cuit => '1', :wsaa => wsaa
|
|
9
|
-
end
|
|
4
|
+
let(:auth) { {auth: {token: 't', sign: 's', expiration_time: 12.hours.from_now}} }
|
|
5
|
+
let(:ws) { Afipws::WSFE.new cuit: '1', wsaa: Afipws::WSAA.new.tap { |wsaa| wsaa.stubs auth: auth } }
|
|
10
6
|
|
|
11
7
|
context "Métodos de negocio" do
|
|
12
8
|
it "dummy" do
|
|
13
|
-
savon.expects(
|
|
14
|
-
ws.dummy.should == { :
|
|
9
|
+
savon.expects(:fe_dummy).returns(fixture('fe_dummy/success'))
|
|
10
|
+
ws.dummy.should == { app_server: "OK", db_server: "OK", auth_server: "OK" }
|
|
15
11
|
end
|
|
16
12
|
|
|
17
13
|
it "tipos_comprobantes" do
|
|
18
|
-
savon.expects(
|
|
14
|
+
savon.expects(:fe_param_get_tipos_cbte).with(message: auth).returns(fixture('fe_param_get_tipos_cbte/success'))
|
|
19
15
|
ws.tipos_comprobantes.should == [
|
|
20
|
-
{ :
|
|
21
|
-
{ :
|
|
16
|
+
{ id: 1, desc: "Factura A", fch_desde: Date.new(2010,9,17), fch_hasta: nil },
|
|
17
|
+
{ id: 2, desc: "Nota de Débito A", fch_desde: Date.new(2010,9,18), fch_hasta: Date.new(2011,9,18) }]
|
|
22
18
|
end
|
|
23
19
|
|
|
24
20
|
it "tipos_documentos" do
|
|
25
|
-
savon.expects(
|
|
26
|
-
ws.tipos_documentos.should == [{ :
|
|
21
|
+
savon.expects(:fe_param_get_tipos_doc).with(message: auth).returns(fixture('fe_param_get_tipos_doc/success'))
|
|
22
|
+
ws.tipos_documentos.should == [{ id: 80, desc: "CUIT", fch_desde: Date.new(2008,7,25), fch_hasta: nil }]
|
|
27
23
|
end
|
|
28
24
|
|
|
29
25
|
it "tipos_monedas" do
|
|
30
|
-
savon.expects(
|
|
26
|
+
savon.expects(:fe_param_get_tipos_monedas).with(message: auth).returns(fixture('fe_param_get_tipos_monedas/success'))
|
|
31
27
|
ws.tipos_monedas.should == [
|
|
32
|
-
{ :
|
|
33
|
-
{ :
|
|
28
|
+
{ id: 'PES', desc: "Pesos Argentinos", fch_desde: Date.new(2009,4,3), fch_hasta: nil },
|
|
29
|
+
{ id: '002', desc: "Dólar Libre EEUU", fch_desde: Date.new(2009,4,16), fch_hasta: nil }]
|
|
34
30
|
end
|
|
35
31
|
|
|
36
32
|
it "tipos_iva" do
|
|
37
|
-
savon.expects(
|
|
38
|
-
ws.tipos_iva.should == [{ :
|
|
33
|
+
savon.expects(:fe_param_get_tipos_iva).with(message: auth).returns(fixture('fe_param_get_tipos_iva/success'))
|
|
34
|
+
ws.tipos_iva.should == [{ id: 5, desc: "21%", fch_desde: Date.new(2009,2,20), fch_hasta: nil }]
|
|
39
35
|
end
|
|
40
36
|
|
|
41
37
|
it "tipos_tributos" do
|
|
42
|
-
savon.expects(
|
|
43
|
-
ws.tipos_tributos.should == [{ :
|
|
38
|
+
savon.expects(:fe_param_get_tipos_tributos).with(message: auth).returns(fixture('fe_param_get_tipos_tributos/success'))
|
|
39
|
+
ws.tipos_tributos.should == [{ id: 2, desc: "Impuestos provinciales", fch_desde: Date.new(2010,9,17), fch_hasta: nil }]
|
|
44
40
|
end
|
|
45
41
|
|
|
46
42
|
it "puntos_venta" do
|
|
47
|
-
savon.expects(
|
|
43
|
+
savon.expects(:fe_param_get_ptos_venta).with(message: auth).returns(fixture('fe_param_get_ptos_venta/success'))
|
|
48
44
|
ws.puntos_venta.should == [
|
|
49
|
-
{ :
|
|
50
|
-
{ :
|
|
51
|
-
]
|
|
45
|
+
{ nro: 1, emision_tipo: "CAE", bloqueado: false, fch_baja: nil },
|
|
46
|
+
{ nro: 2, emision_tipo: "CAEA", bloqueado: true, fch_baja: Date.new(2011,1,31) }]
|
|
52
47
|
end
|
|
53
48
|
|
|
54
49
|
context "cotizacion" do
|
|
55
50
|
it "cuando la moneda solicitada existe" do
|
|
56
|
-
savon.expects(
|
|
51
|
+
savon.expects(:fe_param_get_cotizacion).with(message: auth.merge(mon_id: 'DOL')).returns(fixture('fe_param_get_cotizacion/dolar'))
|
|
57
52
|
ws.cotizacion('DOL').should == 3.976
|
|
58
53
|
end
|
|
59
54
|
|
|
60
55
|
it "cuando la moneda no existe" do
|
|
61
|
-
savon.expects(
|
|
62
|
-
|
|
56
|
+
savon.expects(:fe_param_get_cotizacion).with(message: auth.merge(mon_id: 'PES')).returns(fixture('fe_param_get_cotizacion/inexistente'))
|
|
57
|
+
lambda { ws.cotizacion('PES') }.should raise_error Afipws::WSError, /602: Sin Resultados/
|
|
63
58
|
end
|
|
64
59
|
end
|
|
65
60
|
|
|
66
61
|
it "cant_max_registros_x_lote" do
|
|
67
|
-
savon.expects(
|
|
62
|
+
savon.expects(:fe_comp_tot_x_request).with(message: auth).returns(fixture('fe_comp_tot_x_request/success'))
|
|
68
63
|
ws.cant_max_registros_x_lote.should == 250
|
|
69
64
|
end
|
|
70
65
|
|
|
71
66
|
context "autorizar_comprobante" do
|
|
72
67
|
it "debería devolver un hash con el CAE y su fecha de vencimiento" do
|
|
73
|
-
savon.expects(
|
|
74
|
-
'/
|
|
75
|
-
'
|
|
76
|
-
'
|
|
77
|
-
'
|
|
78
|
-
'
|
|
79
|
-
'
|
|
80
|
-
'
|
|
81
|
-
'
|
|
82
|
-
'
|
|
83
|
-
'
|
|
84
|
-
'
|
|
85
|
-
'
|
|
86
|
-
'
|
|
87
|
-
'
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
:
|
|
92
|
-
:
|
|
93
|
-
:
|
|
68
|
+
savon.expects(:fecae_solicitar).with(message: has_path(
|
|
69
|
+
'//Auth/Token' => 't',
|
|
70
|
+
'//FeCAEReq/FeCabReq/CantReg' => 1,
|
|
71
|
+
'//FeCAEReq/FeCabReq/PtoVta' => 2,
|
|
72
|
+
'//FeCAEReq/FeCabReq/CbteTipo' => 1,
|
|
73
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/DocTipo' => 80,
|
|
74
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/DocNro' => 30521189203,
|
|
75
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/CbteFch' => 20110113,
|
|
76
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/ImpTotal' => 1270.48,
|
|
77
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/ImpIVA' => 220.5,
|
|
78
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[1]/Id' => 5,
|
|
79
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[1]/Importe' => 220.5,
|
|
80
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Tributos/Tributo[1]/Id' => 0,
|
|
81
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Tributos/Tributo[1]/BaseImp' => 150,
|
|
82
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Tributos/Tributo[1]/Alic' => 5.2,
|
|
83
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Tributos/Tributo[1]/Importe' => 7.8
|
|
84
|
+
)).returns(fixture('fecae_solicitar/autorizacion_1_cbte'))
|
|
85
|
+
rta = ws.autorizar_comprobantes(cbte_tipo: 1, pto_vta: 2, comprobantes: [{cbte_nro: 1, concepto: 1,
|
|
86
|
+
doc_nro: 30521189203, doc_tipo: 80, cbte_fch: Date.new(2011,01,13),
|
|
87
|
+
imp_total: 1270.48, imp_neto: 1049.98, imp_iva: 220.50, mon_id: 'PES', mon_cotiz: 1,
|
|
88
|
+
iva: { alic_iva: [{ id: 5, base_imp: 1049.98, importe: 220.50 }]},
|
|
89
|
+
tributos: { tributo: [{ id: 0, base_imp: 150, alic: 5.2, importe: 7.8 }] }
|
|
94
90
|
}])
|
|
95
|
-
rta[0].should have_entries :
|
|
96
|
-
:
|
|
97
|
-
rta.should
|
|
91
|
+
rta[0].should have_entries cae: '61023008595705', cae_fch_vto: Date.new(2011,01,23), cbte_nro: 1,
|
|
92
|
+
resultado: 'A', observaciones: []
|
|
93
|
+
rta.size.should == 1
|
|
98
94
|
end
|
|
99
95
|
|
|
100
96
|
it "con varias alicuotas iva" do
|
|
101
|
-
savon.expects(
|
|
102
|
-
'
|
|
103
|
-
'
|
|
104
|
-
'
|
|
105
|
-
'
|
|
106
|
-
|
|
107
|
-
ws.autorizar_comprobantes(:
|
|
108
|
-
{ :
|
|
109
|
-
{ :
|
|
97
|
+
savon.expects(:fecae_solicitar).with(message: has_path(
|
|
98
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[1]/Id' => 5,
|
|
99
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[1]/Importe' => 21,
|
|
100
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[2]/Id' => 4,
|
|
101
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/Iva/AlicIva[2]/Importe' => 5.25
|
|
102
|
+
)).returns(fixture('fecae_solicitar/autorizacion_1_cbte'))
|
|
103
|
+
ws.autorizar_comprobantes(cbte_tipo: 1, pto_vta: 2, comprobantes: [{iva: {alic_iva: [
|
|
104
|
+
{ id: 5, base_imp: 100, importe: 21 },
|
|
105
|
+
{ id: 4, base_imp: 50, importe: 5.25 }
|
|
110
106
|
]}}])
|
|
111
107
|
end
|
|
112
108
|
|
|
113
109
|
it "con varios comprobantes aprobados" do
|
|
114
|
-
savon.expects(
|
|
115
|
-
'
|
|
116
|
-
'
|
|
117
|
-
'
|
|
118
|
-
'
|
|
119
|
-
'
|
|
120
|
-
|
|
121
|
-
rta = ws.autorizar_comprobantes(:
|
|
122
|
-
|
|
123
|
-
]
|
|
124
|
-
rta[0].should have_entries :cbte_nro => 5, :cae => '61033008894096'
|
|
125
|
-
rta[1].should have_entries :cbte_nro => 6, :cae => '61033008894101'
|
|
110
|
+
savon.expects(:fecae_solicitar).with(message: has_path(
|
|
111
|
+
'//FeCAEReq/FeCabReq/CantReg' => 2,
|
|
112
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/CbteDesde' => 5,
|
|
113
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[1]/CbteHasta' => 5,
|
|
114
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[2]/CbteDesde' => 6,
|
|
115
|
+
'//FeCAEReq/FeDetReq/FECAEDetRequest[2]/CbteHasta' => 6,
|
|
116
|
+
)).returns(fixture('fecae_solicitar/autorizacion_2_cbtes'))
|
|
117
|
+
rta = ws.autorizar_comprobantes(cbte_tipo: 1, pto_vta: 2, comprobantes: [{ cbte_nro: 5 }, { cbte_nro: 6 }])
|
|
118
|
+
rta[0].should have_entries cbte_nro: 5, cae: '61033008894096'
|
|
119
|
+
rta[1].should have_entries cbte_nro: 6, cae: '61033008894101'
|
|
126
120
|
end
|
|
127
121
|
|
|
128
122
|
it "con 2 observaciones" do
|
|
129
|
-
savon.
|
|
130
|
-
rta = ws.autorizar_comprobantes :
|
|
131
|
-
rta[0].should have_entries :
|
|
132
|
-
{:
|
|
123
|
+
savon.expects(:fecae_solicitar).with(message: :any).returns(fixture 'fecae_solicitar/dos_observaciones')
|
|
124
|
+
rta = ws.autorizar_comprobantes comprobantes: []
|
|
125
|
+
rta[0].should have_entries cbte_nro: 3, cae: nil, resultado: 'R', observaciones: [
|
|
126
|
+
{code: 10048, msg: 'Msg 1'}, {code: 10018, msg: 'Msg 2'}]
|
|
133
127
|
end
|
|
134
128
|
|
|
135
129
|
it "con 1 observación" do
|
|
136
|
-
savon.
|
|
137
|
-
rta = ws.autorizar_comprobantes :
|
|
138
|
-
rta[0].should have_entries :
|
|
130
|
+
savon.expects(:fecae_solicitar).with(message: :any).returns(fixture 'fecae_solicitar/una_observacion')
|
|
131
|
+
rta = ws.autorizar_comprobantes comprobantes: []
|
|
132
|
+
rta[0].should have_entries observaciones: [{code: 10048, msg: 'Msg 1'}]
|
|
139
133
|
end
|
|
140
134
|
end
|
|
141
135
|
|
|
142
136
|
context "solicitar_caea" do
|
|
143
137
|
it "debería mandar automáticamente el período y orden" do
|
|
144
|
-
Date.stubs :
|
|
145
|
-
savon.expects(
|
|
146
|
-
ws.solicitar_caea.should have_entries :
|
|
147
|
-
:
|
|
138
|
+
Date.stubs today: Date.new(2011,1,27)
|
|
139
|
+
savon.expects(:fecaea_solicitar).with(message: has_path('//Periodo' => '201102', '//Orden' => 1)).returns(fixture 'fecaea_solicitar/success')
|
|
140
|
+
ws.solicitar_caea.should have_entries caea: '21043476341977', fch_tope_inf: Date.new(2011,03,17),
|
|
141
|
+
fch_vig_desde: Date.new(2011,02,01), fch_vig_hasta: Date.new(2011,02,15)
|
|
148
142
|
end
|
|
149
143
|
|
|
150
144
|
context "periodo_para_solicitud_caea" do
|
|
151
145
|
it "cuando estoy en la primer quincena" do
|
|
152
|
-
Date.stubs :
|
|
153
|
-
ws.periodo_para_solicitud_caea.should == { :
|
|
154
|
-
Date.stubs :
|
|
155
|
-
ws.periodo_para_solicitud_caea.should == { :
|
|
146
|
+
Date.stubs today: Date.new(2011,1,12)
|
|
147
|
+
ws.periodo_para_solicitud_caea.should == { periodo: '201101', orden: 2 }
|
|
148
|
+
Date.stubs today: Date.new(2011,1,15)
|
|
149
|
+
ws.periodo_para_solicitud_caea.should == { periodo: '201101', orden: 2 }
|
|
156
150
|
end
|
|
157
151
|
|
|
158
152
|
it "cuando estoy en la segunda quincena" do
|
|
159
|
-
Date.stubs :
|
|
160
|
-
ws.periodo_para_solicitud_caea.should == { :
|
|
161
|
-
Date.stubs :
|
|
162
|
-
ws.periodo_para_solicitud_caea.should == { :
|
|
153
|
+
Date.stubs today: Date.new(2011,1,16)
|
|
154
|
+
ws.periodo_para_solicitud_caea.should == { periodo: '201102', orden: 1 }
|
|
155
|
+
Date.stubs today: Date.new(2011,1,31)
|
|
156
|
+
ws.periodo_para_solicitud_caea.should == { periodo: '201102', orden: 1 }
|
|
163
157
|
end
|
|
164
158
|
end
|
|
165
159
|
|
|
166
160
|
it "cuando el caea ya fue otorgado debería consultarlo y devolverlo" do
|
|
167
|
-
Date.stubs :
|
|
168
|
-
savon.expects(
|
|
169
|
-
savon.expects(
|
|
170
|
-
ws.solicitar_caea.should have_entries :
|
|
161
|
+
Date.stubs today: Date.new(2011,1,27)
|
|
162
|
+
savon.expects(:fecaea_solicitar).with(message: has_path('//Periodo' => '201102', '//Orden' => 1)).returns(fixture 'fecaea_solicitar/caea_ya_otorgado')
|
|
163
|
+
savon.expects(:fecaea_consultar).with(message: has_path('//Periodo' => '201102', '//Orden' => 1)).returns(fixture 'fecaea_consultar/success')
|
|
164
|
+
ws.solicitar_caea.should have_entries caea: '21043476341977', fch_vig_desde: Date.new(2011,02,01)
|
|
171
165
|
end
|
|
172
166
|
|
|
173
167
|
it "cuando hay otro error debería burbujearlo" do
|
|
174
|
-
savon.expects(
|
|
175
|
-
|
|
168
|
+
savon.expects(:fecaea_solicitar).with(message: :any).returns(fixture 'fecaea_solicitar/error_distinto')
|
|
169
|
+
lambda { ws.solicitar_caea }.should raise_error Afipws::WSError, /15007/
|
|
176
170
|
end
|
|
177
171
|
end
|
|
178
172
|
|
|
179
173
|
it "informar_comprobantes_caea" do
|
|
180
|
-
savon.expects(
|
|
181
|
-
'/
|
|
182
|
-
'
|
|
183
|
-
'
|
|
184
|
-
'
|
|
185
|
-
'
|
|
186
|
-
'
|
|
187
|
-
'
|
|
188
|
-
'
|
|
189
|
-
'
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
174
|
+
savon.expects(:fecaea_reg_informativo).with(message: has_path(
|
|
175
|
+
'//Auth/Token' => 't',
|
|
176
|
+
'//FeCAEARegInfReq/FeCabReq/CantReg' => 2,
|
|
177
|
+
'//FeCAEARegInfReq/FeCabReq/PtoVta' => 3,
|
|
178
|
+
'//FeCAEARegInfReq/FeCabReq/CbteTipo' => 1,
|
|
179
|
+
'//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[1]/CbteDesde' => 1,
|
|
180
|
+
'//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[1]/CbteHasta' => 1,
|
|
181
|
+
'//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[1]/CAEA' => '21043476341977',
|
|
182
|
+
'//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[2]/CbteDesde' => 2,
|
|
183
|
+
'//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[2]/CbteHasta' => 2,
|
|
184
|
+
'//FeCAEARegInfReq/FeDetReq/FECAEADetRequest[2]/CAEA' => '21043476341977',
|
|
185
|
+
)).returns(fixture 'fecaea_reg_informativo/informe_rtdo_parcial')
|
|
186
|
+
rta = ws.informar_comprobantes_caea(cbte_tipo: 1, pto_vta: 3, comprobantes: [
|
|
187
|
+
{ cbte_nro: 1, caea: '21043476341977' }, { cbte_nro: 2, caea: '21043476341977' },
|
|
193
188
|
])
|
|
194
|
-
rta[0].should have_entries :
|
|
195
|
-
rta[1].should have_entries :
|
|
189
|
+
rta[0].should have_entries cbte_nro: 1, caea: '21043476341977', resultado: 'A', observaciones: []
|
|
190
|
+
rta[1].should have_entries cbte_nro: 2, caea: '21043476341977', resultado: 'R', observaciones: [{code: 724, msg: 'Msg'}]
|
|
196
191
|
end
|
|
197
192
|
|
|
198
193
|
it "informar_caea_sin_movimientos" do
|
|
199
|
-
savon.expects(
|
|
200
|
-
'/
|
|
194
|
+
savon.expects(:fecaea_sin_movimiento_informar).with(message: has_path(
|
|
195
|
+
'//Auth/Token' => 't',
|
|
196
|
+
'//PtoVta' => 4,
|
|
197
|
+
'//CAEA' => '21043476341977'
|
|
198
|
+
)).returns(fixture 'fecaea_sin_movimiento_informar/success')
|
|
201
199
|
rta = ws.informar_caea_sin_movimientos('21043476341977', 4)
|
|
202
|
-
rta.should have_entries :
|
|
200
|
+
rta.should have_entries caea: '21043476341977', resultado: 'A'
|
|
203
201
|
end
|
|
204
202
|
|
|
205
203
|
context "consultar_caea" do
|
|
206
204
|
it "consultar_caea" do
|
|
207
|
-
savon.expects(
|
|
208
|
-
ws.consultar_caea(Date.new(2011,1,1)).should have_entries :
|
|
205
|
+
savon.expects(:fecaea_consultar).with(message: has_path('//Periodo' => '201101', '//Orden' => 1)).returns(fixture 'fecaea_consultar/success')
|
|
206
|
+
ws.consultar_caea(Date.new(2011,1,1)).should have_entries caea: '21043476341977', fch_tope_inf: Date.new(2011,03,17)
|
|
209
207
|
end
|
|
210
208
|
end
|
|
211
209
|
|
|
212
210
|
it "ultimo_comprobante_autorizado" do
|
|
213
|
-
savon.expects(
|
|
214
|
-
ws.ultimo_comprobante_autorizado(:
|
|
211
|
+
savon.expects(:fe_comp_ultimo_autorizado).with(message: has_path('//PtoVta' => 1, '//CbteTipo' => 1)).returns(fixture 'fe_comp_ultimo_autorizado/success')
|
|
212
|
+
ws.ultimo_comprobante_autorizado(pto_vta: 1, cbte_tipo: 1).should == 20
|
|
215
213
|
end
|
|
216
214
|
|
|
217
215
|
it "consultar_comprobante" do
|
|
218
|
-
savon.expects(
|
|
219
|
-
'/FeCompConsReq/PtoVta' => 1, '
|
|
220
|
-
|
|
216
|
+
savon.expects(:fe_comp_consultar).with(message: has_path(
|
|
217
|
+
'//Auth/Token' => 't', '//FeCompConsReq/PtoVta' => 1, '//FeCompConsReq/CbteTipo' => 2, '//FeCompConsReq/CbteNro' => 3
|
|
218
|
+
)).returns(fixture 'fe_comp_consultar/success')
|
|
219
|
+
rta = ws.consultar_comprobante(pto_vta: 1, cbte_tipo: 2, cbte_nro: 3)
|
|
221
220
|
rta[:cod_autorizacion].should == '61023008595705'
|
|
222
221
|
rta[:emision_tipo].should == 'CAE'
|
|
223
222
|
end
|
|
@@ -225,48 +224,49 @@ describe Afipws::WSFE do
|
|
|
225
224
|
|
|
226
225
|
context "autenticacion" do
|
|
227
226
|
it "debería autenticarse usando el WSAA" do
|
|
228
|
-
wsfe = Afipws::WSFE.new :
|
|
227
|
+
wsfe = Afipws::WSFE.new cuit: '1', cert: 'cert', key: 'key'
|
|
229
228
|
wsfe.wsaa.cert.should == 'cert'
|
|
230
229
|
wsfe.wsaa.key.should == 'key'
|
|
231
230
|
wsfe.wsaa.service.should == 'wsfe'
|
|
232
|
-
wsfe.wsaa.expects(:login).returns({ :
|
|
233
|
-
savon.expects(
|
|
231
|
+
wsfe.wsaa.expects(:login).returns({ token: 't', sign: 's' })
|
|
232
|
+
savon.expects(:fe_param_get_tipos_cbte).with(message: has_path(
|
|
233
|
+
'//Auth/Token' => 't', '//Auth/Sign' => 's', '//Auth/Cuit' => '1'
|
|
234
|
+
)).returns(fixture 'fe_param_get_tipos_cbte/success')
|
|
234
235
|
wsfe.tipos_comprobantes
|
|
235
236
|
end
|
|
236
237
|
end
|
|
237
238
|
|
|
238
239
|
context "entorno" do
|
|
239
240
|
it "debería usar las url para development cuando el env es development" do
|
|
240
|
-
Afipws::Client.expects(:new).with(
|
|
241
|
-
Afipws::Client.expects(:new).with(
|
|
242
|
-
wsfe = Afipws::WSFE.new :
|
|
241
|
+
Afipws::Client.expects(:new).with(wsdl: 'https://wsaahomo.afip.gov.ar/ws/services/LoginCms?wsdl')
|
|
242
|
+
Afipws::Client.expects(:new).with(wsdl: 'https://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL', ssl_version: :SSLv3, convert_request_keys_to: :camelcase)
|
|
243
|
+
wsfe = Afipws::WSFE.new env: :development
|
|
243
244
|
wsfe.env.should == :development
|
|
244
245
|
end
|
|
245
246
|
|
|
246
247
|
it "debería usar las url para production cuando el env es production" do
|
|
247
|
-
Afipws::Client.expects(:new).with(
|
|
248
|
-
|
|
249
|
-
Afipws::
|
|
250
|
-
wsfe = Afipws::WSFE.new :env => 'production'
|
|
248
|
+
Afipws::Client.expects(:new).with(wsdl: 'https://wsaa.afip.gov.ar/ws/services/LoginCms?wsdl')
|
|
249
|
+
Afipws::Client.expects(:new).with(has_entries wsdl: File.expand_path(File.dirname(__FILE__) + '/../../') + "/lib/afipws/wsfev1.wsdl")
|
|
250
|
+
wsfe = Afipws::WSFE.new env: 'production'
|
|
251
251
|
wsfe.env.should == :production
|
|
252
252
|
end
|
|
253
253
|
end
|
|
254
254
|
|
|
255
255
|
context "manejo de errores" do
|
|
256
256
|
it "cuando hay un error" do
|
|
257
|
-
savon.expects(
|
|
258
|
-
|
|
257
|
+
savon.expects(:fe_param_get_tipos_cbte).with(message: :any).returns(fixture 'fe_param_get_tipos_cbte/failure_1_error')
|
|
258
|
+
lambda { ws.tipos_comprobantes }.should raise_error { |e|
|
|
259
259
|
e.should be_a Afipws::WSError
|
|
260
|
-
e.errors.should == [{ :
|
|
260
|
+
e.errors.should == [{ code: "600", msg: "No se corresponden token con firma" }]
|
|
261
261
|
e.message.should == "600: No se corresponden token con firma"
|
|
262
262
|
}
|
|
263
263
|
end
|
|
264
264
|
|
|
265
265
|
it "cuando hay varios errores" do
|
|
266
|
-
savon.expects(
|
|
267
|
-
|
|
266
|
+
savon.expects(:fe_param_get_tipos_cbte).with(message: :any).returns(fixture 'fe_param_get_tipos_cbte/failure_2_errors')
|
|
267
|
+
lambda { ws.tipos_comprobantes }.should raise_error { |e|
|
|
268
268
|
e.should be_a Afipws::WSError
|
|
269
|
-
e.errors.should == [{ :
|
|
269
|
+
e.errors.should == [{ code: "600", msg: "No se corresponden token con firma" }, { code: "601", msg: "CUIT representada no incluida en token" }]
|
|
270
270
|
e.message.should == "600: No se corresponden token con firma; 601: CUIT representada no incluida en token"
|
|
271
271
|
}
|
|
272
272
|
end
|
|
@@ -274,11 +274,11 @@ describe Afipws::WSFE do
|
|
|
274
274
|
|
|
275
275
|
context "cálculo de fechas y períodos" do
|
|
276
276
|
it "periodo_para_consulta_caea" do
|
|
277
|
-
ws.periodo_para_consulta_caea(Date.new(2011,1,1)).should == { :
|
|
278
|
-
ws.periodo_para_consulta_caea(Date.new(2011,1,15)).should == { :
|
|
279
|
-
ws.periodo_para_consulta_caea(Date.new(2011,1,16)).should == { :
|
|
280
|
-
ws.periodo_para_consulta_caea(Date.new(2011,1,31)).should == { :
|
|
281
|
-
ws.periodo_para_consulta_caea(Date.new(2011,2,2)).should == { :
|
|
277
|
+
ws.periodo_para_consulta_caea(Date.new(2011,1,1)).should == { periodo: '201101', orden: 1 }
|
|
278
|
+
ws.periodo_para_consulta_caea(Date.new(2011,1,15)).should == { periodo: '201101', orden: 1 }
|
|
279
|
+
ws.periodo_para_consulta_caea(Date.new(2011,1,16)).should == { periodo: '201101', orden: 2 }
|
|
280
|
+
ws.periodo_para_consulta_caea(Date.new(2011,1,31)).should == { periodo: '201101', orden: 2 }
|
|
281
|
+
ws.periodo_para_consulta_caea(Date.new(2011,2,2)).should == { periodo: '201102', orden: 1 }
|
|
282
282
|
end
|
|
283
283
|
|
|
284
284
|
it "fecha_inicio_quincena_siguiente" do
|
|
@@ -293,7 +293,7 @@ describe Afipws::WSFE do
|
|
|
293
293
|
end
|
|
294
294
|
|
|
295
295
|
def fecha_inicio_quincena_siguiente fecha
|
|
296
|
-
Date.stubs(:
|
|
296
|
+
Date.stubs(today: fecha)
|
|
297
297
|
subject.fecha_inicio_quincena_siguiente
|
|
298
298
|
end
|
|
299
299
|
end
|
|
@@ -304,7 +304,7 @@ describe Afipws::WSFE do
|
|
|
304
304
|
end
|
|
305
305
|
|
|
306
306
|
it "no debería enviar tag tributos si el impTrib es 0" do
|
|
307
|
-
c2r(:
|
|
307
|
+
c2r(imp_trib: 0.0, tributos: { tributo: [] }).should_not have_key :tributos
|
|
308
308
|
end
|
|
309
309
|
end
|
|
310
310
|
end
|
data/spec/manual/test.rb
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
$LOAD_PATH.unshift(File.expand_path('lib')); require 'afipws'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
ws = Afipws::WSFE.new :env => :development, :cuit => '20300032673', :cert => File.read('spec/manual/test.crt'), :key => File.read('spec/manual/test.key')
|
|
3
|
+
ws = Afipws::WSFE.new env: :development, cuit: '20300032673', cert: File.read('spec/manual/test.crt'), key: File.read('spec/manual/test.key'), savon: {log: true}
|
|
6
4
|
|
|
7
5
|
def obtener_ta ws
|
|
8
6
|
ws.cotizacion 'DOL'
|
|
@@ -16,26 +14,22 @@ def obtener_ta ws
|
|
|
16
14
|
end
|
|
17
15
|
|
|
18
16
|
def autorizar_comprobante ws
|
|
19
|
-
ultimo = ws.ultimo_comprobante_autorizado :
|
|
17
|
+
ultimo = ws.ultimo_comprobante_autorizado pto_vta: 1, cbte_tipo: 1
|
|
20
18
|
# cant_informar = ws.cant_max_registros_x_lote
|
|
21
19
|
cant_informar = 2
|
|
22
20
|
puts "Informando #{cant_informar} comprobantes"
|
|
23
21
|
comprobantes = (1..cant_informar).to_a.map do |i|
|
|
24
22
|
{
|
|
25
|
-
:
|
|
26
|
-
:
|
|
27
|
-
:
|
|
23
|
+
cbte_nro: ultimo + i, concepto: 1, doc_nro: 30521189203, doc_tipo: 80, cbte_fch: Date.today,
|
|
24
|
+
imp_total: 1270.48, imp_neto: 1049.98, imp_iva: 220.50, mon_id: 'PES', mon_cotiz: 1,
|
|
25
|
+
iva: { alic_iva: [{ id: 5, base_imp: 1049.98, importe: 220.50 }]}
|
|
28
26
|
}
|
|
29
27
|
end
|
|
30
|
-
puts ws.autorizar_comprobantes(:
|
|
28
|
+
puts ws.autorizar_comprobantes(cbte_tipo: 1, pto_vta: 1, comprobantes: comprobantes)
|
|
31
29
|
end
|
|
32
30
|
|
|
33
31
|
def consultar_caea ws
|
|
34
32
|
ws.consultar_caea Date.new(2011,2,3)
|
|
35
33
|
end
|
|
36
34
|
|
|
37
|
-
def soap_actions ws
|
|
38
|
-
ws.client.soap_actions
|
|
39
|
-
end
|
|
40
|
-
|
|
41
35
|
obtener_ta ws
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
require 'rspec'
|
|
2
2
|
require 'afipws'
|
|
3
|
-
require '
|
|
3
|
+
require 'savon/mock/spec_helper'
|
|
4
|
+
require 'mocha'
|
|
5
|
+
require 'pry-byebug'
|
|
4
6
|
|
|
5
7
|
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
|
|
6
8
|
|
|
7
9
|
RSpec.configure do |config|
|
|
8
|
-
config.include Savon::
|
|
10
|
+
config.include Savon::SpecHelper
|
|
11
|
+
|
|
12
|
+
config.mock_with :mocha
|
|
13
|
+
config.expect_with(:rspec) { |c| c.syntax = :should }
|
|
14
|
+
config.alias_example_to :fit, focused: true
|
|
15
|
+
config.filter_run focused: true
|
|
16
|
+
config.run_all_when_everything_filtered = true
|
|
17
|
+
|
|
18
|
+
config.before(:all) { savon.mock! }
|
|
19
|
+
config.after(:all) { savon.unmock! }
|
|
9
20
|
end
|
|
10
21
|
|
|
11
|
-
|
|
22
|
+
def fixture file
|
|
23
|
+
File.read("#{Afipws::Root}/spec/fixtures/#{file}.xml")
|
|
24
|
+
end
|
data/spec/support/matchers.rb
CHANGED
|
@@ -1,37 +1,11 @@
|
|
|
1
|
-
RSpec::Matchers.define :match_xpath do |xpath,
|
|
1
|
+
RSpec::Matchers.define :match_xpath do |xpath, expected_value|
|
|
2
2
|
match do |xml|
|
|
3
|
-
xml = Nokogiri::XML xml
|
|
4
|
-
xml.
|
|
3
|
+
@xml = Nokogiri::XML xml
|
|
4
|
+
@xml.remove_namespaces!
|
|
5
|
+
@xml.xpath(xpath).text.should == expected_value.to_s
|
|
5
6
|
end
|
|
6
|
-
end
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
module Mocha
|
|
11
|
-
module ParameterMatchers
|
|
12
|
-
def has_path(paths)
|
|
13
|
-
HasPath.new(paths)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class HasPath < Base # :nodoc:
|
|
17
|
-
def initialize(paths)
|
|
18
|
-
@paths = paths
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def matches?(available_parameters)
|
|
22
|
-
parameter = available_parameters.shift
|
|
23
|
-
return false unless parameter.is_a? Hash
|
|
24
|
-
@paths.all? do |path|
|
|
25
|
-
path, expected_value = path
|
|
26
|
-
actual_value = parameter.fetch_path path.gsub('/', '/wsdl:')
|
|
27
|
-
@failed_path, @failed_value, @actual_value = path, expected_value, actual_value
|
|
28
|
-
expected_value == actual_value
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def mocha_inspect
|
|
33
|
-
"has_path(#{@failed_path.mocha_inspect} => #{@failed_value.mocha_inspect} | Actual: #{@actual_value.mocha_inspect})"
|
|
34
|
-
end
|
|
35
|
-
end
|
|
8
|
+
failure_message_for_should do |actual|
|
|
9
|
+
"expected xpath '#{xpath}' with value '#{expected_value}' in doc:\n#{@xml}"
|
|
36
10
|
end
|
|
37
11
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Savon 2 sólo permite verificar los params del mensaje como un hash lo cual es poco flexible. Con esto permito pasarle xpaths.
|
|
2
|
+
|
|
3
|
+
module Savon
|
|
4
|
+
module MessageMatcher
|
|
5
|
+
def actual(operation_name, builder, globals, locals)
|
|
6
|
+
super.update request: builder.to_s
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def verify_message!
|
|
10
|
+
if @expected[:message].respond_to? :verify!
|
|
11
|
+
@expected[:message].verify! @actual[:request]
|
|
12
|
+
else
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
MockExpectation.prepend MessageMatcher
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def has_path(paths)
|
|
22
|
+
HasXPath.new(paths)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class HasXPath
|
|
26
|
+
include RSpec::Matchers
|
|
27
|
+
|
|
28
|
+
def initialize(paths)
|
|
29
|
+
@paths = paths
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def verify! xml
|
|
33
|
+
@actual_xml = xml
|
|
34
|
+
@paths.each do |(path, value)|
|
|
35
|
+
@expected_xpath, @expected_value = path, value
|
|
36
|
+
@actual_xml.should match_xpath @expected_xpath, @expected_value
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: afipws
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emmanuel Nicolau
|
|
@@ -14,52 +14,66 @@ dependencies:
|
|
|
14
14
|
name: rspec
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 2.14.1
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 2.14.1
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 10.4.2
|
|
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: 10.4.2
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: mocha
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
47
|
+
version: 0.9.10
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
54
|
+
version: 0.9.10
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: guard-rspec
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 4.3.1
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 4.3.1
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: pry-byebug
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
58
72
|
requirements:
|
|
59
73
|
- - ">="
|
|
60
74
|
- !ruby/object:Gem::Version
|
|
61
75
|
version: '0'
|
|
62
|
-
type: :
|
|
76
|
+
type: :development
|
|
63
77
|
prerelease: false
|
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
79
|
requirements:
|
|
@@ -67,7 +81,7 @@ dependencies:
|
|
|
67
81
|
- !ruby/object:Gem::Version
|
|
68
82
|
version: '0'
|
|
69
83
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
84
|
+
name: builder
|
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
|
72
86
|
requirements:
|
|
73
87
|
- - ">="
|
|
@@ -81,21 +95,21 @@ dependencies:
|
|
|
81
95
|
- !ruby/object:Gem::Version
|
|
82
96
|
version: '0'
|
|
83
97
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
98
|
+
name: savon
|
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
|
86
100
|
requirements:
|
|
87
|
-
- - "
|
|
101
|
+
- - "~>"
|
|
88
102
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
103
|
+
version: 2.11.0
|
|
90
104
|
type: :runtime
|
|
91
105
|
prerelease: false
|
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
107
|
requirements:
|
|
94
|
-
- - "
|
|
108
|
+
- - "~>"
|
|
95
109
|
- !ruby/object:Gem::Version
|
|
96
|
-
version:
|
|
110
|
+
version: 2.11.0
|
|
97
111
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
112
|
+
name: nokogiri
|
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
|
100
114
|
requirements:
|
|
101
115
|
- - ">="
|
|
@@ -109,7 +123,7 @@ dependencies:
|
|
|
109
123
|
- !ruby/object:Gem::Version
|
|
110
124
|
version: '0'
|
|
111
125
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name:
|
|
126
|
+
name: activesupport
|
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
|
114
128
|
requirements:
|
|
115
129
|
- - ">="
|
|
@@ -123,7 +137,7 @@ dependencies:
|
|
|
123
137
|
- !ruby/object:Gem::Version
|
|
124
138
|
version: '0'
|
|
125
139
|
- !ruby/object:Gem::Dependency
|
|
126
|
-
name:
|
|
140
|
+
name: i18n
|
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
|
128
142
|
requirements:
|
|
129
143
|
- - ">="
|
|
@@ -137,19 +151,19 @@ dependencies:
|
|
|
137
151
|
- !ruby/object:Gem::Version
|
|
138
152
|
version: '0'
|
|
139
153
|
- !ruby/object:Gem::Dependency
|
|
140
|
-
name:
|
|
154
|
+
name: httpclient
|
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
|
142
156
|
requirements:
|
|
143
157
|
- - ">="
|
|
144
158
|
- !ruby/object:Gem::Version
|
|
145
|
-
version:
|
|
159
|
+
version: '0'
|
|
146
160
|
type: :runtime
|
|
147
161
|
prerelease: false
|
|
148
162
|
version_requirements: !ruby/object:Gem::Requirement
|
|
149
163
|
requirements:
|
|
150
164
|
- - ">="
|
|
151
165
|
- !ruby/object:Gem::Version
|
|
152
|
-
version:
|
|
166
|
+
version: '0'
|
|
153
167
|
description: ''
|
|
154
168
|
email:
|
|
155
169
|
- emmanicolau@gmail.com
|
|
@@ -216,6 +230,7 @@ files:
|
|
|
216
230
|
- spec/manual/test.rb
|
|
217
231
|
- spec/spec_helper.rb
|
|
218
232
|
- spec/support/matchers.rb
|
|
233
|
+
- spec/support/savon_extensions.rb
|
|
219
234
|
homepage: ''
|
|
220
235
|
licenses: []
|
|
221
236
|
metadata: {}
|
|
@@ -279,3 +294,4 @@ test_files:
|
|
|
279
294
|
- spec/manual/test.rb
|
|
280
295
|
- spec/spec_helper.rb
|
|
281
296
|
- spec/support/matchers.rb
|
|
297
|
+
- spec/support/savon_extensions.rb
|