bravo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +57 -0
- data/LICENSE.txt +20 -0
- data/README.textile +53 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/autotest/discover.rb +1 -0
- data/bravo.gemspec +88 -0
- data/lib/bravo.rb +23 -0
- data/lib/bravo/auth_data.rb +22 -0
- data/lib/bravo/authorizer.rb +10 -0
- data/lib/bravo/bill.rb +122 -0
- data/lib/bravo/constants.rb +42 -0
- data/lib/bravo/core_ext/float.rb +8 -0
- data/lib/bravo/version.rb +3 -0
- data/spec/bravo/auth_data_spec.rb +12 -0
- data/spec/bravo/authorizer_spec.rb +9 -0
- data/spec/bravo/bill_spec.rb +102 -0
- data/spec/spec_helper.rb +24 -0
- data/wsaa-client.sh +171 -0
- metadata +214 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
gem "savon", "~> 0.7.8"
|
3
|
+
|
4
|
+
group :development do
|
5
|
+
platforms :ruby_18 do
|
6
|
+
gem "ruby-debug"
|
7
|
+
end
|
8
|
+
platforms :ruby_19 do
|
9
|
+
gem 'ruby-debug-base19', "0.11.24"
|
10
|
+
gem 'ruby-debug19', "0.11.6"
|
11
|
+
end
|
12
|
+
gem "rspec", "~> 2.4.0"
|
13
|
+
gem "bundler", "~> 1.0.0"
|
14
|
+
gem "jeweler", "~> 1.5.1"
|
15
|
+
gem "rcov", ">= 0"
|
16
|
+
end
|
17
|
+
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
archive-tar-minitar (0.5.2)
|
5
|
+
builder (3.0.0)
|
6
|
+
columnize (0.3.2)
|
7
|
+
crack (0.1.8)
|
8
|
+
diff-lcs (1.1.2)
|
9
|
+
git (1.2.5)
|
10
|
+
jeweler (1.5.2)
|
11
|
+
bundler (~> 1.0.0)
|
12
|
+
git (>= 1.2.5)
|
13
|
+
rake
|
14
|
+
linecache (0.43)
|
15
|
+
linecache19 (0.5.11)
|
16
|
+
ruby_core_source (>= 0.1.4)
|
17
|
+
rake (0.8.7)
|
18
|
+
rcov (0.9.9)
|
19
|
+
rspec (2.4.0)
|
20
|
+
rspec-core (~> 2.4.0)
|
21
|
+
rspec-expectations (~> 2.4.0)
|
22
|
+
rspec-mocks (~> 2.4.0)
|
23
|
+
rspec-core (2.4.0)
|
24
|
+
rspec-expectations (2.4.0)
|
25
|
+
diff-lcs (~> 1.1.2)
|
26
|
+
rspec-mocks (2.4.0)
|
27
|
+
ruby-debug (0.10.4)
|
28
|
+
columnize (>= 0.1)
|
29
|
+
ruby-debug-base (~> 0.10.4.0)
|
30
|
+
ruby-debug-base (0.10.4)
|
31
|
+
linecache (>= 0.3)
|
32
|
+
ruby-debug-base19 (0.11.24)
|
33
|
+
columnize (>= 0.3.1)
|
34
|
+
linecache19 (>= 0.5.11)
|
35
|
+
ruby_core_source (>= 0.1.4)
|
36
|
+
ruby-debug19 (0.11.6)
|
37
|
+
columnize (>= 0.3.1)
|
38
|
+
linecache19 (>= 0.5.11)
|
39
|
+
ruby-debug-base19 (>= 0.11.19)
|
40
|
+
ruby_core_source (0.1.4)
|
41
|
+
archive-tar-minitar (>= 0.5.2)
|
42
|
+
savon (0.7.9)
|
43
|
+
builder (>= 2.1.2)
|
44
|
+
crack (>= 0.1.4)
|
45
|
+
|
46
|
+
PLATFORMS
|
47
|
+
ruby
|
48
|
+
|
49
|
+
DEPENDENCIES
|
50
|
+
bundler (~> 1.0.0)
|
51
|
+
jeweler (~> 1.5.1)
|
52
|
+
rcov
|
53
|
+
rspec (~> 2.4.0)
|
54
|
+
ruby-debug
|
55
|
+
ruby-debug-base19 (= 0.11.24)
|
56
|
+
ruby-debug19 (= 0.11.6)
|
57
|
+
savon (~> 0.7.8)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Leandro Marcucci & Vurbia Technologies International Inc
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
h1. Bravo: la gema de facturación electrónica argentina
|
2
|
+
|
3
|
+
"-Bravo-":http://images.coveralia.com/audio/b/Bravo-Desierto_Sin_Amor-Frontal.jpg Bravo permite la obtención del "-C.A.E.-":http://www.muevamueva.com/masmusica/latina/cae/images/fotos.5.gif C.A.E. (Código de Autorización Electrónico) por medio del Web Service de Facturación Electrónica provisto por la AFIP.
|
4
|
+
|
5
|
+
h2. Instalación
|
6
|
+
|
7
|
+
<pre>
|
8
|
+
gem install bravo
|
9
|
+
</pre>
|
10
|
+
|
11
|
+
o
|
12
|
+
|
13
|
+
<pre>
|
14
|
+
gem 'bravo'
|
15
|
+
</pre>
|
16
|
+
|
17
|
+
en tu @Gemfile@
|
18
|
+
|
19
|
+
|
20
|
+
h2. Configuración
|
21
|
+
|
22
|
+
Los servicios de AFIP requieren la utilización del Web Service de Autorización y Autenticación ("wsaa readme":http://www.afip.gov.ar/ws/WSAA/README.txt)
|
23
|
+
|
24
|
+
Luego de cumplidos los pasos indicados en el readme, basta con configurar Bravo con la ruta a los archivos:
|
25
|
+
|
26
|
+
<pre>
|
27
|
+
Bravo.pkey = "spec/fixtures/pkey"
|
28
|
+
Bravo.cert = "spec/fixtures/cert.crt"
|
29
|
+
</pre>
|
30
|
+
|
31
|
+
y exportar la variable CUIT con el número de cuit usado para obtener los certificados:
|
32
|
+
|
33
|
+
@export CUIT=_numerodecuit_@
|
34
|
+
|
35
|
+
Bravo acepta más opciones, para más detalles ver el "spec_helper":https://github.com/vurbia/Bravo/blob/master/spec/spec_helper.rb
|
36
|
+
|
37
|
+
h2. Uso
|
38
|
+
|
39
|
+
El uso de la gema se centra en el metodo @authorize@. Este método invoca @FECAESolicitar@ y devuelve el resultado, que de ser exitoso incluye el CAE y su fecha de vencimento (ver "bill_spec":https://github.com/vurbia/Bravo/blob/master/spec/bravo/bill_spec.rb#L87)
|
40
|
+
|
41
|
+
|
42
|
+
h2. TODO list
|
43
|
+
|
44
|
+
* rdoc
|
45
|
+
* mensajes de error más completos
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
h2. Agradecimientos
|
50
|
+
|
51
|
+
* Emilio Tagua por sus consejos y contribuciones.
|
52
|
+
|
53
|
+
Copyright (c) 2010 Leandro Marcucci & Vurbia Technologies International Inc. See LICENSE.txt for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "bravo"
|
16
|
+
gem.homepage = "http://github.com/leanucci/bravo"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = "Adaptador AFIP wsfe."
|
19
|
+
gem.description = "Adaptador para el Web Service de Facturacion Electronica de AFIP"
|
20
|
+
gem.email = "leanucci@vurbia.com"
|
21
|
+
gem.authors = ["Leandro Marcucci"]
|
22
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
23
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
24
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
25
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
26
|
+
end
|
27
|
+
Jeweler::RubygemsDotOrgTasks.new
|
28
|
+
|
29
|
+
require 'rspec/core'
|
30
|
+
require 'rspec/core/rake_task'
|
31
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
32
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
33
|
+
end
|
34
|
+
|
35
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
36
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
37
|
+
spec.rcov = true
|
38
|
+
end
|
39
|
+
|
40
|
+
task :default => :spec
|
41
|
+
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
45
|
+
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
rdoc.title = "bravo #{version}"
|
48
|
+
rdoc.rdoc_files.include('README*')
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { "rspec2" } #added according to rspec2 book
|
data/bravo.gemspec
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{bravo}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Leandro Marcucci"]
|
12
|
+
s.date = %q{2011-03-02}
|
13
|
+
s.description = %q{Adaptador para el Web Service de Facturacion Electronica de AFIP}
|
14
|
+
s.email = %q{leanucci@vurbia.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.textile"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.textile",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"autotest/discover.rb",
|
28
|
+
"bravo.gemspec",
|
29
|
+
"lib/bravo.rb",
|
30
|
+
"lib/bravo/auth_data.rb",
|
31
|
+
"lib/bravo/authorizer.rb",
|
32
|
+
"lib/bravo/bill.rb",
|
33
|
+
"lib/bravo/constants.rb",
|
34
|
+
"lib/bravo/core_ext/float.rb",
|
35
|
+
"lib/bravo/version.rb",
|
36
|
+
"spec/bravo/auth_data_spec.rb",
|
37
|
+
"spec/bravo/authorizer_spec.rb",
|
38
|
+
"spec/bravo/bill_spec.rb",
|
39
|
+
"spec/spec_helper.rb",
|
40
|
+
"wsaa-client.sh"
|
41
|
+
]
|
42
|
+
s.homepage = %q{http://github.com/leanucci/bravo}
|
43
|
+
s.licenses = ["MIT"]
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = %q{1.3.7}
|
46
|
+
s.summary = %q{Adaptador AFIP wsfe.}
|
47
|
+
s.test_files = [
|
48
|
+
"spec/bravo/auth_data_spec.rb",
|
49
|
+
"spec/bravo/authorizer_spec.rb",
|
50
|
+
"spec/bravo/bill_spec.rb",
|
51
|
+
"spec/spec_helper.rb"
|
52
|
+
]
|
53
|
+
|
54
|
+
if s.respond_to? :specification_version then
|
55
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
56
|
+
s.specification_version = 3
|
57
|
+
|
58
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
59
|
+
s.add_runtime_dependency(%q<savon>, ["~> 0.7.8"])
|
60
|
+
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
61
|
+
s.add_development_dependency(%q<ruby-debug-base19>, ["= 0.11.24"])
|
62
|
+
s.add_development_dependency(%q<ruby-debug19>, ["= 0.11.6"])
|
63
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.4.0"])
|
64
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
65
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
|
66
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<savon>, ["~> 0.7.8"])
|
69
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
70
|
+
s.add_dependency(%q<ruby-debug-base19>, ["= 0.11.24"])
|
71
|
+
s.add_dependency(%q<ruby-debug19>, ["= 0.11.6"])
|
72
|
+
s.add_dependency(%q<rspec>, ["~> 2.4.0"])
|
73
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
74
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
75
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
76
|
+
end
|
77
|
+
else
|
78
|
+
s.add_dependency(%q<savon>, ["~> 0.7.8"])
|
79
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
80
|
+
s.add_dependency(%q<ruby-debug-base19>, ["= 0.11.24"])
|
81
|
+
s.add_dependency(%q<ruby-debug19>, ["= 0.11.6"])
|
82
|
+
s.add_dependency(%q<rspec>, ["~> 2.4.0"])
|
83
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
84
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
85
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
data/lib/bravo.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "bravo/version"
|
3
|
+
require "bravo/constants"
|
4
|
+
require "savon"
|
5
|
+
require "bravo/core_ext/float"
|
6
|
+
module Bravo
|
7
|
+
|
8
|
+
class NullOrInvalidAttribute < StandardError; end
|
9
|
+
|
10
|
+
autoload :Authorizer, "bravo/authorizer"
|
11
|
+
autoload :AuthData, "bravo/auth_data"
|
12
|
+
autoload :Bill, "bravo/bill"
|
13
|
+
autoload :Constants, "bravo/constants"
|
14
|
+
|
15
|
+
|
16
|
+
extend self
|
17
|
+
attr_accessor :cuit, :sale_point, :service_url, :default_documento, :pkey, :cert,
|
18
|
+
:default_concepto, :default_moneda, :own_iva_cond
|
19
|
+
|
20
|
+
def auth_hash
|
21
|
+
{"Token" => Bravo::TOKEN, "Sign" => Bravo::SIGN, "Cuit" => Bravo.cuit}
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Bravo
|
2
|
+
class AuthData
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def fetch
|
6
|
+
todays_datafile = "/tmp/bravo_#{Time.new.strftime('%d_%m_%Y')}.yml"
|
7
|
+
opts = "-u https://wsaahomo.afip.gov.ar/ws/services/LoginCms"
|
8
|
+
keys_root = "/Users/leanucci/Xephstratus/afip/claves/"
|
9
|
+
opts += " -k #{Bravo.pkey}"
|
10
|
+
opts += " -c #{Bravo.cert}"
|
11
|
+
|
12
|
+
unless File.exists?(todays_datafile)
|
13
|
+
%x(#{File.dirname(__FILE__)}/../../wsaa-client.sh #{opts})
|
14
|
+
end
|
15
|
+
|
16
|
+
@data = YAML.load_file(todays_datafile).each do |k, v|
|
17
|
+
Bravo.const_set(k.to_s.upcase, v) unless Bravo.const_defined?(k.to_s.upcase)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/bravo/bill.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
module Bravo
|
2
|
+
class Bill
|
3
|
+
attr_reader :client, :base_imp, :total
|
4
|
+
attr_accessor :net, :doc_num, :iva_cond, :documento, :concepto, :moneda,
|
5
|
+
:due_date, :from, :to, :aliciva_id, :fch_serv_desde, :fch_serv_hasta,
|
6
|
+
:body, :response
|
7
|
+
|
8
|
+
def initialize(attrs = {})
|
9
|
+
Bravo::AuthData.fetch
|
10
|
+
@client = Savon::Client.new(Bravo.service_url)
|
11
|
+
@body = {"Auth" => Bravo.auth_hash}
|
12
|
+
@net = attrs[:net] || 0
|
13
|
+
self.documento = attrs[:documento] || Bravo.default_documento
|
14
|
+
self.moneda = attrs[:moneda] || Bravo.default_moneda
|
15
|
+
self.iva_cond = attrs[:iva_cond]
|
16
|
+
self.concepto = attrs[:concepto] || Bravo.default_concepto
|
17
|
+
end
|
18
|
+
|
19
|
+
def cbte_type
|
20
|
+
Bravo::BILL_TYPE[Bravo.own_iva_cond][iva_cond] ||
|
21
|
+
raise(NullOrInvalidAttribute.new, "Please choose a valid document type.")
|
22
|
+
end
|
23
|
+
|
24
|
+
def exchange_rate
|
25
|
+
return 1 if moneda == :peso
|
26
|
+
response = client.fe_param_get_cotizacion do |soap|
|
27
|
+
soap.namespaces["xmlns"] = "http://ar.gov.afip.dif.FEV1/"
|
28
|
+
soap.body = body.merge!({"MonId" => Bravo::MONEDAS[moneda][:codigo]})
|
29
|
+
end
|
30
|
+
response.to_hash[:fe_param_get_cotizacion_response][:fe_param_get_cotizacion_result][:result_get][:mon_cotiz].to_f
|
31
|
+
end
|
32
|
+
|
33
|
+
def total
|
34
|
+
@total = net.zero? ? 0 : net + iva_sum
|
35
|
+
end
|
36
|
+
|
37
|
+
def iva_sum
|
38
|
+
@iva_sum = net * Bravo::ALIC_IVA[aliciva_id][1]
|
39
|
+
@iva_sum.round_up_with_precision(2)
|
40
|
+
end
|
41
|
+
|
42
|
+
def authorize
|
43
|
+
setup_bill
|
44
|
+
response = client.fecae_solicitar do |soap|
|
45
|
+
soap.namespaces["xmlns"] = "http://ar.gov.afip.dif.FEV1/"
|
46
|
+
soap.body = body
|
47
|
+
end
|
48
|
+
|
49
|
+
response = response.to_hash
|
50
|
+
|
51
|
+
setup_response(response)
|
52
|
+
self.authorized?
|
53
|
+
end
|
54
|
+
|
55
|
+
def setup_bill
|
56
|
+
today = Time.new.strftime('%Y%m%d')
|
57
|
+
|
58
|
+
fecaereq = {"FeCAEReq" => {
|
59
|
+
"FeCabReq" => Bravo::Bill.header(cbte_type),
|
60
|
+
"FeDetReq" => {
|
61
|
+
"FECAEDetRequest" => {
|
62
|
+
"Concepto" => Bravo::CONCEPTOS[concepto],
|
63
|
+
"DocTipo" => Bravo::DOCUMENTOS[documento],
|
64
|
+
"CbteFch" => today,
|
65
|
+
"ImpTotConc" => 0.00,
|
66
|
+
"MonId" => Bravo::MONEDAS[moneda][:codigo],
|
67
|
+
"MonCotiz" => exchange_rate,
|
68
|
+
"ImpOpEx" => 0.00,
|
69
|
+
"ImpTrib" => 0.00,
|
70
|
+
"Iva" => {
|
71
|
+
"AlicIva" => {
|
72
|
+
"Id" => "5",
|
73
|
+
"BaseImp" => net,
|
74
|
+
"Importe" => iva_sum}}}}}}
|
75
|
+
|
76
|
+
detail = fecaereq["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"]
|
77
|
+
|
78
|
+
detail["DocNro"] = doc_num
|
79
|
+
detail["ImpNeto"] = net.to_f
|
80
|
+
detail["ImpIVA"] = iva_sum
|
81
|
+
detail["ImpTotal"] = total
|
82
|
+
detail["CbteDesde"] = detail["CbteHasta"] = next_bill_number
|
83
|
+
|
84
|
+
unless concepto == 0
|
85
|
+
detail.merge!({"FchServDesde" => fch_serv_desde || today,
|
86
|
+
"FchServHasta" => fch_serv_hasta || today,
|
87
|
+
"FchVtoPago" => due_date || today})
|
88
|
+
end
|
89
|
+
|
90
|
+
body.merge!(fecaereq)
|
91
|
+
end
|
92
|
+
|
93
|
+
def next_bill_number
|
94
|
+
resp = client.fe_comp_ultimo_autorizado do |s|
|
95
|
+
s.namespaces["xmlns"] = "http://ar.gov.afip.dif.FEV1/"
|
96
|
+
s.body = {"Auth" => Bravo.auth_hash, "PtoVta" => Bravo.sale_point, "CbteTipo" => "1"}
|
97
|
+
end
|
98
|
+
|
99
|
+
resp.to_hash[:fe_comp_ultimo_autorizado_response][:fe_comp_ultimo_autorizado_result][:cbte_nro].to_i + 1
|
100
|
+
end
|
101
|
+
|
102
|
+
def authorized?
|
103
|
+
!response.nil? && response.header_result == "A" && response.detail_result == "A"
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
class << self
|
109
|
+
def header(cbte_type)#todo sacado de la factura
|
110
|
+
{"CantReg" => "1", "CbteTipo" => cbte_type, "PtoVta" => "2"}
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def setup_response(response)
|
115
|
+
detail_response = response[:fecae_solicitar_response][:fecae_solicitar_result][:fe_det_resp][:fecae_det_response]
|
116
|
+
header_response = response[:fecae_solicitar_response][:fecae_solicitar_result][:fe_cab_resp]
|
117
|
+
|
118
|
+
response_struct = Struct.new("Response", :header_result, :detail_result, :cae, :cae_due_date, :authorized_on)
|
119
|
+
self.response = response_struct.new(header_response[:resultado], detail_response[:resultado], detail_response[:cae], detail_response[:cae_fch_vto], header_response[:fch_proceso])
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bravo
|
3
|
+
CBTE_TIPO = {
|
4
|
+
"01"=>"Factura A",
|
5
|
+
"02"=>"Nota de Débito A",
|
6
|
+
"03"=>"Nota de Crédito A",
|
7
|
+
"04"=>"Recibos A",
|
8
|
+
"05"=>"Notas de Venta al contado A",
|
9
|
+
"06"=>"Factura B",
|
10
|
+
"07"=>"Nota de Debito B",
|
11
|
+
"08"=>"Nota de Credito B",
|
12
|
+
"09"=>"Recibos B",
|
13
|
+
"10"=>"Notas de Venta al contado B",
|
14
|
+
"34"=>"Cbtes. A del Anexo I, Apartado A,inc.f),R.G.Nro. 1415",
|
15
|
+
"35"=>"Cbtes. B del Anexo I,Apartado A,inc. f),R.G. Nro. 1415",
|
16
|
+
"39"=>"Otros comprobantes A que cumplan con R.G.Nro. 1415",
|
17
|
+
"40"=>"Otros comprobantes B que cumplan con R.G.Nro. 1415",
|
18
|
+
"60"=>"Cta de Vta y Liquido prod. A",
|
19
|
+
"61"=>"Cta de Vta y Liquido prod. B",
|
20
|
+
"63"=>"Liquidacion A",
|
21
|
+
"64"=>"Liquidacion B"
|
22
|
+
}
|
23
|
+
|
24
|
+
CONCEPTOS = {"Productos"=>"01", "Servicios"=>"02", "Productos y Servicios"=>"03"}
|
25
|
+
|
26
|
+
DOCUMENTOS = {"CUIT"=>"80", "CUIL"=>"86", "CDI"=>"87", "LE"=>"89", "LC"=>"90", "CI Extranjera"=>"91", "en tramite"=>"92", "Acta Nacimiento"=>"93", "CI Bs. As. RNP"=>"95", "DNI"=>"96", "Pasaporte"=>"94", "Doc. (Otro)"=>"99"}
|
27
|
+
|
28
|
+
MONEDAS = {
|
29
|
+
:peso => {:codigo => "PES", :nombre =>"Pesos Argentinos"},
|
30
|
+
:dolar => {:codigo => "DOL", :nombre =>"Dolar Estadounidense"},
|
31
|
+
:real => {:codigo => "012", :nombre =>"Real"},
|
32
|
+
:euro => {:codigo => "060", :nombre =>"Euro"},
|
33
|
+
:oro => {:codigo => "049", :nombre =>"Gramos de Oro Fino"}
|
34
|
+
}
|
35
|
+
|
36
|
+
ALIC_IVA = [["03", 0],
|
37
|
+
["04", 0.105],
|
38
|
+
["05", 0.21],
|
39
|
+
["06", 0.27]]
|
40
|
+
|
41
|
+
BILL_TYPE = {:responsable_inscripto => {:responsable_inscripto => "01", :consumidor_final => "06"}}
|
42
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class Float
|
2
|
+
def round_with_precision(precision = nil)
|
3
|
+
precision.nil? ? round : (self * (10 ** precision)).round / (10 ** precision).to_f
|
4
|
+
end
|
5
|
+
def round_up_with_precision(precision = nil)
|
6
|
+
precision.nil? ? round : ((self * (10 ** precision)).round + 1) / (10 ** precision).to_f
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "AuthData" do
|
4
|
+
it "should create constants for todays data" do
|
5
|
+
Bravo::AuthData.fetch
|
6
|
+
if RUBY_VERSION >= "1.9"
|
7
|
+
Bravo.constants.should include(:TOKEN, :SIGN)
|
8
|
+
else
|
9
|
+
Bravo.constants.should include("TOKEN", "SIGN")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "Authorizer" do
|
4
|
+
it "should read credentials on initialize" do
|
5
|
+
authorizer = Bravo::Authorizer.new
|
6
|
+
authorizer.pkey.should == 'spec/fixtures/pkey'
|
7
|
+
authorizer.cert.should == 'spec/fixtures/cert.crt'
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "Bill" do
|
4
|
+
it "should setup a header hash" do
|
5
|
+
@header = Bravo::Bill.header(0)
|
6
|
+
@header.size.should == 3
|
7
|
+
["CantReg", "CbteTipo", "PtoVta"].each do |key|
|
8
|
+
@header.has_key?(key).should == true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "instance" do
|
13
|
+
before(:each) {@bill = Bravo::Bill.new}
|
14
|
+
|
15
|
+
it "should initialize according to Bravo defaults" do
|
16
|
+
@bill.client.class.name.should == "Savon::Client"
|
17
|
+
["Token", "Sign", "Cuit"].each do |key|
|
18
|
+
@bill.body["Auth"][key].should_not == nil
|
19
|
+
end
|
20
|
+
@bill.documento.should == Bravo.default_documento
|
21
|
+
@bill.moneda.should == Bravo.default_moneda
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should calculate it's cbte_tipo for Responsable Inscripto" do
|
25
|
+
@bill.iva_cond = :responsable_inscripto
|
26
|
+
@bill.cbte_type.should == "01"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should calculate it's cbte_tipo for Consumidor Final" do
|
30
|
+
@bill.iva_cond = :consumidor_final
|
31
|
+
@bill.cbte_type.should == "06"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "raise error on nil iva cond" do
|
35
|
+
@bill.iva_cond = 12
|
36
|
+
expect{@bill.cbte_type}.to raise_error(Bravo::NullOrInvalidAttribute)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should fetch non Peso currency's exchange rate" do
|
40
|
+
@bill.moneda = :dolar
|
41
|
+
@bill.exchange_rate.to_i.should be > 0
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return 1 for Peso currency" do
|
45
|
+
@bill.moneda = :peso
|
46
|
+
@bill.exchange_rate.should == 1
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should calculate the IVA array values" do
|
50
|
+
@bill.iva_cond = :responsable_inscripto
|
51
|
+
@bill.moneda = :peso
|
52
|
+
@bill.net = 100.89
|
53
|
+
@bill.aliciva_id = 2
|
54
|
+
|
55
|
+
@bill.iva_sum.should be_within(0.05).of(21.18)
|
56
|
+
@bill.total.should be_within(0.05).of(122.07)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should use give due date an service dates, or todays date" do
|
60
|
+
@bill.net = 100
|
61
|
+
@bill.aliciva_id = 2
|
62
|
+
@bill.doc_num = "30710151543"
|
63
|
+
@bill.iva_cond = :responsable_inscripto
|
64
|
+
@bill.concepto = "Servicios"
|
65
|
+
|
66
|
+
@bill.setup_bill
|
67
|
+
|
68
|
+
detail = @bill.body["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"]
|
69
|
+
|
70
|
+
detail["FchServDesde"].should == Time.new.strftime('%Y%m%d')
|
71
|
+
detail["FchServHasta"].should == Time.new.strftime('%Y%m%d')
|
72
|
+
detail["FchVtoPago"].should == Time.new.strftime('%Y%m%d')
|
73
|
+
|
74
|
+
@bill.due_date = Date.new(2011, 12, 10).strftime('%Y%m%d')
|
75
|
+
@bill.fch_serv_desde = Date.new(2011, 11, 01).strftime('%Y%m%d')
|
76
|
+
@bill.fch_serv_hasta = Date.new(2011, 11, 30).strftime('%Y%m%d')
|
77
|
+
|
78
|
+
@bill.setup_bill
|
79
|
+
|
80
|
+
detail = @bill.body["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"]
|
81
|
+
|
82
|
+
detail["FchServDesde"].should == "20111101"
|
83
|
+
detail["FchServHasta"].should == "20111130"
|
84
|
+
detail["FchVtoPago"].should == "20111210"
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should authorize a valid bill" do
|
88
|
+
@bill.net = 1000000
|
89
|
+
@bill.aliciva_id = 2
|
90
|
+
@bill.doc_num = "30710151543"
|
91
|
+
@bill.iva_cond = :responsable_inscripto
|
92
|
+
@bill.concepto = "Servicios"
|
93
|
+
|
94
|
+
@bill.authorized?.should == false
|
95
|
+
|
96
|
+
@bill.authorize.should == true
|
97
|
+
|
98
|
+
@bill.authorized?.should == true
|
99
|
+
@bill.response.cae.length.should == 14
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'bravo'
|
3
|
+
require 'rspec'
|
4
|
+
require 'ruby-debug'
|
5
|
+
|
6
|
+
class SpecHelper
|
7
|
+
include Savon::Logger
|
8
|
+
end
|
9
|
+
|
10
|
+
# Requires supporting files with custom matchers and macros, etc,
|
11
|
+
# in ./support/ and its subdirectories.
|
12
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
13
|
+
|
14
|
+
Savon::Request.log = false unless ENV["VERBOSE"] == "true"
|
15
|
+
|
16
|
+
Bravo.pkey = "spec/fixtures/pkey"
|
17
|
+
Bravo.cert = "spec/fixtures/cert.crt"
|
18
|
+
Bravo.cuit = ENV["CUIT"] || raise(Bravo::NullOrInvalidAttribute.new, "Please set CUIT env variable.")
|
19
|
+
Bravo.sale_point = "0002"
|
20
|
+
Bravo.service_url = "http://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL"
|
21
|
+
Bravo.default_concepto = "Productos y Servicios"
|
22
|
+
Bravo.default_documento = "CUIT"
|
23
|
+
Bravo.default_moneda = :peso
|
24
|
+
Bravo.own_iva_cond = :responsable_inscripto
|
data/wsaa-client.sh
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# FUNCTION: Bash script to get a TA from WSAA
|
3
|
+
# AUTHOR: Gerardo Fisanotti - AFIP/SDG-SI/DIITEC/DEARIN - 15-nov-2010
|
4
|
+
# Dependencies: curl, openssl >= 1.0, xmllint
|
5
|
+
#
|
6
|
+
# Modify following definitions according to your environment:
|
7
|
+
#
|
8
|
+
# URL=https://wsaahomo.afip.gov.ar/ws/services/LoginCms # WSAA URL
|
9
|
+
# KEY=spec/fixtures/pkey # file containing the private key in PEM format
|
10
|
+
# CRT=spec/fixtures/cert.crt # file containing the X.509 certificate in PEM format
|
11
|
+
TAFN="TA.xml" # file name of the output file
|
12
|
+
# modify next line if you need a proxy to get to the Internet or comment it out
|
13
|
+
# if you don't need a proxy
|
14
|
+
# export https_proxy="http://10.20.152.112:80"
|
15
|
+
#
|
16
|
+
# No further modifications should be needed below this line
|
17
|
+
#==============================================================================
|
18
|
+
function MakeTRA()
|
19
|
+
#
|
20
|
+
# Generate the XML containing the Access Ticket Request (TRA)
|
21
|
+
#
|
22
|
+
{
|
23
|
+
# FROM=$(date -j -f "%a %b %d %T %Z %Y" "`date -v0H -v0M -v0S`" "+%s")
|
24
|
+
# TO=$(date -j -f "%a %b %d %T %Z %Y" "`date -v23H -v59M -v59S`" "+%s")
|
25
|
+
FROM=$(date "+%Y-%m-%dT00:00:00-03:00")
|
26
|
+
TO=$(date "+%Y-%m-%dT23:59:59-03:00")
|
27
|
+
ID=$(date "+%s")
|
28
|
+
TRA=$(cat <<EOF
|
29
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
30
|
+
<loginTicketRequest version="1.0">
|
31
|
+
<header>
|
32
|
+
<uniqueId>$ID</uniqueId>
|
33
|
+
<generationTime>$FROM</generationTime>
|
34
|
+
<expirationTime>$TO</expirationTime>
|
35
|
+
</header>
|
36
|
+
<service>wsfe</service>
|
37
|
+
</loginTicketRequest>
|
38
|
+
EOF
|
39
|
+
)
|
40
|
+
}
|
41
|
+
#------------------------------------------------------------------------------
|
42
|
+
function MakeCMS()
|
43
|
+
#
|
44
|
+
# Generate de CMS container (TRA + sign + certificate)
|
45
|
+
#
|
46
|
+
{
|
47
|
+
CMS=$(
|
48
|
+
echo "$TRA" |
|
49
|
+
/usr/local/ssl/bin/openssl cms -sign -in /dev/stdin -signer $CRT -inkey $KEY -nodetach \
|
50
|
+
-outform der |
|
51
|
+
/usr/local/ssl/bin/openssl base64 -e
|
52
|
+
)
|
53
|
+
}
|
54
|
+
#------------------------------------------------------------------------------
|
55
|
+
function MakeSOAPrequest()
|
56
|
+
#
|
57
|
+
# Generate the SOAP request XML
|
58
|
+
#
|
59
|
+
{
|
60
|
+
REQUEST=$(cat <<EOF
|
61
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
62
|
+
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://wsaa.view.sua.dvadac.desein.afip.gov">
|
63
|
+
<SOAP-ENV:Body>
|
64
|
+
<ns1:loginCms>
|
65
|
+
<ns1:in0>
|
66
|
+
$CMS
|
67
|
+
</ns1:in0>
|
68
|
+
</ns1:loginCms>
|
69
|
+
</SOAP-ENV:Body>
|
70
|
+
</SOAP-ENV:Envelope>
|
71
|
+
EOF
|
72
|
+
)
|
73
|
+
}
|
74
|
+
#------------------------------------------------------------------------------
|
75
|
+
function CallWSAA()
|
76
|
+
#
|
77
|
+
# Invoke WSAA sending SOAP request XML to LoginCMS method
|
78
|
+
#
|
79
|
+
{
|
80
|
+
RESPONSE=$(
|
81
|
+
echo "$REQUEST" |
|
82
|
+
curl -k -H 'Content-Type: application/soap+xml; action=""' -d @- $URL
|
83
|
+
)
|
84
|
+
echo "$REQUEST"
|
85
|
+
}
|
86
|
+
#------------------------------------------------------------------------------
|
87
|
+
function ParseTA()
|
88
|
+
#
|
89
|
+
# Try to parse the results obtained from WSAA
|
90
|
+
#
|
91
|
+
{
|
92
|
+
TOKEN=$(
|
93
|
+
echo "$RESPONSE" |
|
94
|
+
grep token |
|
95
|
+
sed -e 's/<token>//' |
|
96
|
+
sed -e 's/<\/token>//' |
|
97
|
+
sed -e 's/ //g'
|
98
|
+
)
|
99
|
+
SIGN=$(
|
100
|
+
echo "$RESPONSE" |
|
101
|
+
grep sign |
|
102
|
+
sed -e 's/<sign>//' |
|
103
|
+
sed -e 's/<\/sign>//' |
|
104
|
+
sed -e 's/ //g'
|
105
|
+
)
|
106
|
+
# If we did not get TOKEN, then it was a SOAP Fault, show the error message
|
107
|
+
# and exit
|
108
|
+
#
|
109
|
+
if [ "$TOKEN" == "" ]
|
110
|
+
then
|
111
|
+
echo "ERROR: "
|
112
|
+
echo "$(echo "$RESPONSE" | xmllint --format - | grep faultstring)"
|
113
|
+
exit 1
|
114
|
+
fi
|
115
|
+
}
|
116
|
+
#------------------------------------------------------------------------------
|
117
|
+
function WriteTA()
|
118
|
+
#
|
119
|
+
# Write the token and sign to the output file
|
120
|
+
#
|
121
|
+
{
|
122
|
+
cat <<EOF > $TAFN
|
123
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
124
|
+
<loginTicketResponse version="1">
|
125
|
+
<credentials>
|
126
|
+
<token>$TOKEN</token>
|
127
|
+
<sign>$SIGN</sign>
|
128
|
+
</credentials>
|
129
|
+
</loginTicketResponse>
|
130
|
+
EOF
|
131
|
+
}
|
132
|
+
|
133
|
+
function WriteYAML()
|
134
|
+
{
|
135
|
+
cat <<EOF > /tmp/bravo_$(date +"%d_%m_%Y").yml
|
136
|
+
token: '$TOKEN'
|
137
|
+
sign: '$SIGN'
|
138
|
+
EOF
|
139
|
+
}
|
140
|
+
#------------------------------------------------------------------------------
|
141
|
+
#
|
142
|
+
# MAIN program
|
143
|
+
#
|
144
|
+
# If we were invoked with a service name in arg #1, use it
|
145
|
+
#[ $# -eq 1 ] && SERVICE=$1
|
146
|
+
# otherwise, ask for it
|
147
|
+
#[ $# -eq 0 ] && read -p "Service name: " SERVICE
|
148
|
+
|
149
|
+
# Parse commandline arguments
|
150
|
+
while getopts 'k:u:c:' OPTION
|
151
|
+
do
|
152
|
+
case $OPTION in
|
153
|
+
c) CRT=$OPTARG
|
154
|
+
;;
|
155
|
+
k) KEY=$OPTARG
|
156
|
+
;;
|
157
|
+
u) URL=$OPTARG
|
158
|
+
;;
|
159
|
+
esac
|
160
|
+
done
|
161
|
+
shift $(($OPTIND - 1))
|
162
|
+
MakeTRA # Generate TRA
|
163
|
+
MakeCMS # Generate CMS (TRA + signature + certificate)
|
164
|
+
MakeSOAPrequest # Generate the SOAP request XML
|
165
|
+
CallWSAA # Invoke WSAA sending SOAP request
|
166
|
+
ParseTA # Parse the WSAA SOAP response, extract Token and Sign
|
167
|
+
# WriteTA # Write an abbreviated TA.xml with Token and Sign only
|
168
|
+
WriteYAML
|
169
|
+
echo "Access Ticket acquired, written to: $TAFN" # Inform success and exit
|
170
|
+
echo $REQUEST
|
171
|
+
echo $TRA
|
metadata
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bravo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Leandro Marcucci
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-03-02 00:00:00 -03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: savon
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 19
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 7
|
33
|
+
- 8
|
34
|
+
version: 0.7.8
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: ruby-debug
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: ruby-debug-base19
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - "="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
- 11
|
63
|
+
- 24
|
64
|
+
version: 0.11.24
|
65
|
+
type: :development
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: ruby-debug19
|
69
|
+
prerelease: false
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - "="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 63
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
- 11
|
79
|
+
- 6
|
80
|
+
version: 0.11.6
|
81
|
+
type: :development
|
82
|
+
version_requirements: *id004
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
prerelease: false
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ~>
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 31
|
92
|
+
segments:
|
93
|
+
- 2
|
94
|
+
- 4
|
95
|
+
- 0
|
96
|
+
version: 2.4.0
|
97
|
+
type: :development
|
98
|
+
version_requirements: *id005
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: bundler
|
101
|
+
prerelease: false
|
102
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ~>
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
hash: 23
|
108
|
+
segments:
|
109
|
+
- 1
|
110
|
+
- 0
|
111
|
+
- 0
|
112
|
+
version: 1.0.0
|
113
|
+
type: :development
|
114
|
+
version_requirements: *id006
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: jeweler
|
117
|
+
prerelease: false
|
118
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ~>
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
hash: 1
|
124
|
+
segments:
|
125
|
+
- 1
|
126
|
+
- 5
|
127
|
+
- 1
|
128
|
+
version: 1.5.1
|
129
|
+
type: :development
|
130
|
+
version_requirements: *id007
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: rcov
|
133
|
+
prerelease: false
|
134
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
135
|
+
none: false
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
hash: 3
|
140
|
+
segments:
|
141
|
+
- 0
|
142
|
+
version: "0"
|
143
|
+
type: :development
|
144
|
+
version_requirements: *id008
|
145
|
+
description: Adaptador para el Web Service de Facturacion Electronica de AFIP
|
146
|
+
email: leanucci@vurbia.com
|
147
|
+
executables: []
|
148
|
+
|
149
|
+
extensions: []
|
150
|
+
|
151
|
+
extra_rdoc_files:
|
152
|
+
- LICENSE.txt
|
153
|
+
- README.textile
|
154
|
+
files:
|
155
|
+
- .document
|
156
|
+
- Gemfile
|
157
|
+
- Gemfile.lock
|
158
|
+
- LICENSE.txt
|
159
|
+
- README.textile
|
160
|
+
- Rakefile
|
161
|
+
- VERSION
|
162
|
+
- autotest/discover.rb
|
163
|
+
- bravo.gemspec
|
164
|
+
- lib/bravo.rb
|
165
|
+
- lib/bravo/auth_data.rb
|
166
|
+
- lib/bravo/authorizer.rb
|
167
|
+
- lib/bravo/bill.rb
|
168
|
+
- lib/bravo/constants.rb
|
169
|
+
- lib/bravo/core_ext/float.rb
|
170
|
+
- lib/bravo/version.rb
|
171
|
+
- spec/bravo/auth_data_spec.rb
|
172
|
+
- spec/bravo/authorizer_spec.rb
|
173
|
+
- spec/bravo/bill_spec.rb
|
174
|
+
- spec/spec_helper.rb
|
175
|
+
- wsaa-client.sh
|
176
|
+
has_rdoc: true
|
177
|
+
homepage: http://github.com/leanucci/bravo
|
178
|
+
licenses:
|
179
|
+
- MIT
|
180
|
+
post_install_message:
|
181
|
+
rdoc_options: []
|
182
|
+
|
183
|
+
require_paths:
|
184
|
+
- lib
|
185
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
186
|
+
none: false
|
187
|
+
requirements:
|
188
|
+
- - ">="
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
hash: 3
|
191
|
+
segments:
|
192
|
+
- 0
|
193
|
+
version: "0"
|
194
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
|
+
none: false
|
196
|
+
requirements:
|
197
|
+
- - ">="
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
hash: 3
|
200
|
+
segments:
|
201
|
+
- 0
|
202
|
+
version: "0"
|
203
|
+
requirements: []
|
204
|
+
|
205
|
+
rubyforge_project:
|
206
|
+
rubygems_version: 1.6.0
|
207
|
+
signing_key:
|
208
|
+
specification_version: 3
|
209
|
+
summary: Adaptador AFIP wsfe.
|
210
|
+
test_files:
|
211
|
+
- spec/bravo/auth_data_spec.rb
|
212
|
+
- spec/bravo/authorizer_spec.rb
|
213
|
+
- spec/bravo/bill_spec.rb
|
214
|
+
- spec/spec_helper.rb
|