Afip 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e1fef6401f70f1aa4f436f9fee2f20682c85d35aea797239d0890b5747afe61
4
- data.tar.gz: 9931112f5438e38fe67081d8a46f4a3b71806e46b5b04bd4ad9a657e878a4869
3
+ metadata.gz: 423fa3ea9b764029af3e4c7910def5a4f5037125ddc481dd55fa3daa41ee66ae
4
+ data.tar.gz: 04d2a8faaed0d63660f65f0c04ea19b8294cc1c1a21c0e2b9d8a2599b68798d9
5
5
  SHA512:
6
- metadata.gz: a888a80c727ce902d464658002a87e76ad020afac39f45f9be17cf59f2dffe27a0d9a0b89d33892768461282b6bdfd45aeaf4a45894ef45f73c7639f07d5a96d
7
- data.tar.gz: 2bbcef8872130a42eb63d0e9b1120bc94f36c89c3cfa8d1727b661e83526a619ae4572978d996231165afce6f8e8a81c50f774700b58cfe9919e68bb8d46ecd1
6
+ metadata.gz: f4533a6716f515077477e543a39079a6a84768553b9e65d52f4c49d5c88d6075abe84f9caebf790e3c7ec6c25c4281301f697d8009fa4d76c4901e0a8c3ddd62
7
+ data.tar.gz: 560c2dea89ed78fc6d98a9e55dd1c60ed44e3c5c4e3df27c32b52c5bccc9261049f15a1eee28952867624c5ce6e599aabf972a4463f84e0190a858961daeea0e
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Afip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Facundo A. Díaz Martínez
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-07 00:00:00.000000000 Z
11
+ date: 2018-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: savon
@@ -72,31 +72,7 @@ email:
72
72
  executables: []
73
73
  extensions: []
74
74
  extra_rdoc_files: []
75
- files:
76
- - ".DS_Store"
77
- - ".gitignore"
78
- - Afip.gemspec
79
- - Gemfile
80
- - Gemfile.lock
81
- - LICENSE.txt
82
- - README.md
83
- - Rakefile
84
- - bin/console
85
- - bin/setup
86
- - lib/.DS_Store
87
- - lib/Afip.rb
88
- - lib/Afip/.DS_Store
89
- - lib/Afip/auth_data.rb
90
- - lib/Afip/authorizer.rb
91
- - lib/Afip/bill.rb
92
- - lib/Afip/constants.rb
93
- - lib/Afip/core_ext/float.rb
94
- - lib/Afip/core_ext/hash.rb
95
- - lib/Afip/core_ext/string.rb
96
- - lib/Afip/ctg.rb
97
- - lib/Afip/padron.rb
98
- - lib/Afip/version.rb
99
- - lib/Afip/wsaa.rb
75
+ files: []
100
76
  homepage: https://www.desideral.com
101
77
  licenses:
102
78
  - MIT
@@ -118,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
94
  version: '0'
119
95
  requirements: []
120
96
  rubyforge_project:
121
- rubygems_version: 2.7.6
97
+ rubygems_version: 2.7.8
122
98
  signing_key:
123
99
  specification_version: 4
124
100
  summary: Comunicacion con AFIP
data/.DS_Store DELETED
Binary file
data/.gitignore DELETED
@@ -1,8 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
data/Afip.gemspec DELETED
@@ -1,39 +0,0 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "Afip/version"
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "Afip"
8
- spec.version = Afip::VERSION
9
- spec.authors = ["Facundo A. Díaz Martínez"]
10
- spec.email = ["facundo_diaz_martinez@hotmail.com"]
11
-
12
- spec.summary = %q{Comunicacion con AFIP}
13
- spec.description = %q{Gema para la comunicacion con los Web Services de AFIP.}
14
- spec.homepage = "https://www.desideral.com"
15
- spec.license = "MIT"
16
-
17
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
- # to allow pushing to a single host or delete this section to allow pushing to any host.
19
- if spec.respond_to?(:metadata)
20
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
21
- else
22
- raise "RubyGems 2.0 or newer is required to protect against " \
23
- "public gem pushes."
24
- end
25
-
26
- # Specify which files should be added to the gem when it is released.
27
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
28
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
29
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
30
- end
31
- spec.bindir = "exe"
32
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33
- spec.require_paths = ["lib"]
34
-
35
- spec.add_dependency "savon"
36
- spec.add_dependency "httpi"
37
- spec.add_development_dependency "bundler", "~> 1.16"
38
- spec.add_development_dependency "rake", "~> 10.0"
39
- end
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
-
5
- # Specify your gem's dependencies in Afip.gemspec
6
- gemspec
data/Gemfile.lock DELETED
@@ -1,48 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- Afip (0.8.0)
5
- httpi
6
- savon
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- akami (1.3.1)
12
- gyoku (>= 0.4.0)
13
- nokogiri
14
- builder (3.2.3)
15
- gyoku (1.3.1)
16
- builder (>= 2.1.2)
17
- httpi (2.4.4)
18
- rack
19
- socksify
20
- mini_portile2 (2.3.0)
21
- nokogiri (1.8.5)
22
- mini_portile2 (~> 2.3.0)
23
- nori (2.6.0)
24
- rack (2.0.6)
25
- rake (10.5.0)
26
- savon (2.12.0)
27
- akami (~> 1.2)
28
- builder (>= 2.1.2)
29
- gyoku (~> 1.2)
30
- httpi (~> 2.3)
31
- nokogiri (>= 1.8.1)
32
- nori (~> 2.4)
33
- wasabi (~> 3.4)
34
- socksify (1.7.1)
35
- wasabi (3.5.0)
36
- httpi (~> 2.0)
37
- nokogiri (>= 1.4.2)
38
-
39
- PLATFORMS
40
- ruby
41
-
42
- DEPENDENCIES
43
- Afip!
44
- bundler (~> 1.16)
45
- rake (~> 10.0)
46
-
47
- BUNDLED WITH
48
- 1.17.1
data/LICENSE.txt DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2018 Facundo A. Díaz Martínez
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
data/README.md DELETED
@@ -1,39 +0,0 @@
1
- # Afip
2
-
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/Afip`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
6
-
7
- ## Installation
8
-
9
- Add this line to your application's Gemfile:
10
-
11
- ```ruby
12
- gem 'Afip'
13
- ```
14
-
15
- And then execute:
16
-
17
- $ bundle
18
-
19
- Or install it yourself as:
20
-
21
- $ gem install Afip
22
-
23
- ## Usage
24
-
25
- TODO: Write usage instructions here
26
-
27
- ## Development
28
-
29
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
-
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
-
33
- ## Contributing
34
-
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/Afip.
36
-
37
- ## License
38
-
39
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile DELETED
@@ -1,2 +0,0 @@
1
- require "bundler/gem_tasks"
2
- task :default => :spec
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "Afip"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
data/lib/.DS_Store DELETED
Binary file
data/lib/Afip.rb DELETED
@@ -1,59 +0,0 @@
1
- require "Afip/version"
2
- require "bundler/setup"
3
- require "Afip/constants"
4
- require "savon"
5
- require "Afip/core_ext/float"
6
- require "Afip/core_ext/hash"
7
- require "Afip/core_ext/string"
8
-
9
- require 'net/http'
10
- require 'net/https'
11
-
12
- #require 'net/http'
13
- require 'net/https'
14
- module Afip
15
-
16
- class NullOrInvalidAttribute < StandardError; end
17
-
18
- def self.root
19
- File.expand_path '../..', __FILE__
20
- end
21
-
22
- autoload :Authorizer, "Afip/authorizer"
23
- autoload :AuthData, "Afip/auth_data"
24
- autoload :Padron, "Afip/padron"
25
- autoload :Wsaa, "Afip/wsaa"
26
- autoload :Bill, "Afip/bill"
27
- autoload :CTG, "Afip/ctg"
28
-
29
-
30
- class << self
31
- mattr_accessor :cuit, :pkey, :cert, :environment, :openssl_bin,
32
- :default_concepto, :default_documento, :default_moneda, :own_iva_cond, :service_url, :auth_url
33
- end
34
-
35
- def self.setup(&block)
36
- yield self
37
- end
38
-
39
- extend self
40
-
41
- def auth_hash(service = "wsfe")
42
- case service
43
- when "wsfe"
44
- { 'Token' => Afip::TOKEN, 'Sign' => Afip::SIGN, 'Cuit' => Afip.cuit }
45
- when "ws_sr_padron_a4"
46
- { 'token' => Afip::TOKEN, 'sign' => Afip::SIGN, 'cuitRepresentado' => Afip.cuit }
47
- when "wsctg"
48
- { 'token' => Afip::TOKEN, 'sign' => Afip::SIGN, 'cuitRepresentado' => Afip.cuit }
49
- end
50
- end
51
-
52
- def log?
53
- Afip.verbose || ENV["VERBOSE"]
54
- end
55
-
56
- def deleteToken
57
- AuthData.deleteToken
58
- end
59
- end
data/lib/Afip/.DS_Store DELETED
Binary file
@@ -1,71 +0,0 @@
1
- module Afip
2
-
3
- # This class handles authorization data
4
- #
5
- class AuthData
6
-
7
- class << self
8
-
9
- attr_accessor :environment, :todays_data_file_name
10
-
11
- # Fetches WSAA Authorization Data to build the datafile for the day.
12
- # It requires the private key file and the certificate to exist and
13
- # to be configured as Afip.pkey and Afip.cert
14
- #
15
- def fetch(service = "wsfe")
16
- unless File.exists?(Afip.pkey)
17
- raise "Archivo de llave privada no encontrado en #{ Afip.pkey }"
18
- end
19
-
20
- unless File.exists?(Afip.cert)
21
- raise "Archivo certificado no encontrado en #{ Afip.cert }"
22
- end
23
-
24
- unless File.exists?(todays_data_file_name)
25
- Afip::Wsaa.login(service)
26
- end
27
-
28
- YAML.load_file(todays_data_file_name).each do |k, v|
29
- Afip.const_set(k.to_s.upcase, v) unless Afip.const_defined?(k.to_s.upcase)
30
- end
31
- end
32
-
33
- # Returns the authorization hash, containing the Token, Signature and Cuit
34
- # @return [Hash]
35
- #
36
- def auth_hash(service = "wsfe")
37
- fetch unless Afip.constants.include?(:TOKEN) && Afip.constants.include?(:SIGN)
38
- case service
39
- when "wsfe"
40
- { 'Token' => Afip::TOKEN, 'Sign' => Afip::SIGN, 'Cuit' => Afip.cuit }
41
- when "ws_sr_padron_a4"
42
- { 'token' => Afip::TOKEN, 'sign' => Afip::SIGN, 'cuitRepresentado' => Afip.cuit }
43
- when "wsctg"
44
- { 'token' => Afip::TOKEN, 'sign' => Afip::SIGN, 'cuitRepresentado' => Afip.cuit }
45
- end
46
- end
47
-
48
- # Returns the right wsaa url for the specific environment
49
- # @return [String]
50
- #
51
- def wsaa_url
52
- Afip::URLS[Afip.environment][:wsaa]
53
- end
54
-
55
- # Returns the right wsfe url for the specific environment
56
- # @return [String]
57
- #
58
- def wsfe_url
59
- raise 'Environment not sent to either :test or :production' unless Afip::URLS.keys.include? environment
60
- Afip::URLS[Afip.environment][:wsfe]
61
- end
62
-
63
- # Creates the data file name for a cuit number and the current day
64
- # @return [String]
65
- #
66
- def todays_data_file_name
67
- @todays_data_file = "/tmp/#{environment.to_s}_Afip_#{ Afip.cuit }_#{ Time.new.strftime('%Y_%m_%d') }.yml"
68
- end
69
- end
70
- end
71
- end
@@ -1,10 +0,0 @@
1
- module Afip
2
- class Authorizer
3
- attr_reader :pkey, :cert
4
-
5
- def initialize
6
- @pkey = Afip.pkey
7
- @cert = Afip.cert
8
- end
9
- end
10
- end
data/lib/Afip/bill.rb DELETED
@@ -1,193 +0,0 @@
1
- module Afip
2
- class Bill
3
- attr_reader :cbte_type, :body, :response, :fecha_emision, :total, :client
4
- attr_accessor :net, :doc_num, :iva_cond, :documento, :concepto, :moneda,
5
- :due_date, :fch_serv_desde, :fch_serv_hasta, :fch_emision,
6
- :ivas, :sale_point
7
-
8
- def initialize(attrs={})
9
- Bill.set_client
10
- @sale_point = attrs[:sale_point]
11
- @body = { "Auth" => Afip.auth_hash }
12
- @net = attrs[:net] || 0
13
- @documento = attrs[:documento] || Afip.default_documento
14
- @moneda = attrs[:moneda] || Afip.default_moneda
15
- @iva_cond = attrs[:iva_cond]
16
- @concepto = attrs[:concepto] || Afip.default_concepto
17
- @ivas = attrs[:ivas] || Array.new # [ 1, 100.00, 10.50 ], [ 2, 100.00, 21.00 ]
18
- @fecha_emision = attrs[:fch_emision] || Time.new
19
- @cbte_type = Afip::BILL_TYPE[Afip.own_iva_cond][iva_cond]
20
- @total = net.zero? ? 0 : net + iva_sum
21
- end
22
-
23
- def self.get_ptos_vta
24
- client = set_client
25
- body = { "Auth" => Afip.auth_hash }
26
- response = client.call(:fe_param_get_ptos_venta, message: body)
27
- if response.body[:fe_param_get_ptos_venta_response][:fe_param_get_ptos_venta_result][:errors].nil?
28
- if response.body[:fe_param_get_ptos_venta_response][:fe_param_get_ptos_venta_result][:result_get][:pto_venta].is_a?(Hash)
29
- response.body[:fe_param_get_ptos_venta_response][:fe_param_get_ptos_venta_result][:result_get][:pto_venta][:nro]
30
- else
31
- response.body[:fe_param_get_ptos_venta_response][:fe_param_get_ptos_venta_result][:result_get][:pto_venta].map{|r| r[:nro]}
32
- end
33
- else
34
- []
35
- end
36
- end
37
-
38
- def self.set_client
39
- Afip::AuthData.fetch
40
- @client = Savon.client(
41
- wsdl: Afip.service_url,
42
- namespaces: { "xmlns" => "http://ar.gov.afip.dif.FEV1/" },
43
- log_level: :debug,
44
- ssl_cert_key_file: Afip.pkey,
45
- ssl_cert_file: Afip.cert,
46
- ssl_verify_mode: :none,
47
- read_timeout: 90,
48
- open_timeout: 90,
49
- headers: { "Accept-Encoding" => "gzip, deflate", "Connection" => "Keep-Alive" }
50
- )
51
- end
52
-
53
- def authorize
54
- body = setup_bill
55
- response = client.call(:fecae_solicitar, message: body)
56
- setup_response(response.to_hash)
57
- authorized?
58
- end
59
-
60
- def setup_bill
61
- array_ivas = Array.new
62
- ivas.each{ |i|
63
- array_ivas << {
64
- "Id" => i[0],
65
- "BaseImp" => i[1].round(2),
66
- "Importe" => i[2].round(2) }
67
- }
68
-
69
- fecaereq = {
70
- "FeCAEReq" => {
71
- "FeCabReq" => Afip::Bill.header(cbte_type, sale_point),
72
- "FeDetReq" => {
73
- "FECAEDetRequest" => {
74
- "Concepto" => Afip::CONCEPTOS[concepto],
75
- "DocTipo" => Afip::DOCUMENTOS[documento],
76
- "DocNro" => doc_num,
77
- "CbteFch" => fecha_emision.strftime('%Y%m%d'),
78
- "ImpTotConc" => 0.00,
79
- "ImpNeto" => net.to_f,
80
- "MonId" => Afip::MONEDAS[moneda][:codigo],
81
- "MonCotiz" => exchange_rate,
82
- "ImpOpEx" => 0.00,
83
- "ImpTrib" => 0.00,
84
- "ImpTotal" => (Afip.own_iva_cond == :responsable_monotributo ? net : total).to_f.round(2),
85
- "CbteDesde" => next_bill_number,
86
- "CbteHasta" => next_bill_number
87
- }
88
- }
89
- }
90
- }
91
-
92
- detail = fecaereq["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"]
93
-
94
- if (Afip.own_iva_cond == :responsable_inscripto)
95
- detail["ImpIVA"] = iva_sum
96
- detail["Iva"] = { "AlicIva" => array_ivas }
97
- end
98
-
99
- unless concepto == "Productos" # En "Productos" ("01"), si se mandan estos parámetros la afip rechaza.
100
- detail.merge!({"FchServDesde" => fch_serv_desde,
101
- "FchServHasta" => fch_serv_hasta,
102
- "FchVtoPago" => due_date})
103
- end
104
-
105
- body.merge!(fecaereq)
106
- end
107
-
108
- def self.header(cbte_type, sale_point)
109
- {"CantReg" => "1", "CbteTipo" => cbte_type, "PtoVta" => sale_point}
110
- end
111
-
112
- def exchange_rate
113
- return 1 if moneda == :peso
114
- response = client.call :fe_param_get_cotizacion do
115
- message = body.merge!({"MonId" => Afip::MONEDAS[moneda][:codigo]})
116
- end
117
- response.to_hash[:fe_param_get_cotizacion_response][:fe_param_get_cotizacion_result][:result_get][:mon_cotiz].to_f
118
- end
119
-
120
- def iva_sum
121
- iva_sum = 0.0
122
- self.ivas.each{ |i|
123
- iva_sum += i[2]
124
- }
125
- return iva_sum.round(2)
126
- end
127
-
128
- def next_bill_number
129
- var = {"Auth" => Afip.auth_hash, "PtoVta" => sale_point, "CbteTipo" => cbte_type}
130
- resp = client.call :fe_comp_ultimo_autorizado do
131
- message(var)
132
- end
133
-
134
- resp.to_hash[:fe_comp_ultimo_autorizado_response][:fe_comp_ultimo_autorizado_result][:cbte_nro].to_i + 1
135
- end
136
-
137
- def setup_response(response)
138
- # TODO: turn this into an all-purpose Response class
139
-
140
- result = response[:fecae_solicitar_response][:fecae_solicitar_result]
141
-
142
- if not result[:fe_det_resp] or not result[:fe_cab_resp] then
143
- # Si no obtuvo respuesta ni cabecera ni detalle, evito hacer '[]' sobre algo indefinido.
144
- # Ejemplo: Error con el token-sign de WSAA
145
- keys, values = {
146
- :errores => result[:errors],
147
- :header_result => {:resultado => "X" },
148
- :observaciones => nil
149
- }.to_a.transpose
150
- @response = (defined?(Struct::ResponseMal) ? Struct::ResponseMal : Struct.new("ResponseMal", *keys)).new(*values)
151
- return
152
- end
153
-
154
- response_header = result[:fe_cab_resp]
155
- response_detail = result[:fe_det_resp][:fecae_det_response]
156
-
157
- request_header = body["FeCAEReq"]["FeCabReq"].underscore_keys.symbolize_keys
158
- request_detail = body["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"].underscore_keys.symbolize_keys
159
-
160
- # Esto no funciona desde que se soportan múltiples alícuotas de iva simultáneas
161
- # FIX ? TO-DO
162
- # iva = request_detail.delete(:iva)["AlicIva"].underscore_keys.symbolize_keys
163
- # request_detail.merge!(iva)
164
-
165
- if result[:errors] then
166
- response_detail.merge!( result[:errors] )
167
- end
168
-
169
- response_hash = {
170
- :header_result => response_header.delete(:resultado),
171
- :authorized_on => response_header.delete(:fch_proceso),
172
- :detail_result => response_detail.delete(:resultado),
173
- :cae_due_date => response_detail.delete(:cae_fch_vto),
174
- :cae => response_detail.delete(:cae),
175
- :iva_id => request_detail.delete(:id),
176
- :iva_importe => request_detail.delete(:importe),
177
- :moneda => request_detail.delete(:mon_id),
178
- :cotizacion => request_detail.delete(:mon_cotiz),
179
- :iva_base_imp => request_detail.delete(:base_imp),
180
- :doc_num => request_detail.delete(:doc_nro),
181
- :observaciones => response_detail.delete(:observaciones),
182
- :errores => response_detail.delete(:err)
183
- }.merge!(request_header).merge!(request_detail)
184
-
185
- keys, values = response_hash.to_a.transpose
186
- @response = (defined?(Struct::Response) ? Struct::Response : Struct.new("Response", *keys)).new(*values)
187
- end
188
-
189
- def authorized?
190
- !response.nil? && response.header_result == "A" && response.detail_result == "A"
191
- end
192
- end
193
- end
@@ -1,80 +0,0 @@
1
- module Afip
2
- CBTE_TIPO = {
3
- "01"=>"Factura A",
4
- "02"=>"Nota de Débito A",
5
- "03"=>"Nota de Crédito A",
6
- "06"=>"Factura B",
7
- "07"=>"Nota de Debito B",
8
- "08"=>"Nota de Credito B",
9
- "11"=>"Factura C",
10
- "12"=>"Nota de Debito C",
11
- "13"=>"Nota de Credito C"
12
- }
13
-
14
- CONCEPTOS = {"Productos"=>"01", "Servicios"=>"02", "Productos y Servicios"=>"03"}
15
-
16
- 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"}
17
-
18
- MONEDAS = {
19
- :peso => {:codigo => "PES", :nombre =>"Pesos Argentinos"},
20
- :dolar => {:codigo => "DOL", :nombre =>"Dolar Estadounidense"},
21
- :real => {:codigo => "012", :nombre =>"Real"},
22
- :euro => {:codigo => "060", :nombre =>"Euro"},
23
- :oro => {:codigo => "049", :nombre =>"Gramos de Oro Fino"}
24
- }
25
-
26
- ALIC_IVA = [["03", 0], ["04", 0.105], ["05", 0.21], ["06", 0.27]]
27
-
28
- IVA_COND = ["Responsable Inscripto", "Responsable Monotributo"]
29
-
30
- BILL_TYPE = {
31
- :responsable_inscripto => {
32
- :responsable_inscripto => "01",
33
- :consumidor_final => "06",
34
- :exento => "06",
35
- :responsable_monotributo => "06",
36
- :nota_credito_a => "03",
37
- :nota_credito_b => "08",
38
- :nota_debito_a => "02",
39
- :nota_debito_b => "07"
40
- },
41
- :responsable_monotributo => {
42
- :responsable_inscripto => "11",
43
- :consumidor_final => "11",
44
- :exento => "11",
45
- :responsable_monotributo => "11",
46
- :nota_credito_c => "13",
47
- :nota_debito_c => "12"
48
- }
49
- }
50
-
51
- AVAILABLE_TYPES = {
52
- :responsable_inscripto => {
53
- :responsable_inscripto => ["01", "02", "03"],
54
- :consumidor_final => ["06", "07", "08"],
55
- :exento => ["06", "07", "08"],
56
- :responsable_monotributo => ["06", "07", "08"],
57
- },
58
- :responsable_monotributo => {
59
- :responsable_inscripto => ["11", "12", "13"],
60
- :consumidor_final => ["11", "12", "13"],
61
- :exento => ["11", "12", "13"],
62
- :responsable_monotributo => ["11", "12", "13"]
63
- }
64
- }
65
-
66
- URLS =
67
- {
68
- :test => {
69
- :wsaa => 'https://wsaahomo.afip.gov.ar/ws/services/LoginCms',
70
- :padron => "https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA5?WSDL",
71
- :wsfe => 'https://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL'
72
- },
73
- :production => {
74
- :wsaa => 'https://wsaa.afip.gov.ar/ws/services/LoginCms',
75
- :padron => "https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA5?WSDL",
76
- :wsfe => 'https://servicios1.afip.gov.ar/wsfev1/service.asmx'
77
- }
78
- }
79
-
80
- end
@@ -1,8 +0,0 @@
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
@@ -1,23 +0,0 @@
1
- class Hash
2
- def symbolize_keys!
3
- keys.each do |key|
4
- self[(key.to_sym rescue key) || key] = delete(key)
5
- end
6
- self
7
- end unless method_defined?(:symbolize_keys!)
8
-
9
- def symbolize_keys
10
- dup.symbolize_keys!
11
- end unless method_defined?(:symbolize_keys)
12
-
13
- def underscore_keys!
14
- keys.each do |key|
15
- self[(key.underscore rescue key) || key] = delete(key)
16
- end
17
- self
18
- end unless method_defined?(:underscore_keys!)
19
-
20
- def underscore_keys
21
- dup.underscore_keys!
22
- end unless method_defined?(:underscore_keys)
23
- end
@@ -1,12 +0,0 @@
1
- # Stolen from activesupport/lib/active_support/inflector/methods.rb, line 48
2
- class String
3
- def underscore
4
- word = self.to_s.dup
5
- word.gsub!(/::/, '/')
6
- word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
7
- word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
8
- word.tr!("-", "_")
9
- word.downcase!
10
- word
11
- end
12
- end
data/lib/Afip/ctg.rb DELETED
@@ -1,234 +0,0 @@
1
- module Afip
2
- class CTG
3
- attr_reader :client, :base_imp, :total
4
- attr_accessor :ctg_num, :cp_num, :cod_especie, :cuit_canjeador,:rccc, :cuit_destino, :cuit_destinatario, :localidad_origen, :localidad_destino,
5
- :cosecha, :peso, :cuit_transportista, :horas, :patente, :km, :cuit_corredor, :remitente_com, :body
6
-
7
- def initialize(attrs = {})
8
- Afip::AuthData.fetch("wsctg")
9
- @client = Savon.client(
10
- ssl_cert_key_file: Afip.pkey,
11
- ssl_cert_file: Afip.cert,
12
- env_namespace: :soapenv,
13
- namespace_identifier: :ctg,
14
- log: true,
15
- logger: Rails.logger,
16
- log_level: :debug,
17
- pretty_print_xml: true,
18
- encoding: 'UTF-8',
19
- ssl_version: :TLSv1,
20
- wsdl: Afip.service_url
21
- )
22
-
23
- @ctg_num = attrs[:ctg_num]
24
- @cp_num = attrs[:cp_num]
25
- @cod_especie = attrs[:cod_especie]
26
- @cuit_canjeador = attrs[:cuit_canjeador]
27
- @rccc = attrs[:rccc]
28
- @cuit_destino = attrs[:cuit_destino]
29
- @cuit_destinatario = attrs[:cuit_destinatario]
30
- @localidad_origen = attrs[:localidad_origen]
31
- @localidad_destino = attrs[:localidad_destino]
32
- @cosecha = attrs[:cosecha]
33
- @peso = attrs[:peso]
34
- @cuit_transportista = attrs[:cuit_transportista]
35
- @horas = attrs[:horas]
36
- @patente = attrs[:patente]
37
- @km = attrs[:km]
38
- @cuit_corredor = attrs[:cuit_corredor]
39
- @remitente_com = attrs[:remitente_com]
40
- @cuit_chofer = attrs[:cuit_chofer]
41
- @cant_kilos_carta_porte = attrs[:cant_kilos_carta_porte]
42
- @establecimiento = attrs[:establecimiento]
43
- @cuit_solicitante = attrs[:cuit_solicitante]
44
- @fecha_desde = attrs[:fecha_desde]
45
- @fecha_hasta = attrs[:fecha_hasta]
46
-
47
- @body = {"request" =>{"auth" => Afip.auth_hash("wsctg")}}
48
- end
49
-
50
- def solicitar_ctg_inicial
51
- pp body = setup_ctg
52
-
53
- pp response = client.call(:solicitar_ctg_inicial,message: body)
54
-
55
- setup_response(response.to_hash)
56
-
57
- self.authorized?
58
- end
59
-
60
- def setup_ctg
61
-
62
- datos = {
63
- "datosSolicitarCTGInicial" =>{
64
- "cartaPorte" => @cp_num, #long
65
- "codigoEspecie" => @cod_especie, #int
66
- #"cuitCanjeador" => @cuit_canjeador.to_i, #long
67
- #"remitenteComercialComoCanjeador" => @rccc,
68
- "cuitDestino" => @cuit_destino, #long
69
- "cuitDestinatario" => @cuit_destinatario, #long
70
- "codigoLocalidadOrigen" => @localidad_origen, #int
71
- "codigoLocalidadDestino" => @localidad_destino, #int
72
- "codigoCosecha" => @cosecha, #string
73
- "pesoNeto" => @peso.to_i, #long
74
- #"cuitTransportista" => @cuit_transportista.to_i, #long
75
- #"cantHoras" => @horas, #int
76
- #"patente" => @patente, #string
77
- "kmARecorrer" => @km, #unsignedint
78
- #"cuitCorredor" => @cuit_corredor.to_i, #long
79
- #"remitenteComercialcomoProductor" => @remitente_com
80
- }
81
- }
82
-
83
- @body["request"].merge!(datos)
84
- return @body
85
- end
86
-
87
- def authorized?
88
- !response.nil?
89
- end
90
-
91
- def anular_ctg
92
- request = {
93
- "datosAnularCTG" =>{
94
- "cartaPorte" => "@ctg_num",
95
- "ctg" => "#{self.code}"
96
- }
97
- }
98
- body["request"].merge(request)
99
-
100
- response = client.call(:anular_ctg, message: body)
101
- end
102
-
103
- def cambiar_destino_detinatario_ctg_rechazado
104
- request = {
105
- "datosCambiarDestinoDestinatarioCTGRechazado" =>{
106
- "cartaPorte" => "@ctg_num",
107
- "ctg" => "#{code}",
108
- "codigoLocalidadDestino" => @destino,
109
- "codigoLocalidadDestinatario" => @destinatario,
110
- "kmARecorrer" => @km
111
- }
112
- }
113
- body["request"].merge(request)
114
-
115
- response = client.call(:cambiar_destino_detinatario_ctg_rechazado, message: body)
116
- end
117
-
118
- def confirmar_arribo
119
- request = {
120
- "datosConfirmarArribo" =>{
121
- "cartaPorte" => "@ctg_num",
122
- "ctg" => "#{self.code}",
123
- "cuitTransportista" => @cuit_transportista,
124
- "cuitChofer" => @cuit_chofer,
125
- "cantKilosCartaPorte" => @cant_kilos_carta_porte
126
- }
127
- }
128
- body["request"].merge(request)
129
-
130
- response = client.call(:confirmar_arribo, message: body)
131
- end
132
-
133
- def confirmar_definitivo
134
- request = {
135
- "datosConfirmarDefinitivo" =>{
136
- "cartaPorte" => "@ctg_num",
137
- "ctg" => "#{self.code}",
138
- "establecimiento" => @establecimiento,
139
- "codigoCosecha" => @cosecha,
140
- "pesoNeto" => @peso
141
- }
142
- }
143
- body["request"].merge(request)
144
-
145
- response = client.call(:confirmar_definitivo, message: body)
146
- end
147
-
148
- def consultar_cosechas
149
- response = client.call(:consultar_cosechas, message: body)
150
- return response["arrayCosechas"]
151
- end
152
-
153
- def consultar_constancia_ctg_pdf
154
- request = {
155
- "ctg" => "#{code}"
156
- }
157
-
158
- body["request"].merge(request)
159
-
160
- response = client.call(:consultar_constancia_ctg_pdf, message: body)
161
- end
162
-
163
- def consultar_ctg
164
- request = {
165
- "consultarCTGDatos" =>{
166
- "cartaPorte" => "@ctg_num",
167
- "ctg" => "#{self.code}",
168
- "patente" => @patente,
169
- "cuitSolicitante" => @cuit_solicitante,
170
- "cuitDestino" => @destino,
171
- "fechaEmisionDesde" => @fecha_desde,
172
- "fechaEmisionHsta" => @fecha_hasta,
173
- "cuitCorredor" => @cuit_corredor
174
- }
175
- }
176
- body["request"].merge(request)
177
-
178
- response = client.call(:consultar_ctg, message: body)
179
- end
180
-
181
- def consultar_ctg_rechazados
182
- response = client.call(:consultar_ctg_rechazados, message: body)
183
- return response.to_hash["response"]["arrayConsultarCTGRechazados"]
184
- end
185
-
186
- def consultar_detalle_ctg
187
- request = {
188
- "ctg" => "#{code}"
189
- }
190
-
191
- body["request"].merge(request)
192
-
193
- response = client.call(:consultar_constancia_ctg_pdf, message: body)
194
- return response.to_hash["response"]["consultarDetalleCTGDatos"]
195
- end
196
-
197
- def consultar_especies
198
- response = client.call(:consultar_especies, message: body)
199
- response.body[:consultar_especies_response][:response][:array_especies][:especie].map{|c| [c[:codigo],c[:descripcion]]}
200
- end
201
-
202
- def consultar_establecimientos
203
- response = client.call(:consultar_establecimientos, message: body)
204
- response.body[:consultar_especies_response][:response][:array_establecimientos][:establecimiento].map{|c| [c]}
205
- end
206
-
207
- def consultar_provincias
208
- response = client.call(:consultar_provincias, message: body)
209
- response.body[:consultar_provincias_response][:consultar_provincias_response][:array_provincias][:provincia].map{|c| [c[:codigo],c[:descripcion]]}
210
- end
211
-
212
- def consultar_cosechas
213
- response = client.call(:consultar_cosechas, message: body)
214
- response.body[:consultar_cosechas_response][:response][:array_cosechas][:cosecha].map{|c| [c[:codigo],c[:descripcion]]}
215
- end
216
-
217
- def consultar_localidades(city)
218
- body["request"]["codigoProvincia"] = city
219
- response = client.call(:consultar_localidades_por_provincia, message: body)
220
- if response.body[:consultar_localidades_por_provincia_response][:response][:array_localidades][:localidad].class.name != "Array"
221
- [response.body[:consultar_localidades_por_provincia_response][:response][:array_localidades][:localidad]].map{|c| [c[:codigo],c[:descripcion]]}
222
- else
223
- response.body[:consultar_localidades_por_provincia_response][:response][:array_localidades][:localidad].map{|c| [c[:codigo],c[:descripcion]]}
224
- end
225
- end
226
-
227
- private
228
-
229
- def setup_response(response)
230
- # TODO: turn this into an all-purpose Response class
231
- pp response
232
- end
233
- end
234
- end
data/lib/Afip/padron.rb DELETED
@@ -1,183 +0,0 @@
1
- module Afip
2
- class Padron
3
- attr_reader :client, :body, :fault_code
4
- attr_accessor :dni, :tipo, :data
5
- def initialize(attrs = {})
6
- Afip::AuthData.environment = Afip.environment || :production
7
- url = Afip::AuthData.environment == :production ? "aws" : "awshomo"
8
- Afip.service_url = "https://#{url}.afip.gov.ar/sr-padron/webservices/personaServiceA4?WSDL"
9
- Afip.cuit ||= "20368642682"
10
- Afip.cert ||= "#{Afip.root}/lib/Afip/certs/desideral_prod.crt"
11
- Afip.pkey ||= "#{Afip.root}/lib/Afip/certs/desideral.key"
12
- Afip::AuthData.fetch("ws_sr_padron_a4")
13
-
14
- @client = Savon.client(
15
- ssl_cert_key_file: Afip.pkey,
16
- ssl_cert_file: Afip.cert,
17
- env_namespace: :soapenv,
18
- namespace_identifier: :a4,
19
- encoding: 'UTF-8',
20
- wsdl: Afip.service_url
21
- )
22
-
23
- @dni = attrs[:dni].rjust(8, "0")
24
- @tipo = attrs[:tipo]
25
- @cuit = get_cuit
26
- end
27
-
28
- def get_persona
29
- body = setup_body
30
-
31
- response = client.call(:get_persona,message: body)
32
- rescue Savon::SOAPFault => error
33
- if !error.blank?
34
- @fault_code = error.to_hash[:fault][:faultstring]
35
- else
36
- @fault_code = nil
37
- end
38
- return response
39
- end
40
-
41
- def get_data
42
- @data = get_persona
43
- if fault_code.nil?
44
- set_data
45
- else
46
- return nil
47
- end
48
-
49
- end
50
-
51
- def set_data
52
- pp data.body
53
- if not data.body[:get_persona_response][:persona_return][:persona][:actividad].nil?
54
- {
55
- :last_name => data.body[:get_persona_response][:persona_return][:persona][:apellido],
56
- :first_name => data.body[:get_persona_response][:persona_return][:persona][:nombre],
57
- :cuit => data.body[:get_persona_response][:persona_return][:persona][:id_persona],
58
- :cp => data.body[:get_persona_response][:persona_return][:persona][:domicilio].last[:cod_postal],
59
- :address => data.body[:get_persona_response][:persona_return][:persona][:domicilio].last[:direccion],
60
- :city_id => data.body[:get_persona_response][:persona_return][:persona][:domicilio].last[:id_provincia],
61
- :city => PROVINCIAS[data.body[:get_persona_response][:persona_return][:persona][:domicilio].last[:id_provincia]],
62
- :locality => data.body[:get_persona_response][:persona_return][:persona][:domicilio].last[:localidad],
63
- :birthday => data.body[:get_persona_response][:persona_return][:persona][:fecha_nacimiento].to_date
64
- }
65
- else
66
- {
67
- :last_name => Padron.divide_name(data.body[:get_persona_response][:persona_return][:persona][:apellido])[0],
68
- :first_name => Padron.divide_name(data.body[:get_persona_response][:persona_return][:persona][:apellido])[1],
69
- :cuit => data.body[:get_persona_response][:persona_return][:persona][:id_persona],
70
- :cp => data.body[:get_persona_response][:persona_return][:persona].try(:[], :domicilio).try(:[], :cod_postal),
71
- :address => data.body[:get_persona_response][:persona_return][:persona].try(:[], :domicilio).try(:[], :direccion),
72
- :city_id => data.body[:get_persona_response][:persona_return][:persona].try(:[], :domicilio).try(:[], :id_provincia),
73
- :city => PROVINCIAS[data.body[:get_persona_response][:persona_return][:persona].try(:[], :domicilio).try(:[], :id_provincia)],
74
- :locality => data.body[:get_persona_response][:persona_return][:persona].try(:[], :domicilio).try(:[], :localidad),
75
- :birthday => data.body[:get_persona_response][:persona_return][:persona][:fecha_nacimiento].to_date
76
- }
77
- end
78
- end
79
-
80
- def self.divide_name(full_name)
81
- full_name = full_name.strip.split(/\s+/)
82
- last_name = ''
83
- last = (full_name.count / 2) - 1
84
- (0..last).each do |i|
85
- if i != last
86
- last_name += full_name[i] + ' '
87
- else
88
- last_name += full_name[i]
89
- end
90
- end
91
- full_name = full_name - (last_name.strip.split(/\s+/))
92
- first_name = full_name.join(", ").gsub(",","").split.map(&:capitalize).join(' ')
93
- last_name = last_name.split.map(&:capitalize).join(' ')
94
- return [last_name, first_name]
95
- end
96
-
97
- def get_cuit
98
- if dni.length == 11
99
- @cuit = @dni
100
- else
101
- @cuit = calculate_cuit
102
- end
103
- end
104
-
105
- def calculate_cuit
106
- multiplicador = "2345672345"
107
-
108
- case tipo
109
- when "F"
110
- xy = 27
111
- xy_dni = "27#{dni}"
112
- when "M"
113
- xy = 20
114
- xy_dni = "20#{dni}"
115
- end
116
- verificador = 0
117
- (0..9).each do |i|
118
- verificador += (xy_dni.reverse[i].to_i * multiplicador[i].to_i)
119
- end
120
- verificador
121
- z = verificador - (verificador / 11 * 11)
122
-
123
- case z
124
- when 0
125
- z = 0
126
- when 1
127
- if tipo == "M"
128
- z = 9
129
- xy = 23
130
- elsif tipo == "F"
131
- z = 4
132
- xy = 23
133
- else
134
- z = 11 - z
135
- end
136
- else
137
- z = 11 - z
138
- end
139
-
140
- return "#{xy}#{dni}#{z}"
141
- end
142
-
143
- def setup_body
144
- body = {
145
- 'token' => Afip::TOKEN,
146
- 'sign' => Afip::SIGN,
147
- 'cuitRepresentada' => Afip.cuit,
148
- 'idPersona' => @cuit.to_s
149
- }
150
- end
151
-
152
- PROVINCIAS = {
153
- "0" => 'CIUDAD AUTONOMA BUENOS AIRES',
154
- "1" => 'BUENOS AIRES',
155
- "2" => 'CATAMARCA',
156
- "3" => 'CORDOBA',
157
- "4" => 'CORRIENTES',
158
- "5" => 'ENTRE RIOS',
159
- "6" => 'JUJUY',
160
- "7" => 'MENDOZA',
161
- "8" => 'LA RIOJA',
162
- "9" => 'SALTA',
163
- "10" => 'SAN JUAN',
164
- "11" => 'SAN LUIS',
165
- "12" => 'SANTA FE',
166
- "13" => 'SANTIAGO DEL ESTERO',
167
- "14" => 'TUCUMAN',
168
- "16" => 'CHACO',
169
- "17" => 'CHUBUT',
170
- "18" => 'FORMOSA',
171
- "19" => 'MISIONES',
172
- "20" => 'NEUQUEN',
173
- "21" => 'LA PAMPA',
174
- "22" => 'RIO NEGRO',
175
- "23" => 'SANTA CRUZ',
176
- "24" => 'TIERRA DEL FUEGO'
177
- }
178
- end
179
- end
180
-
181
-
182
-
183
-
data/lib/Afip/version.rb DELETED
@@ -1,3 +0,0 @@
1
- module Afip
2
- VERSION = "0.8.1"
3
- end
data/lib/Afip/wsaa.rb DELETED
@@ -1,94 +0,0 @@
1
- module Afip
2
- # Authorization class. Handles interactions wiht the WSAA, to provide
3
- # valid key and signature that will last for a day.
4
- #
5
- class Wsaa
6
- # Main method for authentication and authorization.
7
- # When successful, produces the yaml file with auth data.
8
- #
9
- def self.login(service = "wsfe")
10
- tra = build_tra(service)
11
- cms = build_cms(tra)
12
- req = build_request(cms)
13
- auth = call_wsaa(req)
14
-
15
- write_yaml(auth)
16
- end
17
-
18
- protected
19
- # Builds the xml for the 'Ticket de Requerimiento de Acceso'
20
- # @return [String] containing the request body
21
- #
22
- def self.build_tra service
23
- @now = (Time.now) - 120
24
- @from = @now.strftime('%FT%T%:z')
25
- @to = (@now + ((12*60*60))).strftime('%FT%T%:z')
26
- @id = @now.strftime('%s')
27
- tra = <<-EOF
28
- <?xml version="1.0" encoding="UTF-8"?>
29
- <loginTicketRequest version="1.0">
30
- <header>
31
- <uniqueId>#{ @id }</uniqueId>
32
- <generationTime>#{ @from }</generationTime>
33
- <expirationTime>#{ @to }</expirationTime>
34
- </header>
35
- <service>#{service}</service>
36
- </loginTicketRequest>
37
- EOF
38
- return tra
39
- end
40
-
41
- # Builds the CMS
42
- # @return [String] cms
43
- #
44
- def self.build_cms(tra)
45
- cms = `echo '#{ tra }' |
46
- #{ Afip.openssl_bin } cms -sign -in /dev/stdin -signer #{ Afip.cert } -inkey #{ Afip.pkey } -nodetach \
47
- -outform der |
48
- #{ Afip.openssl_bin } base64 -e`
49
- return cms
50
- end
51
-
52
- # Builds the CMS request to log in to the server
53
- # @return [String] the cms body
54
- #
55
- def self.build_request(cms)
56
- request = <<-XML
57
- <?xml version="1.0" encoding="UTF-8"?>
58
- <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://wsaa.view.sua.dvadac.desein.afip.gov">
59
- <SOAP-ENV:Body>
60
- <ns1:loginCms>
61
- <ns1:in0>
62
- #{ cms }
63
- </ns1:in0>
64
- </ns1:loginCms>
65
- </SOAP-ENV:Body>
66
- </SOAP-ENV:Envelope>
67
- XML
68
- return request
69
- end
70
-
71
- # Calls the WSAA with the request built by build_request
72
- # @return [Array] with the token and signature
73
- #
74
- def self.call_wsaa(req)
75
- response = `echo '#{ req }' | curl -k -s -H 'Content-Type: application/soap+xml; action=""' -d @- #{ Afip::AuthData.wsaa_url }`
76
- pp response
77
- response = CGI::unescapeHTML(response)
78
- token = response.scan(/\<token\>(.+)\<\/token\>/).first.first
79
- sign = response.scan(/\<sign\>(.+)\<\/sign\>/).first.first
80
- return [token, sign]
81
- end
82
-
83
- # Writes the token and signature to a YAML file in the /tmp directory
84
- #
85
- def self.write_yaml(certs)
86
- yml = <<-YML
87
- token: #{certs[0]}
88
- sign: #{certs[1]}
89
- YML
90
- `echo '#{ yml }' > /tmp/#{Afip::AuthData.environment.to_s}_Afip_#{ Afip.cuit }_#{ Time.new.strftime('%Y_%m_%d') }.yml`
91
- end
92
-
93
- end
94
- end