Afip 1.4.6 → 1.4.7

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: c07764d2ac36151ee8123d36a5c798ffced1b3b184d42c18d2d2988fc8ce72a3
4
- data.tar.gz: 8fd477544eed952a64312d0a86b1cfae6694d48a468054c6fa18d371192ceb09
3
+ metadata.gz: 45fffc2182c70856fbf8f8c12facd1bd5f8bf0653bbd319f24a87cab99da787e
4
+ data.tar.gz: f38fe48699d8ab2c5c790fbb723d0e04c7f44fa1050203605f8171875ccbc82c
5
5
  SHA512:
6
- metadata.gz: 5e46c5dae7fed9d8fcb7465dbc6a3d23a920d70de0c5704f3f8e478cf424582b16659c23c91657a7a19d4888bae6395c72a5604f827cfdb52ed037fa927ede5e
7
- data.tar.gz: cf1ae128519b5ebaf1e1f6aff47c9de2102a9d92bb589667f42bc8f6f3da8250d3ee44ec08d8b11338519f81db74ecbb8675645d933ff9e655cf8f023a269bc0
6
+ metadata.gz: b94a4851e7ce54f99cc2ee98af7a59401cf67236b6b0c27b2317d63c602ce2d38f76362125fdb2015196288f756c8b882640c50b44a529dfded54496b2b5e0b0
7
+ data.tar.gz: e48f2867900d2bf664ee1ac067bb8393738b5f67af95e48c05ca26fbdd3ec8dff3da1f31b7905a70d20519e428a7eb25914f7abd2398359e0cb9abc40b4550db
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: 1.4.6
4
+ version: 1.4.7
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: 2020-04-30 00:00:00.000000000 Z
11
+ date: 2020-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: savon
@@ -86,30 +86,7 @@ email:
86
86
  executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
- files:
90
- - ".gitignore"
91
- - Afip-1.2.1.gem
92
- - Afip-1.4.gem
93
- - Afip.gemspec
94
- - Gemfile
95
- - Gemfile.lock
96
- - LICENSE.txt
97
- - README.md
98
- - Rakefile
99
- - bin/console
100
- - bin/setup
101
- - lib/Afip.rb
102
- - lib/Afip/auth_data.rb
103
- - lib/Afip/authorizer.rb
104
- - lib/Afip/bill.rb
105
- - lib/Afip/constants.rb
106
- - lib/Afip/core_ext/float.rb
107
- - lib/Afip/core_ext/hash.rb
108
- - lib/Afip/core_ext/string.rb
109
- - lib/Afip/ctg.rb
110
- - lib/Afip/padron.rb
111
- - lib/Afip/version.rb
112
- - lib/Afip/wsaa.rb
89
+ files: []
113
90
  homepage: http://litecode.com.ar/
114
91
  licenses:
115
92
  - MIT
@@ -130,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
107
  - !ruby/object:Gem::Version
131
108
  version: '0'
132
109
  requirements: []
133
- rubygems_version: 3.0.3
110
+ rubygems_version: 3.1.2
134
111
  signing_key:
135
112
  specification_version: 4
136
113
  summary: Comunicacion con AFIP
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-1.2.1.gem DELETED
Binary file
data/Afip-1.4.gem DELETED
Binary file
data/Afip.gemspec DELETED
@@ -1,41 +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 = "http://litecode.com.ar/"
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
-
32
- spec.bindir = "exe"
33
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
34
- spec.require_paths = ["lib"]
35
-
36
- spec.add_dependency "savon"
37
- spec.add_dependency "httpi"
38
- spec.add_dependency "nokogiri", ">= 1.10.4"
39
- spec.add_development_dependency "bundler"
40
- spec.add_development_dependency "rake"
41
- 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,49 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- Afip (1.4.5)
5
- httpi
6
- nokogiri (>= 1.10.4)
7
- savon
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
- akami (1.3.1)
13
- gyoku (>= 0.4.0)
14
- nokogiri
15
- builder (3.2.4)
16
- gyoku (1.3.1)
17
- builder (>= 2.1.2)
18
- httpi (2.4.4)
19
- rack
20
- socksify
21
- mini_portile2 (2.4.0)
22
- nokogiri (1.10.9)
23
- mini_portile2 (~> 2.4.0)
24
- nori (2.6.0)
25
- rack (2.2.2)
26
- rake (10.5.0)
27
- savon (2.12.0)
28
- akami (~> 1.2)
29
- builder (>= 2.1.2)
30
- gyoku (~> 1.2)
31
- httpi (~> 2.3)
32
- nokogiri (>= 1.8.1)
33
- nori (~> 2.4)
34
- wasabi (~> 3.4)
35
- socksify (1.7.1)
36
- wasabi (3.5.0)
37
- httpi (~> 2.0)
38
- nokogiri (>= 1.4.2)
39
-
40
- PLATFORMS
41
- ruby
42
-
43
- DEPENDENCIES
44
- Afip!
45
- bundler
46
- rake
47
-
48
- BUNDLED WITH
49
- 1.17.3
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/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
@@ -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
- "/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,274 +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, :cbte_type,
5
- :due_date, :fch_serv_desde, :fch_serv_hasta, :fch_emision,
6
- :ivas, :sale_point, :cant_reg, :no_gravado, :gravado, :exento, :otros_imp, :tributos, :opcionales
7
-
8
- def initialize(attrs={})
9
- @client = Bill.set_client
10
- @sale_point = attrs[:sale_point]
11
- @body = { "Auth" => Afip.auth_hash }
12
- @net = attrs[:net] || 0.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
- @fch_serv_hasta = attrs[:fch_serv_hasta]
20
- @fch_serv_desde = attrs[:fch_serv_desde]
21
- @due_date = attrs[:due_date]
22
- @cbte_type = attrs[:cbte_type]
23
- @cant_reg = attrs[:cant_reg] || 1
24
- @no_gravado = attrs[:no_gravado] || 0.0
25
- @gravado = attrs[:gravado] || 0.0
26
- @exento = attrs[:exento] || 0.0
27
- @otros_imp = attrs[:otros_imp] || 0.0
28
- @total = net.to_f + iva_sum.to_f + exento.to_f + no_gravado.to_f + otros_imp.to_f
29
- @tributos = attrs[:tributos] || []
30
- @opcionales = attrs[:opcionales] || []
31
- end
32
-
33
- def self.get_ptos_vta
34
- client = set_client
35
- body = { "Auth" => Afip.auth_hash }
36
- response = client.call(:fe_param_get_ptos_venta, message: body)
37
- if response.body[:fe_param_get_ptos_venta_response][:fe_param_get_ptos_venta_result][:errors].nil?
38
- if response.body[:fe_param_get_ptos_venta_response][:fe_param_get_ptos_venta_result][:result_get][:pto_venta].is_a?(Hash)
39
- response.body[:fe_param_get_ptos_venta_response][:fe_param_get_ptos_venta_result][:result_get][:pto_venta][:nro]
40
- else
41
- response.body[:fe_param_get_ptos_venta_response][:fe_param_get_ptos_venta_result][:result_get][:pto_venta].map{|r| r[:nro]}
42
- end
43
- else
44
- []
45
- end
46
- end
47
-
48
- def self.get_tipos_cbte
49
- client = set_client
50
- body = { "Auth" => Afip.auth_hash }
51
- response = client.call(:fe_param_get_tipos_cbte, message: body)
52
- end
53
-
54
- def self.get_tributos
55
- client = set_client
56
- body = { "Auth" => Afip.auth_hash }
57
- response = client.call(:fe_param_get_tipos_tributos, message: body)
58
- if response.body[:fe_param_get_tipos_tributos_response][:fe_param_get_tipos_tributos_result][:errors].nil?
59
- response.body[:fe_param_get_tipos_tributos_response][:fe_param_get_tipos_tributos_result][:result_get][:tributo_tipo]
60
- else
61
- []
62
- end
63
- end
64
-
65
- def self.set_client
66
- Afip::AuthData.fetch
67
- @client = Savon.client(
68
- wsdl: Afip.service_url,
69
- namespaces: { "xmlns" => "http://ar.gov.afip.dif.FEV1/" },
70
- log_level: :debug,
71
- ssl_cert_key_file: Afip.pkey,
72
- ssl_cert_file: Afip.cert,
73
- ssl_verify_mode: :none,
74
- read_timeout: 90,
75
- open_timeout: 90,
76
- headers: { "Accept-Encoding" => "gzip, deflate", "Connection" => "Keep-Alive" }
77
- )
78
- end
79
-
80
- def authorize
81
- body = setup_bill
82
- pp response = client.call(:fecae_solicitar, message: body)
83
- setup_response(response.to_hash)
84
- authorized?
85
- end
86
-
87
- def setup_bill
88
- array_ivas = {}
89
- array_ivas["AlicIva"] = ivas.map{ |i| { "Id" => i[0], "BaseImp" => i[1].round(2), "Importe" => i[2].round(2)} unless ["01", "02"].include?(i[0])}.compact
90
-
91
- array_tributos = {}
92
- array_tributos["Tributo"] = tributos.map{ |t|
93
- if t[1].blank?
94
- {
95
- "Id" => t[0],
96
- "BaseImp" => t[2].to_f.round(2),
97
- "Alic" => t[3].to_f.round(2),
98
- "Importe" => t[4].to_f.round(2)
99
- }
100
- else
101
- {
102
- "Id" => t[0],
103
- "Desc" => t[1],
104
- "BaseImp" => t[2].to_f.round(2),
105
- "Alic" => t[3].to_f.round(2),
106
- "Importe" => t[4].to_f.round(2)
107
- }
108
- end
109
- }
110
-
111
- array_opcionales = {}
112
- array_opcionales["Opcional"] = opcionales.map{ |t|
113
- {
114
- "Id" => t[:id],
115
- "Valor" => t[:valor]
116
- }
117
- }
118
-
119
-
120
- fecaereq = {
121
- "FeCAEReq" => {
122
- "FeCabReq" => Afip::Bill.header(cant_reg, cbte_type, sale_point),
123
- "FeDetReq" => {
124
- "FECAEDetRequest" => {
125
- "Concepto" => Afip::CONCEPTOS[concepto],
126
- "DocTipo" => Afip::DOCUMENTOS[documento],
127
- "DocNro" => doc_num,
128
- "CbteFch" => fecha_emision.strftime('%Y%m%d'),
129
- "ImpTotConc" => no_gravado,
130
- "ImpNeto" => net.to_f,
131
- "MonId" => Afip::MONEDAS[moneda][:codigo],
132
- "MonCotiz" => exchange_rate,
133
- "ImpOpEx" => exento,
134
- "ImpTotal" => (Afip.own_iva_cond == :responsable_monotributo ? net : total).to_f.round(2),
135
- "CbteDesde" => next_bill_number,
136
- "CbteHasta" => next_bill_number
137
- }
138
- }
139
- }
140
- }
141
-
142
- detail = fecaereq["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"]
143
-
144
- if (Afip.own_iva_cond == :responsable_inscripto)
145
- detail["ImpIVA"] = iva_sum
146
- detail["Iva"] = array_ivas unless iva_sum == 0
147
- end
148
-
149
- if !tributos.empty?
150
- detail["ImpTrib"] = otros_imp
151
- detail["Tributos"] = array_tributos
152
- end
153
-
154
- if !opcionales.empty?
155
- detail["Opcionales"] = array_opcionales
156
- end
157
-
158
- unless concepto == "Productos" # En "Productos" ("01"), si se mandan estos parámetros la afip rechaza.
159
- detail.merge!({"FchServDesde" => fch_serv_desde.strftime("%Y%m%d"),
160
- "FchServHasta" => fch_serv_hasta.strftime("%Y%m%d"),
161
- "FchVtoPago" => due_date.strftime("%Y%m%d")})
162
- end
163
-
164
- if ["201", "202", "203", "206", "207", "208", "211", "212", "213"].include?(cbte_type)
165
- detail.merge!({"FchVtoPago" => due_date.strftime("%Y%m%d")})
166
- end
167
-
168
- body.merge!(fecaereq)
169
- pp body
170
- end
171
-
172
- def self.header(cant_reg, cbte_type, sale_point)
173
- {"CantReg" => cant_reg.to_s, "CbteTipo" => cbte_type, "PtoVta" => sale_point}
174
- end
175
-
176
- def exchange_rate
177
- return 1 if moneda == :peso
178
- response = client.call :fe_param_get_cotizacion do
179
- message = body.merge!({"MonId" => Afip::MONEDAS[moneda][:codigo]})
180
- end
181
- response.to_hash[:fe_param_get_cotizacion_response][:fe_param_get_cotizacion_result][:result_get][:mon_cotiz].to_f
182
- end
183
-
184
- def iva_sum
185
- iva_sum = 0.0
186
- self.ivas.each{ |i|
187
- iva_sum += i[2]
188
- }
189
- return iva_sum.round(2)
190
- end
191
-
192
- def next_bill_number
193
- var = {"Auth" => Afip.auth_hash, "PtoVta" => sale_point, "CbteTipo" => cbte_type}
194
- resp = client.call :fe_comp_ultimo_autorizado do
195
- message(var)
196
- end
197
-
198
- resp.to_hash[:fe_comp_ultimo_autorizado_response][:fe_comp_ultimo_autorizado_result][:cbte_nro].to_i + 1
199
- end
200
-
201
- def setup_response(response)
202
- # TODO: turn this into an all-purpose Response class
203
- pp response
204
- result = response[:fecae_solicitar_response][:fecae_solicitar_result]
205
-
206
- if not result[:fe_det_resp] or not result[:fe_cab_resp] then
207
- # Si no obtuvo respuesta ni cabecera ni detalle, evito hacer '[]' sobre algo indefinido.
208
- # Ejemplo: Error con el token-sign de WSAA
209
- keys, values = {
210
- :errores => result[:errors],
211
- :header_result => {:resultado => "X" },
212
- :observaciones => nil
213
- }.to_a.transpose
214
- @response = (defined?(Struct::ResponseMal) ? Struct::ResponseMal : Struct.new("ResponseMal", *keys)).new(*values)
215
- return
216
- end
217
-
218
- response_header = result[:fe_cab_resp]
219
- response_detail = result[:fe_det_resp][:fecae_det_response]
220
-
221
- request_header = body["FeCAEReq"]["FeCabReq"].underscore_keys.symbolize_keys
222
- request_detail = body["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"].underscore_keys.symbolize_keys
223
-
224
- # Esto no funciona desde que se soportan múltiples alícuotas de iva simultáneas
225
- # FIX ? TO-DO
226
- # iva = request_detail.delete(:iva)["AlicIva"].underscore_keys.symbolize_keys
227
- # request_detail.merge!(iva)
228
-
229
- if result[:errors] then
230
- response_detail.merge!( result[:errors] )
231
- end
232
-
233
- response_hash = {
234
- :header_result => response_header.delete(:resultado),
235
- :authorized_on => response_header.delete(:fch_proceso),
236
- :detail_result => response_detail.delete(:resultado),
237
- :cae_due_date => response_detail.delete(:cae_fch_vto),
238
- :cae => response_detail.delete(:cae),
239
- :iva_id => request_detail.delete(:id),
240
- :iva_importe => request_detail.delete(:importe),
241
- :moneda => request_detail.delete(:mon_id),
242
- :cotizacion => request_detail.delete(:mon_cotiz),
243
- :iva_base_imp => request_detail.delete(:base_imp),
244
- :doc_num => request_detail.delete(:doc_nro),
245
- :observaciones => response_detail.delete(:observaciones),
246
- :ivas => response_detail.delete(:iva),
247
- :tributos => response_detail.delete(:tributos),
248
- :errores => response_detail.delete(:err)
249
- }.merge!(request_header).merge!(request_detail)
250
-
251
- keys, values = response_hash.to_a.transpose
252
- pp @response = Struct.new("Response", *keys).new(*values)
253
- end
254
-
255
- def authorized?
256
- !response.nil? && response.header_result == "A" && response.detail_result == "A"
257
- end
258
-
259
- def self.comp_consultar(cbte_tipo, cbte_nro, pto_venta)
260
- client = set_client
261
-
262
- body = {
263
- "Auth" => Afip.auth_hash,
264
- "FeCompConsReq" => {
265
- "CbteTipo" => cbte_tipo,
266
- "CbteNro" => cbte_nro,
267
- "PtoVta" => pto_venta
268
- }
269
- }
270
- response = client.call(:fe_comp_consultar, message: body)
271
- return response
272
- end
273
- end
274
- end