snoopy_afip 2.1.1 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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