facturapi 0.0.1 → 0.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c84c8ad9f595de425766ed65c06063b58744ae60
4
- data.tar.gz: 25ffce29b83b617bfbfda57245ad1d73865fbd5a
3
+ metadata.gz: 9c4286989ee90c94066e323aecac710629cf2695
4
+ data.tar.gz: 604c064a8cdeb558f609dfa54dbdf70e7026f10c
5
5
  SHA512:
6
- metadata.gz: aff36a3dce1bb173b18fe55917acb3123cf76cddfac684e1aa603f8156c5a53463c7aa130890af68f0941ca46749e20ba556d20565b7cac7d81eeb1a18a6b58a
7
- data.tar.gz: 6b9ca89f47ffddbd389e46cbe7af3b50bf5686f627c909bafd7fae3ed0d3cd70e7fc1d0800aec8a3d62f7aae787a525c985fdb7509b7bd6668bdf77e9d41d210
6
+ metadata.gz: 30d4c5f7152e6c74d1b20484baab7f2b4d39a640f609a7ebd6533fa099552c2a1d1c877f428f9d9a1888a6302d97cdd9a4ec278814e4247f96fbdb4ebde54b85
7
+ data.tar.gz: 4ec0827f0b24fd5b15bdd0f7a9f3bfc6db211beda4149e4b358cfbd72c3578033166d116f527cb9cff4cebb6ef94b795a3b6b26446da292460a463e74db177e3
data/Guardfile ADDED
@@ -0,0 +1,14 @@
1
+ guard :rspec, cmd: "bundle exec rspec" do
2
+ require "guard/rspec/dsl"
3
+ dsl = Guard::RSpec::Dsl.new(self)
4
+
5
+ # RSpec files
6
+ rspec = dsl.rspec
7
+ watch(rspec.spec_helper) { rspec.spec_dir }
8
+ watch(rspec.spec_support) { rspec.spec_dir }
9
+ watch(rspec.spec_files)
10
+
11
+ # Ruby files
12
+ ruby = dsl.ruby
13
+ dsl.watch_spec_files_for(ruby.lib_files)
14
+ end
data/README.md CHANGED
@@ -1,41 +1,138 @@
1
1
  # Facturapi
2
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/facturapi`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ [![Code Climate](https://codeclimate.com/github/meloncargo/facturapi/badges/gpa.svg)](https://codeclimate.com/github/meloncargo/facturapi)
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ Esta gema facilita la integración con el servicio SOAP de facturacion.cl para
6
+ aplicaciones Ruby on Rails.
6
7
 
7
- ## Installation
8
+ ## Instalación
8
9
 
9
- Add this line to your application's Gemfile:
10
+ Agrega a tu Gemfile:
10
11
 
11
12
  ```ruby
12
13
  gem 'facturapi'
13
14
  ```
14
15
 
15
- And then execute:
16
+ Y luego ejecuta
16
17
 
17
18
  $ bundle
18
19
 
19
- Or install it yourself as:
20
+ ## Configuración
20
21
 
21
- $ gem install facturapi
22
+ Agrega a tu archivo `config/initializers/facturapi.rb`:
22
23
 
23
- ## Usage
24
+ ```ruby
25
+ Facturapi.configure do |config|
26
+ config.fact_rut '1-9'
27
+ config.fact_user 'usuario'
28
+ config.fact_password '12345'
29
+ config.fact_port 9350
30
+ end
31
+ ```
32
+
33
+ o también puedes definir variables de entorno en tu sistema:
34
+
35
+ ```
36
+ FACTURACION_USER=1-9
37
+ FACTURACION_RUT=usuario
38
+ FACTURACION_PASSWORD=12345
39
+ FACTURACION_PORT=9350
40
+ ```
24
41
 
25
- TODO: Write usage instructions here
42
+ ## Uso
26
43
 
27
- ## Development
44
+ Ejemplo mínimo de envío de boleta:
28
45
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
46
+ ```ruby
47
+ include Facturapi::Helpers
48
+
49
+ detalle = [
50
+ Detalle.new(
51
+ vlr_codigo: '17409',
52
+ nmb_item: 'Reloj',
53
+ qty_item: '1',
54
+ prc_item: 20_500
55
+ )
56
+ ]
57
+
58
+ dte = Dte.new(
59
+ encabezado: Encabezado.new(
60
+ id_doc: IdDoc.new(
61
+ fch_emis: Date.new(2016, 11, 14),
62
+ ind_servicio: 3
63
+ ),
64
+ emisor: Emisor.new(
65
+ rut_emisor: '1-9',
66
+ rzn_soc_emisor: 'SUPER EMPRESA',
67
+ giro_emisor: 'VENDEMOS COSAS',
68
+ dir_origen: 'Luis Thayer Ojeda Nº1525',
69
+ cmna_origen: 'Providencia',
70
+ ciudad_origen: 'Santiago'
71
+ ),
72
+ receptor: Receptor.new(
73
+ cdg_int_recep: '1000215-220',
74
+ rzn_soc_recep: 'Juan Perez',
75
+ contacto: 'juan@perez.com',
76
+ dir_recep: 'CALLE A 50',
77
+ cmna_recep: 'SANTIAGO',
78
+ ciudad_recep: 'SANTIAGO'
79
+ )
80
+ ),
81
+ detalle: detalle
82
+ )
83
+ # Realiza cálculos automáticos de totales, ademas de rellenar datos de
84
+ dte.autocomplete!
85
+
86
+ procesar = Facturapi::Service::Procesar.new(dte)
87
+ response = procesar.send
88
+
89
+
90
+ response.valid? # true
91
+ response.error # ''
92
+ response.folio # 4666638667
93
+ response.tipo_dte # 39
94
+ response.fecha # 2017-02-20 19:01:36 -0300
95
+ puts response
96
+ # <?xml version="1.0"?>
97
+ # <WSPLANO>
98
+ # <Resultado>True</Resultado>
99
+ # <Mensaje>Proceso exitoso.</Mensaje>
100
+ # <Detalle>
101
+ # <Documento>
102
+ # <Folio>4666638667</Folio>
103
+ # <TipoDte>39</TipoDte>
104
+ # <Operacion>VENTA</Operacion>
105
+ # <Fecha>2017-02-20T19:01:36</Fecha>
106
+ # <Resultado>True</Resultado>
107
+ # </Documento>
108
+ # </Detalle>
109
+ # </WSPLANO>
110
+
111
+ ```
30
112
 
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).
113
+ Obtención de link para descargar documento tributario
32
114
 
33
- ## Contributing
115
+ ```ruby
116
+ obtener_link = Facturapi::Services::ObtenerLink.new(folio: '123')
117
+ response = obtener_link.send
118
+
119
+ response.url # http://www.facturacion.cl/plano/descargar.php?...
120
+ ```
34
121
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/facturapi. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
122
+ Mas información sobre los atributos aceptados por los helpers, revisa [la
123
+ documentación](https://github.com/meloncargo/facturapi/tree/master/lib/facturapi/helpers)
124
+ contenida en los mismos.
36
125
 
126
+ ## Why tanto spanglish?
37
127
 
38
- ## License
128
+ Ya que esta gema sería usada principalmente por desarrolladores chilenos y para
129
+ facilidad de uso, toda la documentación irá en español. Además los nombres de
130
+ clases y variables seguirán la misma nomenclatura usada en el servicio web, la
131
+ cual es en español. Todo lo que escape a el ámbito descrito, será en inglés.
39
132
 
40
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
133
+ ## Aviso Legal
41
134
 
135
+ Esta gema no está desarrollada, soportada ni avalada de ninguna manera por
136
+ Desis Ltda. y es el resultado de ingeniería inversa al servicio de integración
137
+ de facturacion.cl con fines de interoperabilidad, como lo permite la [ley chilena
138
+ 20.435, artículo 71 Ñ, sección b.](http://www.leychile.cl/Navegar?idNorma=1012827)
@@ -0,0 +1,21 @@
1
+ es:
2
+ facturapi:
3
+ dte_type:
4
+ factura: 'Factura'
5
+ factura_ex: 'Factura exenta'
6
+ factura_elec: 'Factura electrónica'
7
+ factura_ex_elec: 'Factura exenta electrónica'
8
+ boleta: 'Boleta'
9
+ boleta_ex: 'Boleta exenta'
10
+ boleta_elec: 'Boleta electrónica'
11
+ liq_factura: 'Liquidación factura'
12
+ boleta_ex_elec: 'Boleta exenta electrónica'
13
+ liq_factura_elec: 'Liquidación factura electrónica'
14
+ factura_compra: 'Factura de compra'
15
+ factura_compra_elec: 'Factura de compra electrónica'
16
+ guia_despacho: 'Guia de despacho'
17
+ guia_despacho_elec: 'Guia de despacho electrónica'
18
+ nota_deb: 'Nota de débito'
19
+ nota_deb_elec: 'Nota de débito electrónica'
20
+ nota_cred: 'Nota de crédito'
21
+ nota_cred_elec: 'Nota de crédito electrónica'
data/facturapi.gemspec CHANGED
@@ -10,8 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["alter.strife@gmail.com"]
11
11
 
12
12
  spec.summary = %q{Ruby integration with facturacion.cl service}
13
- # spec.description = %q{TODO: Write a longer description or delete this line.}
14
- # spec.homepage = ""
13
+ spec.homepage = "https://github.com/meloncargo/facturapi"
15
14
  spec.license = "MIT"
16
15
 
17
16
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -23,8 +22,10 @@ Gem::Specification.new do |spec|
23
22
  spec.add_runtime_dependency "savon", "~> 2.0"
24
23
  spec.add_runtime_dependency "libxml-ruby", "~> 2.0"
25
24
  spec.add_runtime_dependency "nokogiri", "~> 1.4", ">= 1.4.0"
25
+ spec.add_runtime_dependency "i18n", "~> 0.6"
26
26
 
27
- spec.add_development_dependency "bundler", "~> 1.13"
28
27
  spec.add_development_dependency "rake", "~> 10.0"
29
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
+ spec.add_development_dependency "pry-byebug", "~> 3.4.0"
30
+ spec.add_development_dependency "guard-rspec", "~> 4.7.0"
30
31
  end
data/lib/facturapi.rb CHANGED
@@ -1,6 +1,8 @@
1
+ require 'facturapi/version'
1
2
  require 'facturapi/xml'
2
3
  require 'facturapi/config'
3
4
  require 'facturapi/client'
5
+
4
6
  require 'facturapi/helpers'
5
- require 'facturapi/service'
6
- require 'facturapi/version'
7
+ require 'facturapi/services'
8
+ require 'facturapi/utils'
@@ -2,26 +2,38 @@ require 'savon'
2
2
 
3
3
  module Facturapi
4
4
  class Client
5
- attr_accessor :client
6
- attr_reader :login
5
+ class << self
6
+ def call(method, params = {})
7
+ params[:login] ||= login
8
+ client.call(method, message: params)
9
+ end
7
10
 
8
- def initialize
9
- @login = {
10
- 'Usuario' => Facturapi.config.fact_user,
11
- 'Rut' => Facturapi.config.fact_rut,
12
- 'Clave' => Facturapi.config.fact_password,
13
- 'Puerto' => Facturapi.config.fact_port
14
- }
15
- @client = Savon.client(
16
- wsdl: 'http://ws1.facturacion.cl/WSDS/wsplano.asmx?wsdl'
17
- )
18
- end
11
+ def xml(method, params = {})
12
+ ops = client.operation(method)
13
+ params[:login] ||= login
14
+ Nokogiri::XML(ops.build(message: params).to_s).to_s
15
+ end
16
+
17
+ def client
18
+ @client ||= Savon.client(
19
+ wsdl: 'http://ws1.facturacion.cl/WSDS/wsplano.asmx?wsdl'
20
+ )
21
+ end
22
+
23
+ def operations
24
+ client.operations
25
+ end
26
+
27
+ private
19
28
 
20
- def call(method, params = {})
21
- params[:login] ||= login
22
- puts params
23
- response = @client.call(method, message: params)
24
- response.body[:procesar_response][:procesar_result]
29
+ def login
30
+ @login ||= {
31
+ 'Usuario' => Facturapi.config.fact_user,
32
+ 'Rut' => Facturapi.config.fact_rut,
33
+ 'Clave' => Facturapi.config.fact_password,
34
+ 'Puerto' => Facturapi.config.fact_port
35
+ }
36
+ end
25
37
  end
26
38
  end
27
39
  end
@@ -1,5 +1,7 @@
1
1
  require 'facturapi/helpers/detalle'
2
2
  require 'facturapi/helpers/dsc_rcg_global'
3
+ require 'facturapi/helpers/descuento_global'
4
+ require 'facturapi/helpers/recargo_global'
3
5
  require 'facturapi/helpers/dte'
4
6
  require 'facturapi/helpers/emisor'
5
7
  require 'facturapi/helpers/encabezado'
@@ -0,0 +1,10 @@
1
+ module Facturapi
2
+ module Helpers
3
+ class DescuentoGlobal < DscRcgGlobal
4
+ def initialize(params = {})
5
+ params[:tpo_mov] = 'D'
6
+ super(params)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,22 +1,117 @@
1
1
  module Facturapi
2
2
  module Helpers
3
+ # Corresponde a las lineas de detalle de una Boleta Electronica, con un
4
+ # minimo de 1 linea de detalle y un maximo de 1.000 lineas
3
5
  class Detalle
4
- attr_accessor :nro_lin_det, :tpo_codigo, :vlr_codigo, :ind_exe,
5
- :rut_mandante, :nmb_item, :dsc_item, :qty_item, :unmd_item,
6
- :prc_item, :monto_item
6
+ # Indica el numero secuencial de linea de detalle de la Boleta
7
+ # Electronica, el cual puede ser desde la linea 1 hasta la linea 1.000.
8
+ attr_accessor :nro_lin_det
9
+
10
+ # Es el tipo de codigo que la empresa utiliza en el producto que se esta
11
+ # indicando en la linea de detalle; si no se tiene un tipo de codigo
12
+ # definido, se puede utilizar por defecto el tipo INT1.
13
+ attr_accessor :tpo_codigo
14
+
15
+ # Es el codigo del producto, con un maximo de 35 caracteres.
16
+ attr_accessor :vlr_codigo
17
+
18
+ # Indica si el producto o servicio del item es afecto, exento o es no
19
+ # facturable, los indicadores son:
20
+ #
21
+ # - 0: afecto a IVA
22
+ # - 1: exento de IVA
23
+ # - 2: no facturable
24
+ # - 6: no facturable (negativo)
25
+ #
26
+ # En caso que sea una factura, solo es necesario si se desea indicar que
27
+ # la linea es exenta de IVA. Los valores son:
28
+ #
29
+ # - 1: No afecto o exento de IVA
30
+ # - 2: Producto o servicio no es facturable
31
+ # - 3: Garantia de deposito por envases (Cervezas, Jugos, Aguas Minerales,
32
+ # Bebidas Analcoholicas u otros autorizados por Resolucion especial)
33
+ # - 4: item No Venta. (Para facturas y guias de despacho (esta ultima con
34
+ # Indicador Tipo de Traslado de Bienes igual a 1) y este item no
35
+ # sera facturado.
36
+ # - 5: item a rebajar. Para guias de despacho NO VENTA que rebajan guia
37
+ # anterior. En el area de referencias se debe indicar la guia
38
+ # anterior.
39
+ # - 6: Producto o servicio no facturable negativo
40
+ attr_accessor :ind_exe
41
+
42
+ # Es la descripcion del producto o servicio, es decir, corresponde al
43
+ # nombre del producto o descripcion del servicio.
44
+ attr_accessor :nmb_item
45
+
46
+ # Es la cantidad del item, su valor debe ser hasta 12 digitos y 6
47
+ # decimales.
48
+ attr_accessor :qty_item
49
+
50
+ # Es el precio unitario del item, su valor debe ser hasta 16 digitos y
51
+ # 2 decimales.
52
+ attr_accessor :prc_item
53
+
54
+ # Indica el valor del item, es decir, el valor final de la linea de
55
+ # detalle. Este valor es bruto (con IVA), excepto cuando el campo
56
+ # IndMntNeto tenga el valor 2. Al ser un campo de monto, se debe
57
+ # indicar sin decimales y sin separadores de miles.
58
+ # Se calcula de la siguiente forma:
59
+ # MontoItem = PrcItem * QtyItem
60
+ attr_accessor :monto_item
61
+
62
+ # Corresponde al RUT del Mandante si la venta o servicio es por cuenta
63
+ # de otro, el cual es responsable del IVA devengado en el periodo.
64
+ # Debe contener valor desde 100.000 hasta 99 millones, guion y digito
65
+ # verificador (sin separador de miles).
66
+ attr_accessor :rut_mandante
67
+
68
+ # Es la descripcion adicional del producto o servicio antes indicado,
69
+ # con un maximo de 1.000 caracteres, en este campo se puede indicar mas
70
+ # informacion del producto o incluso una observacion en la linea de
71
+ # detalle.
72
+ attr_accessor :dsc_item
73
+
74
+ # Es la unidad de medida que se utiliza en el producto que se esta
75
+ # indicando en la linea de detalle; si no se tiene una unidad de medida
76
+ # definida, se puede utilizar por defecto la unidad de medida UN
77
+ attr_accessor :unmd_item
78
+
79
+ # Es el porcentaje de descuento del item (cuando corresponda), si el item
80
+ # no posee descuento se debe asignar 0 (cero) o no incluir el campo en el
81
+ # documento.
82
+ attr_accessor :descuento_pct
83
+
84
+ # Es el valor de descuento del item (cuando corresponda), si el item no
85
+ # posee descuento se debe asignar 0 (cero) o no incluir el campo en el
86
+ # documento.
87
+ attr_accessor :descuento_monto
88
+
89
+ # Es el porcentaje de recargo del item (cuando corresponda), si el item
90
+ # no posee recargo se debe asignar 0 (cero) o no incluir el campo en el
91
+ # documento.
92
+ attr_accessor :recargo_pct
93
+
94
+ # Es el valor de recargo del item (cuando corresponda), si el item no
95
+ # posee recargo se debe asignar 0 (cero) o no incluir el campo en el
96
+ # documento.
97
+ attr_accessor :recargo_monto
7
98
 
8
99
  def initialize(params = {})
9
100
  @nro_lin_det = params[:nro_lin_det]
10
- @tpo_codigo = params[:tpo_codigo]
101
+ @tpo_codigo = params[:tpo_codigo] || 'INT1'
11
102
  @vlr_codigo = params[:vlr_codigo]
12
- @ind_exe = params[:ind_exe]
13
- @rut_mandante = params[:rut_mandante]
103
+ @ind_exe = /^[0126]$/ =~ params[:ind_exe].to_s ? params[:ind_exe].to_s : '0'
14
104
  @nmb_item = params[:nmb_item]
15
- @dsc_item = params[:dsc_item]
16
- @qty_item = params[:qty_item]
17
- @unmd_item = params[:unmd_item]
18
- @prc_item = params[:prc_item]
105
+ @qty_item = params[:qty_item].to_f.round(6)
106
+ @prc_item = params[:prc_item].to_f.round(2)
19
107
  @monto_item = params[:monto_item]
108
+ @rut_mandante = params[:rut_mandante]
109
+ @dsc_item = params[:dsc_item]
110
+ @unmd_item = params[:unmd_item] || 'UN'
111
+ @descuento_pct = params[:descuento_pct]
112
+ @descuento_monto = params[:descuento_monto]
113
+ @recargo_pct = params[:recargo_pct]
114
+ @recargo_monto = params[:recargo_monto]
20
115
  end
21
116
 
22
117
  def as_node
@@ -25,15 +120,39 @@ module Facturapi
25
120
  detalle << create_node('TpoCodigo') { |n| n << tpo_codigo }
26
121
  detalle << create_node('VlrCodigo') { |n| n << vlr_codigo }
27
122
  detalle << create_node('IndExe') { |n| n << ind_exe }
28
- detalle << create_node('RUTMandante') { |n| n << rut_mandante }
29
123
  detalle << create_node('NmbItem') { |n| n << nmb_item }
30
- detalle << create_node('DscItem') { |n| n << dsc_item }
31
124
  detalle << create_node('QtyItem') { |n| n << qty_item }
32
- detalle << create_node('UnmdItem') { |n| n << unmd_item }
33
125
  detalle << create_node('PrcItem') { |n| n << prc_item }
34
126
  detalle << create_node('MontoItem') { |n| n << monto_item }
127
+ detalle << create_node('RUTMandante') { |n| n << rut_mandante } if rut_mandante
128
+ detalle << create_node('DscItem') { |n| n << dsc_item } if dsc_item
129
+ detalle << create_node('UnmdItem') { |n| n << unmd_item } if unmd_item
130
+ detalle << create_node('DescuentoPct') { |n| n << descuento_pct } if descuento_pct
131
+ detalle << create_node('DescuentoMonto') { |n| n << descuento_monto } if descuento_monto
132
+ detalle << create_node('RecargoPct') { |n| n << recargo_pct } if recargo_pct
133
+ detalle << create_node('RecargoMonto') { |n| n << recargo_monto } if recargo_monto
35
134
  end
36
135
  end
136
+
137
+ def autocomplete!
138
+ self.monto_item = (prc_item * qty_item).to_i if monto_item.blank?
139
+ end
140
+
141
+ def afecto_iva?
142
+ ind_exe == '0'
143
+ end
144
+
145
+ def exento_iva?
146
+ ind_exe == '1'
147
+ end
148
+
149
+ def no_fact?
150
+ ind_exe == '2'
151
+ end
152
+
153
+ def no_fact_neg?
154
+ ind_exe == '6'
155
+ end
37
156
  end
38
157
  end
39
158
  end