snoopy_afip 2.1.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,254 +1,175 @@
1
1
  # coding: utf-8
2
2
  module Snoopy
3
3
  class Bill
4
- include AuthData
4
+ attr_accessor :total_net, :document_num, :document_type, :concept, :currency, :result,
5
+ :cbte_asoc_num, :cae, :service_date_to, :due_date,
6
+ :number, :alicivas, :cuit, :sale_point, :service_date_from,
7
+ :due_date_cae, :voucher_date, :process_date, :imp_iva, :cbte_asoc_sale_point,
8
+ :receiver_iva_cond, :issuer_iva_cond, :errors
5
9
 
6
- attr_reader :base_imp, :total
10
+ ATTRIBUTES = [ :total_net, :document_num, :document_type, :concept, :currency, :result,
11
+ :cbte_asoc_num, :cae, :service_date_to, :due_date,
12
+ :number, :alicivas, :cuit, :sale_point, :service_date_from,
13
+ :due_date_cae, :voucher_date, :process_date, :imp_iva, :cbte_asoc_sale_point,
14
+ :receiver_iva_cond, :issuer_iva_cond, :errors ]
7
15
 
8
- attr_accessor :neto_total, :numero_documento, :condicion_iva_receptor, :tipo_documento, :concepto, :moneda,
9
- :due_date, :aliciva_id, :fecha_servicio_desde, :fecha_servicio_hasta, :body,
10
- :response, :cbte_asoc_num, :cbte_asoc_pto_venta, :numero, :alicivas,
11
- :pkey, :cert, :cuit, :punto_venta, :condicion_iva_emisor, :auth, :errors,
12
- :cae, :resultado, :fecha_proceso, :vencimiento_cae, :fecha_comprobante,
13
- :observaciones, :events, :imp_iva, :backtrace
16
+ TAX_ATTRIBUTES = [ :id, :amount, :taxeable_base ]
17
+
18
+ ATTRIBUTES_PRECENSE = [:total_net, :concept, :receiver_iva_cond, :alicivas, :document_type, :service_date_from, :service_date_to, :sale_point, :issuer_iva_cond]
14
19
 
15
20
  def initialize(attrs={})
16
- @pkey = attrs[:pkey]
17
- @cert = attrs[:cert]
18
- @cuit = attrs[:cuit]
19
- @punto_venta = attrs[:sale_point]
20
- @condicion_iva_emisor = attrs[:own_iva_cond]
21
- @neto_total = attrs[:net] || 0
22
- @tipo_documento = attrs[:documento] || Snoopy.default_documento
23
- @moneda = attrs[:moneda] || Snoopy.default_moneda
24
- @concepto = attrs[:concepto] || Snoopy.default_concepto
25
- @numero_documento = attrs[:doc_num]
26
- @fecha_servicio_desde = attrs[:fch_serv_desde]
27
- @fecha_servicio_hasta = attrs[:fch_serv_hasta]
28
- @cbte_asoc_pto_venta = attrs[:cbte_asoc_pto_venta] # Esto es el punto de venta de la factura para la nota de credito
29
- @cbte_asoc_num = attrs[:cbte_asoc_num] # Esto es el numero de factura para la nota de credito
30
- @condicion_iva_receptor = attrs[:iva_cond]
31
- @alicivas = attrs[:alicivas]
32
- @imp_iva = attrs[:imp_iva] # Monto total de impuestos
33
- @response = nil
34
- @errors = []
35
- @observaciones = []
36
- @events = []
37
- @backtrace = ""
38
- end
21
+ # attrs = attrs.deep_symbolize_keys
22
+ @cuit = attrs[:cuit]
23
+ @result = nil
24
+ @number = nil
25
+ @errors = {}
26
+ @concept = attrs[:concept] || Snoopy.default_concept
27
+ @imp_iva = attrs[:imp_iva] # Monto total de impuestos
28
+ @currency = attrs[:currency] || Snoopy.default_currency
29
+ @alicivas = attrs[:alicivas]
30
+ @total_net = attrs[:total_net] || 0
31
+ @sale_point = attrs[:sale_point]
32
+ @document_num = attrs[:document_num]
33
+ @cbte_asoc_num = attrs[:cbte_asoc_num] # Esto es el numero de factura para la nota de credito
34
+ @document_type = attrs[:document_type] || Snoopy.default_document_type
35
+ @issuer_iva_cond = attrs[:issuer_iva_cond]
36
+ @service_date_to = attrs[:service_date_to]
37
+ @service_date_from = attrs[:service_date_from]
38
+ @receiver_iva_cond = attrs[:receiver_iva_cond]
39
+ @cbte_asoc_to_sale_point = attrs[:cbte_asoc_to_sale_point] # Esto es el punto de venta de la factura para la nota de credito
40
+ end
41
+
42
+ # def self.bill_request(number, attrs={})
43
+ # bill = Snoopy::Bill.new(attrs)
44
+ # bill.response = bill.client_call( :fe_comp_consultar,
45
+ # :message => {"Auth" => bill.auth,
46
+ # "FeCompConsReq" => {"CbteTipo" => bill.cbte_type, "PtoVta" => bill.sale_point, "CbteNro" => number.to_s}})
47
+ # bill.parse_fe_comp_consultar_response
48
+ # bill
49
+ # rescue => e
50
+ # binding.pry
51
+ # end
52
+
53
+ # Para probar que la conexion con afip es correcta, si este metodo devuelve true, es posible realizar cualquier consulta al ws de la AFIP.
54
+ # def connection_valid?
55
+ # # result = client.call(:fe_dummy).body[:fe_dummy_response][:fe_dummy_result]
56
+ # result = client_call(:fe_dummy)[:fe_dummy_response][:fe_dummy_result]
57
+ # @afip_observations[:db_server] = result[:db_server]
58
+ # @afip_observations[:app_server] = result[:app_server]
59
+ # @afip_observations[:auth_server] = result[:auth_server]
60
+ # result[:app_server] == 'OK' and result[:db_server] == 'OK' and result[:auth_server] == 'OK'
61
+ # end
39
62
 
40
63
  def exchange_rate
41
- return 1 if moneda == :peso
42
- response = client.fe_param_get_cotizacion do |soap|
43
- soap.namespaces["xmlns"] = "http://ar.gov.afip.dif.FEV1/"
44
- soap.body = body.merge!({"MonId" => Snoopy::MONEDAS[moneda][:codigo]})
45
- end
46
- response.to_hash[:fe_param_get_cotizacion_response][:fe_param_get_cotizacion_result][:result_get][:mon_cotiz].to_f
64
+ return 1 if currency == :peso
65
+ # response = client.fe_param_get_cotizacion do |soap|
66
+ # soap.namespaces["xmlns"] = "http://ar.gov.afip.dif.FEV1/"
67
+ # soap.body = body.merge!({"MonId" => Snoopy::CURRENCY[currency][:code]})
68
+ # end
69
+ # response.to_hash[:fe_param_get_cotizacion_response][:fe_param_get_cotizacion_result][:result_get][:mon_cotiz].to_f
47
70
  end
48
71
 
49
72
  def total
50
- @total = neto_total.zero? ? 0 : (neto_total + iva_sum).round(2)
73
+ @total = total_net.zero? ? 0 : (total_net + iva_sum).round(2)
51
74
  end
52
75
 
53
76
  def iva_sum
54
- @iva_sum = alicivas.collect{|aliciva| if aliciva.has_key?('importe'); aliciva['importe'].to_f; else aliciva[:importe].to_f end }.sum.to_f.round_with_precision(2)
77
+ @iva_sum = alicivas.map{|aliciva| aliciva[:amount].to_f }.inject(:+).to_f.round_with_precision(2)
55
78
  end
56
79
 
57
80
  def cbte_type
58
- Snoopy::BILL_TYPE[condicion_iva_receptor.to_sym] || raise(NullOrInvalidAttribute.new, "Please choose a valid document type.")
81
+ Snoopy::BILL_TYPE[receiver_iva_cond.to_sym]
59
82
  end
60
83
 
61
- def client
62
- Savon.client( :wsdl => Snoopy.service_url,
63
- :ssl_cert_key_file => pkey,
64
- :ssl_cert_file => cert,
65
- :ssl_version => :TLSv1,
66
- :read_timeout => 90,
67
- :open_timeout => 90,
68
- :headers => { "Accept-Encoding" => "gzip, deflate", "Connection" => "Keep-Alive" },
69
- :pretty_print_xml => true,
70
- :namespaces => {"xmlns" => "http://ar.gov.afip.dif.FEV1/"} )
84
+ def approved?
85
+ result == 'A'
71
86
  end
72
87
 
73
- def set_bill_number!
74
- resp = client.call( :fe_comp_ultimo_autorizado,
75
- :message => { "Auth" => generate_auth_file, "PtoVta" => punto_venta, "CbteTipo" => cbte_type })
88
+ def rejected?
89
+ result == 'R'
90
+ end
76
91
 
77
- resp_errors = resp.hash[:envelope][:body][:fe_comp_ultimo_autorizado_response][:fe_comp_ultimo_autorizado_result][:errors]
78
- resp_errors.each_value { |value| @errors << "Código #{value[:code]}: #{value[:msg]}" } unless resp_errors.nil?
79
- @numero = resp.to_hash[:fe_comp_ultimo_autorizado_response][:fe_comp_ultimo_autorizado_result][:cbte_nro].to_i + 1 if @errors.empty?
92
+ def partial_approved?
93
+ result == 'P'
80
94
  end
81
95
 
82
- def build_header
83
- { "CantReg" => "1", "CbteTipo" => cbte_type, "PtoVta" => punto_venta }
96
+ def valid?
97
+ validate!
84
98
  end
85
99
 
86
- def build_body_request
87
- # today = Time.new.in_time_zone('Buenos Aires').strftime('%Y%m%d')
88
- today = Date.today.strftime('%Y%m%d')
89
-
90
- fecaereq = {"FeCAEReq" => {
91
- "FeCabReq" => build_header,
92
- "FeDetReq" => {
93
- "FECAEDetRequest" => {
94
- "Concepto" => Snoopy::CONCEPTOS[concepto],
95
- "DocTipo" => Snoopy::DOCUMENTOS[tipo_documento],
96
- "CbteFch" => today,
97
- "ImpTotConc" => 0.00,
98
- "MonId" => Snoopy::MONEDAS[moneda][:codigo],
99
- "MonCotiz" => exchange_rate,
100
- "ImpOpEx" => 0.00,
101
- "ImpTrib" => 0.00 }}}}
102
-
103
- unless condicion_iva_emisor.to_sym == :responsable_monotributo
104
- _alicivas = alicivas.collect do |aliciva|
105
- id = if aliciva.has_key?('id'); aliciva['id']; else aliciva[:id]; end
106
- importe = if aliciva.has_key?('importe'); aliciva['importe']; else aliciva[:importe]; end
107
- base_imp = if aliciva.has_key?('base_imp'); aliciva['base_imp']; else aliciva[:base_imp]; end
108
- { "Id" => Snoopy::ALIC_IVA[id], "BaseImp" => base_imp, "Importe" => importe }
109
- end
110
- fecaereq["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"]["Iva"] = { "AlicIva" => _alicivas }
111
- end
100
+ def to_h
101
+ Hash[*instance_variables.map { |v|
102
+ [v.to_s.sub('@', '').to_sym, instance_variable_get(v)]
103
+ }.flatten]
104
+ end
105
+ alias :to_hash :to_h
112
106
 
113
- detail = fecaereq["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"]
107
+ private
114
108
 
115
- detail["DocNro"] = numero_documento
116
- detail["ImpNeto"] = neto_total.to_f
117
- detail["ImpIVA"] = iva_sum
118
- detail["ImpTotal"] = total
109
+ def validate!
110
+ # validate_attributes_name(attrs)
111
+ @errors = {}
112
+ validate_attributes_presence
113
+ validate_standar_values
114
+ end
119
115
 
120
- detail["CbteDesde"] = detail["CbteHasta"] = numero
116
+ def validate_attributes_presence
117
+ missing_attributes = []
118
+ ATTRIBUTES_PRECENSE.each { |_attr| missing_attributes << _attr if (self.send(_attr).blank? || self.send(_attr).nil?) }
121
119
 
122
- unless concepto == "Productos"
123
- detail.merge!({ "FchServDesde" => fecha_servicio_desde || today,
124
- "FchServHasta" => fecha_servicio_hasta || today,
125
- "FchVtoPago" => due_date || today})
126
- end
120
+ @alicivas.each { |imp| missing_attributes += Snoopy::Bill::TAX_ATTRIBUTES - imp.keys }
127
121
 
128
- if self.condicion_iva_receptor.to_s.include?("nota_credito")
129
- detail.merge!({"CbtesAsoc" => {"CbteAsoc" => {"Nro" => cbte_asoc_num,
130
- "PtoVta" => cbte_asoc_pto_venta,
131
- "Tipo" => cbte_type }}})
122
+ missing_attributes.uniq.each do |attr|
123
+ @errors[attr.to_sym] = [] unless errors.has_key?(attr)
124
+ @errors[attr.to_sym] << Snoopy::Exception::Bill::MissingAttributes.new(attr).message
132
125
  end
133
126
 
134
- @body = { "Auth" => generate_auth_file }.merge!(fecaereq)
135
127
  end
136
128
 
137
- def cae_request
138
- begin
139
- set_bill_number!
140
- if @errors.empty?
141
- build_body_request
142
- @response = client.call( :fecae_solicitar, :message => body ).body
143
- parse_fecae_solicitar_response
144
- end
145
- rescue => e #Curl::Err::GotNothingError, Curl::Err::TimeoutError
146
- @errors = e.message
147
- @backtrace = e.backtrace
129
+ def validate_standar_values
130
+ status = true
131
+ unless Snoopy::CURRENCY.keys.include?(@currency.to_sym)
132
+ @errors[:currency] = [] unless errors.has_key?(:currency)
133
+ @errors[:currency] << Snoopy::Exception::Bill::InvalidValueAttribute.new("Invalid value #{@currency}, Possible values #{Snoopy::CURRENCY.keys}").message
134
+ status = false unless errors.empty?
148
135
  end
149
- !@response.nil?
150
- end
151
-
152
- def aprobada?; @resultado == "A"; end
153
- def parcial?; @resultado == "P"; end
154
- def rechazada?; @resultado == "R"; end
155
136
 
156
- # Para probar que la conexion con afip es correcta, si este metodo devuelve true, es posible realizar cualquier consulta al ws de la AFIP.
157
- def connection_valid?
158
- begin
159
- result = client.call(:fe_dummy).body[:fe_dummy_response][:fe_dummy_result]
160
- @observaciones << "app_server: #{result[:app_server]}, db_server: #{result[:db_server]}, auth_server: #{result[:auth_server]}"
161
- result[:app_server] == "OK" and result[:db_server] == "OK" and result[:auth_server] == "OK"
162
- rescue => e
163
- @errors << e.message
164
- @backtrace = e.backtrace
165
- false
137
+ unless Snoopy::IVA_COND.include?(@issuer_iva_cond.to_sym)
138
+ @errors[:issuer_iva_cond] = [] unless errors.has_key?(:issuer_iva_cond)
139
+ @errors[:issuer_iva_cond] << Snoopy::Exception::Bill::InvalidValueAttribute.new("Invalid value #{@issuer_iva_cond}. Possible values #{Snoopy::IVA_COND}").message
140
+ status = false unless errors.empty?
166
141
  end
167
- end
168
142
 
169
- def parse_observations(fecae_observations)
170
- begin
171
- fecae_observations.each_value do |obs|
172
- [obs].flatten.each { |ob| @observaciones << "Código #{ob[:code]}: #{ob[:msg]}" }
173
- end
174
- rescue
175
- @observaciones << "Ocurrió un error al parsear las observaciones de AFIP"
143
+ unless Snoopy::BILL_TYPE.keys.include?(@receiver_iva_cond.to_sym)
144
+ @errors[:receiver_iva_cond] = [] unless errors.has_key?(:receiver_iva_cond)
145
+ @errors[:receiver_iva_cond] << Snoopy::Exception::Bill::InvalidValueAttribute.new("Invalid value #{@receiver_iva_cond}. Possible values #{Snoopy::BILL_TYPE.keys}").message
146
+ status = false unless errors.empty?
176
147
  end
177
- end
178
148
 
179
- def parse_errors(fecae_errors)
180
- begin
181
- fecae_errors.each_value do |errores|
182
- [errores].flatten.each { |error| @errors << "Código #{error[:code]}: #{error[:msg]}" }
183
- end
184
- rescue
185
- @errors << "Ocurrió un error al parsear los errores de AFIP"
149
+ unless Snoopy::DOCUMENTS.keys.include?(@document_type)
150
+ @errors[:document_type] = [] unless errors.has_key?(:document_type)
151
+ @errors[:document_type] << Snoopy::Exception::Bill::InvalidValueAttribute.new("Invalid value #{@document_type}. Possible values #{Snoopy::DOCUMENTS.keys}").message
152
+ status = false unless errors.empty?
186
153
  end
187
- end
188
154
 
189
- def parse_events(fecae_events)
190
- begin
191
- fecae_events.each_value do |events|
192
- [events].flatten.each { |event| @events << "Código #{event[:code]}: #{event[:msg]}" }
193
- end
194
- rescue
195
- @events << "Ocurrió un error al parsear los eventos de AFIP"
155
+ unless Snoopy::CONCEPTS.keys.include?(@concept)
156
+ @errors[:concept] = [] unless errors.has_key?(:concept)
157
+ @errors[:concept] << Snoopy::Exception::Bill::InvalidValueAttribute.new("Invalid value #{@concept}. Possible values #{Snoopy::CONCEPTS.keys}").message
158
+ status = false unless errors.empty?
196
159
  end
160
+ status
197
161
  end
198
162
 
199
- def parse_fecae_solicitar_response
200
- fecae_response = @response[:fecae_solicitar_response][:fecae_solicitar_result][:fe_det_resp][:fecae_det_response] rescue {}
201
- fe_cab_resp = @response[:fecae_solicitar_response][:fecae_solicitar_result][:fe_cab_resp] rescue {}
202
- fecae_result = @response[:fecae_solicitar_response][:fecae_solicitar_result] rescue {}
203
-
204
- @cae = fecae_response[:cae]
205
- @numero = fecae_response[:cbte_desde]
206
- @resultado = fecae_response[:resultado]
207
- @vencimiento_cae = fecae_response[:cae_fch_vto]
208
- @fecha_comprobante = fecae_response[:cbte_fch]
209
-
210
- @fecha_proceso = fe_cab_resp[:fch_proceso]
211
-
212
- parse_observations(fecae_response.delete(:observaciones)) if fecae_response.has_key? :observaciones
213
- parse_errors(fecae_result[:errors]) if fecae_result.has_key? :errors
214
- parse_events(fecae_result[:events]) if fecae_result.has_key? :events
215
- end
163
+ # def validate_attributes_name attrs
164
+ # attrs_not_found = attrs.keys - Snoopy::Bill::ATTRIBUTES
165
+ # imp_atts_not_found = []
216
166
 
217
- def parse_fe_comp_consultar_response
218
- result_get = @response.to_hash[:fe_comp_consultar_response][:fe_comp_consultar_result][:result_get]
219
- fe_comp_consultar_result = @response.to_hash[:fe_comp_consultar_response][:fe_comp_consultar_result]
220
-
221
- unless result_get.nil?
222
- @cae = result_get[:cod_autorizacion]
223
- @imp_iva = result_get[:imp_iva]
224
- @numero = result_get[:cbte_desde]
225
- @resultado = result_get[:resultado]
226
- @fecha_proceso = result_get[:fch_proceso]
227
- @vencimiento_cae = result_get[:fch_vto]
228
- @numero_documento = result_get[:doc_numero]
229
- @fecha_comprobante = result_get[:cbte_fch]
230
- @fecha_servicio_desde = result_get[:fch_serv_desde]
231
- @fecha_servicio_hasta = result_get[:fch_serv_hasta]
232
- parse_events(result_get[:observaciones]) if result_get.has_key? :observaciones
233
- end
234
-
235
- self.parse_events(fe_comp_consultar_result[:errors]) if fe_comp_consultar_result and fe_comp_consultar_result.has_key? :errors
236
- self.parse_events(fe_comp_consultar_result[:events]) if fe_comp_consultar_result and fe_comp_consultar_result.has_key? :events
237
- end
238
-
239
- def self.bill_request(numero, attrs={})
240
- bill = new(attrs)
241
- begin
242
- bill.response = bill.client.call( :fe_comp_consultar,
243
- :message => {"Auth" => bill.generate_auth_file,
244
- "FeCompConsReq" => {"CbteTipo" => bill.cbte_type, "PtoVta" => bill.punto_venta, "CbteNro" => numero.to_s}})
245
- bill.parse_fe_comp_consultar_response
246
- rescue => e
247
- bill.errors << e.message
248
- bill.backtrace = e.backtrace
249
- end
250
- bill
251
- end
167
+ # if attrs.has_key?(:alicivas)
168
+ # attrs[:alicivas].each { |imp| imp_atts_not_found += imp.keys - Snoopy::Bill::TAX_ATTRIBUTES }
169
+ # end
252
170
 
171
+ # _attrs = attrs_not_found + imp_atts_not_found.uniq
172
+ # raise Snoopy::Exception::NonExistAttributes.new(_attrs.join(', ')) if _attrs.present?
173
+ # end
253
174
  end
254
175
  end
@@ -0,0 +1,20 @@
1
+ module Snoopy
2
+ class Client
3
+ attr_accessor :savon
4
+
5
+ def initialize(attrs)
6
+ @savon = Savon.client(attrs)
7
+ end
8
+
9
+ def call service, args={}
10
+ Timeout::timeout(5) do
11
+ savon.call(service, args).body
12
+ end
13
+ rescue Timeout::Error
14
+ raise Snoopy::Exception::ServerTimeout.new
15
+ rescue => e
16
+ raise Snoopy::Exception::ClientError.new(e.message)
17
+ end
18
+
19
+ end
20
+ end
@@ -1,72 +1,77 @@
1
1
  # encoding: utf-8
2
2
  module Snoopy
3
- CBTE_TIPO = { "01" => "Factura A",
4
- "02" => "Nota de Débito A",
5
- "03" => "Nota de Crédito A",
6
- "04" => "Recibos A",
7
- "05" => "Notas de Venta al contado A",
8
- "06" => "Factura B",
9
- "07" => "Nota de Debito B",
10
- "08" => "Nota de Credito B",
11
- "09" => "Recibos B",
12
- "10" => "Notas de Venta al contado B",
13
- "11" => "Factura C",
14
- "13" => "Nota de Crédito C",
15
- "34" => "Cbtes. A del Anexo I, Apartado A,inc.f),R.G.Nro. 1415",
16
- "35" => "Cbtes. B del Anexo I,Apartado A,inc. f),R.G. Nro. 1415",
17
- "39" => "Otros comprobantes A que cumplan con R.G.Nro. 1415",
18
- "40" => "Otros comprobantes B que cumplan con R.G.Nro. 1415",
19
- "60" => "Cta de Vta y Liquido prod. A",
20
- "61" => "Cta de Vta y Liquido prod. B",
21
- "63" => "Liquidacion A",
22
- "64" => "Liquidacion B" }
3
+ CBTE_TYPE = { '01' => 'Factura A',
4
+ '02' => 'Nota de Débito A',
5
+ '03' => 'Nota de Crédito A',
6
+ '04' => 'Recibos A',
7
+ '05' => 'Notas de Venta al contado A',
8
+ '06' => 'Factura B',
9
+ '07' => 'Nota de Debito B',
10
+ '08' => 'Nota de Credito B',
11
+ '09' => 'Recibos B',
12
+ '10' => 'Notas de Venta al contado B',
13
+ '11' => 'Factura C',
14
+ '13' => 'Nota de Crédito C',
15
+ '34' => 'Cbtes. A del Anexo I, Apartado A,inc.f),R.G.Nro. 1415',
16
+ '35' => 'Cbtes. B del Anexo I,Apartado A,inc. f),R.G. Nro. 1415',
17
+ '39' => 'Otros comprobantes A que cumplan con R.G.Nro. 1415',
18
+ '40' => 'Otros comprobantes B que cumplan con R.G.Nro. 1415',
19
+ '60' => 'Cta de Vta y Liquido prod. A',
20
+ '61' => 'Cta de Vta y Liquido prod. B',
21
+ '63' => 'Liquidacion A',
22
+ '64' => 'Liquidacion B' }
23
23
 
24
- CONCEPTOS = { "Productos" => "01",
25
- "Servicios" => "02",
26
- "Productos y Servicios" => "03" }
24
+ RESPONSABLE_INSCRIPTO = :responsable_inscripto
25
+ RESPONSABLE_MONOTRIBUTO = :responsable_monotributo
27
26
 
28
- DOCUMENTOS = { "CUIT" => "80",
29
- "CUIL" => "86",
30
- "CDI" => "87",
31
- "LE" => "89",
32
- "LC" => "90",
33
- "CI Extranjera" => "91",
34
- "en tramite" => "92",
35
- "Acta Nacimiento" => "93",
36
- "CI Bs. As. RNP" => "95",
37
- "DNI" => "96",
38
- "Pasaporte" => "94",
39
- "Doc. (Otro)" => "99",
40
- "CI Policía Federal" => '00',
41
- "CI Buenos Aires" => '01',
42
- "CI Catamarca" => '02',
43
- "CI Córdoba" => '03',
44
- "CI Corrientes" => '04',
45
- "CI Entre Ríos" => '05',
46
- "CI Jujuy" => '06',
47
- "CI Mendoza" => '07',
48
- "CI La Rioja" => '08',
49
- "CI Salta" => '09',
50
- "CI San Juan" => '10',
51
- "CI San Luis" => '11',
52
- "CI Santa Fe" => '12',
53
- "CI Santiago del Estero" => '13',
54
- "CI Tucumán" => '14',
55
- "CI Chaco" => '16',
56
- "CI Chubut" => '17',
57
- "CI Formosa" => '18',
58
- "CI Misiones" => '19',
59
- "CI Neuquén" => '20',
60
- "CI La Pampa" => '21',
61
- "CI Río Negro" => '22',
62
- "CI Santa Cruz" => '23',
63
- "CI Tierra del Fuego" => '24' }
27
+ IVA_COND = [ RESPONSABLE_MONOTRIBUTO, RESPONSABLE_INSCRIPTO ]
64
28
 
65
- MONEDAS = { :peso => { :codigo => 'PES', :nombre => 'Pesos Argentinos' },
66
- :dolar => { :codigo => 'DOL', :nombre => 'Dolar Estadounidense' },
67
- :real => { :codigo => '012', :nombre => 'Real' },
68
- :euro => { :codigo => '060', :nombre => 'Euro' },
69
- :oro => { :codigo => '049', :nombre => 'Gramos de Oro Fino' } }
29
+ CONCEPTS = { 'Productos' => '01',
30
+ 'Servicios' => '02',
31
+ 'Productos y Servicios' => '03' }
32
+
33
+ DOCUMENTS = { 'CUIT' => '80',
34
+ 'CUIL' => '86',
35
+ 'CDI' => '87',
36
+ 'LE' => '89',
37
+ 'LC' => '90',
38
+ 'CI Extranjera' => '91',
39
+ 'en tramite' => '92',
40
+ 'Acta Nacimiento' => '93',
41
+ 'CI Bs. As. RNP' => '95',
42
+ 'DNI' => '96',
43
+ 'Pasaporte' => '94',
44
+ 'Doc. (Otro)' => '99',
45
+ 'CI Policía Federal' => '00',
46
+ 'CI Buenos Aires' => '01',
47
+ 'CI Catamarca' => '02',
48
+ 'CI Córdoba' => '03',
49
+ 'CI Corrientes' => '04',
50
+ 'CI Entre Ríos' => '05',
51
+ 'CI Jujuy' => '06',
52
+ 'CI Mendoza' => '07',
53
+ 'CI La Rioja' => '08',
54
+ 'CI Salta' => '09',
55
+ 'CI San Juan' => '10',
56
+ 'CI San Luis' => '11',
57
+ 'CI Santa Fe' => '12',
58
+ 'CI Santiago del Estero' => '13',
59
+ 'CI Tucumán' => '14',
60
+ 'CI Chaco' => '16',
61
+ 'CI Chubut' => '17',
62
+ 'CI Formosa' => '18',
63
+ 'CI Misiones' => '19',
64
+ 'CI Neuquén' => '20',
65
+ 'CI La Pampa' => '21',
66
+ 'CI Río Negro' => '22',
67
+ 'CI Santa Cruz' => '23',
68
+ 'CI Tierra del Fuego' => '24' }
69
+
70
+ CURRENCY = { :peso => { :code => 'PES', :nombre => 'Pesos Argentinos' },
71
+ :dolar => { :code => 'DOL', :nombre => 'Dolar Estadounidense' },
72
+ :real => { :code => '012', :nombre => 'Real' },
73
+ :euro => { :code => '060', :nombre => 'Euro' },
74
+ :oro => { :code => '049', :nombre => 'Gramos de Oro Fino' } }
70
75
 
71
76
  ALIC_IVA = { 0 => '3',
72
77
  0.0 => '3',
@@ -82,5 +87,4 @@ module Snoopy
82
87
  :nota_credito_a => '03',
83
88
  :nota_credito_b => '08',
84
89
  :nota_credito_c => '13' }
85
-
86
90
  end
@@ -20,4 +20,15 @@ class Hash
20
20
  def underscore_keys
21
21
  dup.underscore_keys!
22
22
  end unless method_defined?(:underscore_keys)
23
+
24
+ # Implement this method because only is supported by > Rails 4, so if you want use only ruby, this will help. :)
25
+ def deep_symbolize_keys
26
+ return self.reduce({}) do |memo, (k, v)|
27
+ memo.tap { |m| m[k.to_sym] = (v.is_a?(Hash) || v.is_a?(Array)) ? v.deep_symbolize_keys : v }
28
+ end if self.is_a? Hash
29
+ return self.reduce([]) do |memo, v|
30
+ memo << v.deep_symbolize_keys; memo
31
+ end if self.is_a? Array
32
+ self
33
+ end unless method_defined?(:deep_symbolize_keys)
23
34
  end
@@ -0,0 +1,74 @@
1
+ module Snoopy
2
+ module Exception
3
+
4
+ class Exception < ::StandardError
5
+ attr_accessor :backtrace
6
+
7
+ def initialize(msg, backtrace)
8
+ @backtrace = backtrace
9
+ super(msg)
10
+ end
11
+ end
12
+
13
+ class ClientError < Exception
14
+ def initialize(msj)
15
+ super(msj, nil)
16
+ end
17
+ end
18
+
19
+ class ServerTimeout < Timeout::Error
20
+ end
21
+
22
+ module AuthenticationAdapter
23
+ end
24
+
25
+ module AuthorizeAdapter
26
+ class SetBillNumberParser < Exception
27
+ end
28
+
29
+ class BuildBodyRequest < Exception
30
+ end
31
+
32
+ class ObservationParser < Exception
33
+ end
34
+
35
+ class ErrorParser < Exception
36
+ end
37
+
38
+ class EventsParser < Exception
39
+ end
40
+
41
+ class FecaeSolicitarResultParser < Exception
42
+ end
43
+
44
+ class FecaeResponseParser < Exception
45
+ end
46
+
47
+ class FecompConsultResponseParser < Exception
48
+ end
49
+ end
50
+
51
+ module Bill
52
+ # class NonExistAttributes < Exception
53
+ # def initialize(attributes, backtrace=nil)
54
+ # @backtrace = backtrace
55
+ # super("Non exist attributes: #{attributes}", backtrace)
56
+ # end
57
+ # end
58
+
59
+ class MissingAttributes < Exception
60
+ def initialize(attributes, backtrace=nil)
61
+ @backtrace = backtrace
62
+ super("Missing attributes: #{attributes}", backtrace)
63
+ end
64
+ end
65
+
66
+ class InvalidValueAttribute < Exception
67
+ def initialize(attribute, backtrace=nil)
68
+ @backtrace = backtrace
69
+ super("Invalid value for: #{attribute}", backtrace)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -1,3 +1,3 @@
1
1
  module Snoopy
2
- VERSION = "2.1.1"
2
+ VERSION = "3.0.1"
3
3
  end