nubefact 0.0.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 334a6ea69d81677919e57612d6ffb3b2f781a17f
4
+ data.tar.gz: 54c4acd5cdf9f73ca74d9a245a5e0bbfa3cbf743
5
+ SHA512:
6
+ metadata.gz: 16700cd9ab376dd903148f1cd4ae9158dc4e66dabbf8360842aba3e77b9bce84afa1b62c7405d85b96504b794f6de981bae89789a85c0dba8b4a8ff12c83c473
7
+ data.tar.gz: df676318a355cdce1080ca465deb481d7e79de9d038b92e7b88b3560506ff16ee900644a1eb807c747157ae985a742619a32ca1d1afd761dd22f9251a085dcff
@@ -0,0 +1,50 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
@@ -0,0 +1,3 @@
1
+ SimpleCov.start do
2
+ add_group 'lib', 'lib'
3
+ end
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at andfb18@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nubefact.gemspec
4
+ gemspec
5
+
6
+
7
+ group :development do
8
+ gem 'pry'
9
+ end
10
+
11
+ group :test do
12
+ gem 'rspec', '~> 3.6'
13
+ gem 'simplecov', '~> 0.15', require: false
14
+ gem 'webmock'
15
+ end
@@ -0,0 +1,61 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ nubefact (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.5.2)
10
+ public_suffix (>= 2.0.2, < 4.0)
11
+ coderay (1.1.2)
12
+ crack (0.4.3)
13
+ safe_yaml (~> 1.0.0)
14
+ diff-lcs (1.3)
15
+ docile (1.1.5)
16
+ hashdiff (0.3.6)
17
+ json (2.1.0)
18
+ method_source (0.9.0)
19
+ pry (0.11.1)
20
+ coderay (~> 1.1.0)
21
+ method_source (~> 0.9.0)
22
+ public_suffix (3.0.0)
23
+ rake (10.5.0)
24
+ rspec (3.6.0)
25
+ rspec-core (~> 3.6.0)
26
+ rspec-expectations (~> 3.6.0)
27
+ rspec-mocks (~> 3.6.0)
28
+ rspec-core (3.6.0)
29
+ rspec-support (~> 3.6.0)
30
+ rspec-expectations (3.6.0)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.6.0)
33
+ rspec-mocks (3.6.0)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.6.0)
36
+ rspec-support (3.6.0)
37
+ safe_yaml (1.0.4)
38
+ simplecov (0.15.1)
39
+ docile (~> 1.1.0)
40
+ json (>= 1.8, < 3)
41
+ simplecov-html (~> 0.10.0)
42
+ simplecov-html (0.10.2)
43
+ webmock (3.1.0)
44
+ addressable (>= 2.3.6)
45
+ crack (>= 0.3.2)
46
+ hashdiff
47
+
48
+ PLATFORMS
49
+ ruby
50
+
51
+ DEPENDENCIES
52
+ bundler (~> 1.13)
53
+ nubefact!
54
+ pry
55
+ rake (~> 10.0)
56
+ rspec (~> 3.6)
57
+ simplecov (~> 0.15)
58
+ webmock
59
+
60
+ BUNDLED WITH
61
+ 1.15.3
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Arnold Roa
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 all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1,66 @@
1
+ # NubeFact
2
+
3
+ Ruby gem to consume NubeFact API to generate electronic tax document in PERU.
4
+
5
+ Currently only has an interface to create invoice, but can be used easily to consume other operations.
6
+
7
+ NubeFact API documentation: https://docs.google.com/document/d/1QWWSILBbjd4MDkJl7vCkL2RZvkPh0IC7Wa67BvoYIhA/edit
8
+
9
+ Se pueden hacer 4 tipos de operaciones con nuestra API:
10
+
11
+ ```
12
+ OPERACIÓN 1: GENERAR FACTURAS, BOLETAS Y NOTAS
13
+ OPERACIÓN 2: CONSULTA DE FACTURAS, BOLETAS Y NOTAS
14
+ OPERACIÓN 3: GENERAR ANULACIÓN DE FACTURAS, BOLETAS Y NOTAS
15
+ OPERACIÓN 4: CONSULTA ANULACIÓN DE FACTURAS, BOLETAS Y NOTAS
16
+ ```
17
+
18
+ ## How to use:
19
+
20
+ ```ruby
21
+
22
+ # Set your url_token and api_token.
23
+ # If you are using rails copy this 2 lines to config/initilizers/nubefact.rb
24
+ NubeFact.url_token = '93123123-ecfc-4496-ac6e-8add6940e238'
25
+ NubeFact.api_token = '29842498b15ff41f9817f036b23182e789d5a04f28ca14255822a59bfcee00e4e'
26
+ ```
27
+
28
+ ## Create an Electronic Invoice
29
+
30
+ ```ruby
31
+ # create a new Invoice object
32
+ invoice = NubeFact::Invoice.new({
33
+ serie: 'F001',
34
+ numero: 2,
35
+ sunat_transaction: 2,
36
+ cliente_tipo_de_documento: 0,
37
+ cliente_numero_de_documento: 'AP990427',
38
+ cliente_denominacion: 'Bugs Bunny',
39
+ cliente_direccion: 'Kra 11 11 A',
40
+ cliente_email: 'nubefact@mailinator.com',
41
+ moneda: 2,
42
+ tipo_de_cambio: 3.25,
43
+ porcentaje_de_igv: 0,
44
+ total_inafecta: 65.00,
45
+ total: 65.00,
46
+ enviar_automaticamente_a_la_sunat: false,
47
+ enviar_automaticamente_al_cliente: true,
48
+ codigo_unico: 'ABC',
49
+ formato_de_pdf: 'A5'
50
+ })
51
+
52
+ # Add items
53
+ # You don't need to add the fields that are calculated like total or igv
54
+ # those got calculated automatically.
55
+
56
+ invoice.add_item({
57
+ unidad_de_medida: 'ZZ',
58
+ descripcion: 'Osito de peluche de taiwan',
59
+ cantidad: 1,
60
+ valor_unitario: 65.00,
61
+ tipo_de_igv: 16,
62
+ })
63
+
64
+ result = invoice.deliver
65
+
66
+ ```
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "peru_sunat_ruc"
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
@@ -0,0 +1,8 @@
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
@@ -0,0 +1,60 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'openssl'
4
+ require 'json'
5
+
6
+ module NubeFact; end
7
+
8
+ require "util/validator"
9
+ require "util/utils"
10
+
11
+ require "nube_fact/version"
12
+ require "nube_fact/exceptions"
13
+ require "nube_fact/invoice"
14
+ require 'nube_fact/invoice/guia'
15
+ require 'nube_fact/invoice/item'
16
+
17
+ module NubeFact
18
+ API_BASE = 'https://www.nubefact.com/api/v1'
19
+
20
+ READ_TIMEOUT = 120
21
+ LIST_TIMEOUT = 360
22
+
23
+ DATE_FORMAT = "%d-%m-%Y"
24
+
25
+ extend self
26
+
27
+ attr_accessor :url_token
28
+ attr_accessor :api_token
29
+
30
+ def request(data)
31
+ raise NotConfigured unless url_token && api_token
32
+
33
+ http = Net::HTTP.new(url.host, url.port)
34
+ http.read_timeout = READ_TIMEOUT
35
+ http.use_ssl = true
36
+ # http.verify_mode = OpenSSL::SSL::VERIFY_NONE
37
+
38
+ request = Net::HTTP::Post.new(url)
39
+ request.body = data.to_json
40
+
41
+ request["Authorization"] = 'Token token="%s"' % api_token
42
+ request["Content-Type"] = 'application/json'
43
+ request["cache-control"] = 'no-cache'
44
+
45
+ response = http.request request
46
+
47
+ # ToDO evaluate response code (not authorized, 500, etc)
48
+
49
+ result = JSON.parse(response.read_body)
50
+ if result['errors']
51
+ raise ErrorResponse.new "#{result['codigo']}: #{result['errors']}"
52
+ end
53
+
54
+ result
55
+ end
56
+
57
+ def url
58
+ URI("#{API_BASE}/#{url_token}")
59
+ end
60
+ end
@@ -0,0 +1,23 @@
1
+ # CÓDIGO - DESCRIPCIÓN
2
+ # 10 - No se pudo autenticar, token incorrecto o eliminado
3
+ # 11 - La ruta o URL que estás usando no es correcta o no existe.
4
+ # Ingresa a tu cuenta en www.nubefact.com en la opción Api-Integración para verificar este dato
5
+ # 12 - Solicitud incorrecta, la cabecera (Header) no contiene un Content-Type correcto
6
+ # 20 - El archivo enviado no cumple con el formato establecido
7
+ # 21 - No se pudo completar la operación, se acompaña el problema con un mensaje
8
+ # 22 - Documento enviado fuera del plazo permitido
9
+ # 23 - Este documento ya existe en NubeFacT
10
+ # 24 - El documento indicado no existe o no fue enviado a NubeFacT
11
+ # 40 - Error interno desconocido
12
+ # 50 - Su cuenta ha sido suspendida
13
+ # 51 - Su cuenta ha sido suspendida por falta de pago
14
+
15
+ module NubeFact
16
+ # Request Related
17
+ class NotConfigured < StandardError; end
18
+ class ErrorResponse < StandardError; end
19
+
20
+ # Data Related
21
+ class ValidationError < StandardError; end
22
+ class InvalidField < StandardError; end
23
+ end
@@ -0,0 +1,146 @@
1
+ # https://docs.google.com/document/d/1QWWSILBbjd4MDkJl7vCkL2RZvkPh0IC7Wa67BvoYIhA/edit
2
+
3
+
4
+ class NubeFact::Invoice
5
+ include NubeFact::Validator
6
+ include NubeFact::Utils
7
+
8
+ FIELDS = [
9
+ "operacion",
10
+ "tipo_de_comprobante", # 1=FACTURA 2=BOLETA 3=NOTA CREDITO 4 NOTA DEBITO
11
+ "serie", # F para FACTURA | B PARA BOLETA
12
+ "numero",
13
+ "sunat_transaction",
14
+ # 1 = VENTA INTERNA
15
+ # 2 = EXPORTACIÓN
16
+ # 3 = NO DOMICILIADO
17
+ # 4 = VENTA INTERNA – ANTICIPOS
18
+ # 5 = VENTA ITINERANTE
19
+ # 6 = FACTURA GUÍA
20
+ # 7 = VENTA ARROZ PILADO
21
+ # 8 = FACTURA - COMPROBANTE DE PERCEPCIÓN
22
+ # 10 = FACTURA - GUÍA REMITENTE
23
+ # 11 = FACTURA - GUÍA TRANSPORTISTA
24
+ # 12 = BOLETA DE VENTA – COMPROBANTE DE PERCEPCIÓN
25
+ # 13 = GASTO DEDUCIBLE PERSONA NATURAL
26
+
27
+ "cliente_tipo_de_documento",
28
+ # 6 = RUC - REGISTRO ÚNICO DE CONTRIBUYENTE
29
+ # 1 = DNI - DOC. NACIONAL DE IDENTIDAD
30
+ # - = VARIOS - VENTAS MENORES A S/.700.00 Y OTROS
31
+ # 4 = CARNET DE EXTRANJERÍA
32
+ # 7 = PASAPORTE
33
+ # A = CÉDULA DIPLOMÁTICA DE IDENTIDAD
34
+ # 0 = NO DOMICILIADO, SIN RUC (EXPORTACIÓN)
35
+
36
+ "cliente_numero_de_documento",
37
+ "cliente_denominacion",
38
+ "cliente_direccion",
39
+ "cliente_email",
40
+ "cliente_email_1",
41
+ "cliente_email_2",
42
+
43
+ "fecha_de_emision",
44
+ "fecha_de_vencimiento",
45
+ "moneda",
46
+ # 1 = SOLES
47
+ # 2 = DÓLARES
48
+ # 3 = EUROS
49
+ "tipo_de_cambio",
50
+
51
+ "porcentaje_de_igv",
52
+ "descuento_global",
53
+ "total_descuento",
54
+ "total_anticipo",
55
+ "total_gravada",
56
+ "total_inafecta",
57
+ "total_exonerada",
58
+ "total_igv",
59
+ "total_gratuita",
60
+ "total_otros_cargos",
61
+ "total",
62
+
63
+ "percepcion_tipo",
64
+ "percepcion_base_imponible",
65
+ "total_percepcion",
66
+ "total_incluido_percepcion",
67
+ "detraccion",
68
+
69
+ "observaciones",
70
+
71
+ "documento_que_se_modifica_tipo",
72
+ "documento_que_se_modifica_serie",
73
+ "documento_que_se_modifica_numero",
74
+
75
+ "tipo_de_nota_de_credito",
76
+ "tipo_de_nota_de_debito",
77
+
78
+ "enviar_automaticamente_a_la_sunat",
79
+ "enviar_automaticamente_al_cliente",
80
+
81
+ "codigo_unico",
82
+ "condiciones_de_pago",
83
+ "medio_de_pago",
84
+ "placa_vehiculo",
85
+ "orden_compra_servicio",
86
+ "tabla_personalizada_codigo",
87
+ "formato_de_pdf",
88
+
89
+ "items",
90
+ "guias"
91
+ ]
92
+
93
+ attr_accessor *FIELDS
94
+
95
+ REQUIRED_FIELDS = %i(
96
+ serie
97
+ numero
98
+ sunat_transaction
99
+ cliente_tipo_de_documento
100
+ cliente_numero_de_documento
101
+ cliente_denominacion
102
+ cliente_direccion
103
+ fecha_de_emision
104
+ moneda
105
+ porcentaje_de_igv
106
+ total
107
+ )
108
+
109
+ DEFAULT_DATA = {
110
+ operacion: 'generar_comprobante',
111
+ tipo_de_comprobante: 1,
112
+ serie: 'F',
113
+ sunat_transaction: 1,
114
+ fecha_de_emision: -> { Time.now.strftime(NubeFact::DATE_FORMAT) },
115
+ porcentaje_de_igv: 18,
116
+ moneda: 1
117
+ }
118
+
119
+ def initialize(data_hash)
120
+ @items = []
121
+ @guias = []
122
+
123
+ load_data_from_param data_hash
124
+ end
125
+
126
+ def add_item(item)
127
+ if item.is_a? Hash
128
+ item = Item.new self, item
129
+ end
130
+ @items << item
131
+ end
132
+
133
+ def add_guia(guia)
134
+
135
+ end
136
+
137
+ def deliver
138
+ if items.empty?
139
+ raise NubeFact::ValidationError.new "At least one item have to be present"
140
+ end
141
+ validate!
142
+
143
+ NubeFact.request to_h
144
+ end
145
+
146
+ end
@@ -0,0 +1,4 @@
1
+ class NubeFact::Invoice::Item
2
+ attr_accessor "guia_tipo",
3
+ "guia_serie_numero"
4
+ end
@@ -0,0 +1,98 @@
1
+ class NubeFact::Invoice::Item
2
+ include NubeFact::Validator
3
+ include NubeFact::Utils
4
+
5
+ FIELDS = [
6
+ "unidad_de_medida",
7
+ # NIU = PRODUCTO
8
+ # ZZ = SERVICIO
9
+ # Puedes crear mas unidades en tu cuenta de NUBEFACT.
10
+ "codigo",
11
+ "descripcion",
12
+ "cantidad",
13
+ "valor_unitario",
14
+ # sin IGV
15
+ "precio_unitario",
16
+ # con IGV
17
+ "descuento",
18
+ "subtotal",
19
+ # @ToDO calcular: VALOR_UNITARIO * CANTIDAD - DESCUENTO
20
+ "tipo_de_igv",
21
+ # 1 = Gravado - Operación Onerosa
22
+ # 2 = Gravado – Retiro por premio
23
+ # 3 = Gravado – Retiro por donación
24
+ # 4 = Gravado – Retiro
25
+ # 5 = Gravado – Retiro por publicidad
26
+ # 6 = Gravado – Bonificaciones
27
+ # 7 = Gravado – Retiro por entrega a trabajadores
28
+ # 8 = Exonerado - Operación Onerosa
29
+ # 9 = Inafecto - Operación Onerosa
30
+ # 10 = Inafecto – Retiro por Bonificación
31
+ # 11 = Inafecto – Retiro
32
+ # 12 = Inafecto – Retiro por Muestras Médicas
33
+ # 13 = Inafecto - Retiro por Convenio Colectivo
34
+ # 14 = Inafecto – Retiro por premio
35
+ # 15 = Inafecto - Retiro por publicidad
36
+ # 16 = Exportación
37
+ "igv",
38
+ # Total de IGV
39
+ "total",
40
+ # Total de la linea
41
+ "anticipo_regularizacion",
42
+ "anticipo_documento_serie",
43
+ "anticipo_documento_numero"
44
+ ]
45
+ attr_accessor *FIELDS
46
+
47
+ REQUIRED_FIELDS = %i(
48
+ unidad_de_medida
49
+ descripcion
50
+ cantidad
51
+ valor_unitario
52
+ tipo_de_igv
53
+ )
54
+
55
+ AUTO_CALCULATED_FIELDS = %i(
56
+ precio_unitario
57
+ subtotal
58
+ igv
59
+ total
60
+ )
61
+
62
+ DEFAULT_DATA = {
63
+ unidad_de_medida: 'ZZ',
64
+ anticipo_regularizacion: false,
65
+ descuento: 0
66
+ }
67
+
68
+ attr_accessor :invoice
69
+ def initialize(invoice, data_hash)
70
+ @invoice = invoice
71
+
72
+ load_data_from_param data_hash
73
+
74
+ validate!
75
+
76
+ calculate_amounts
77
+ end
78
+
79
+ def calculate_amounts
80
+ unit_igv = if should_add_igv?
81
+ ( (valor_unitario / 100) * @invoice.porcentaje_de_igv ).round 2
82
+ else
83
+ 0
84
+ end
85
+
86
+ self.igv = unit_igv * cantidad # total IGV de la linea
87
+
88
+ self.precio_unitario = valor_unitario + unit_igv
89
+ self.subtotal = (valor_unitario * cantidad) - descuento
90
+ self.total = subtotal + igv
91
+ end
92
+
93
+ TYPES_SUBJECT_TO_IGV = [1, 2, 3, 4, 5, 6, 7]
94
+ def should_add_igv?
95
+ # Check description on FIELDS constant
96
+ TYPES_SUBJECT_TO_IGV.include? tipo_de_igv
97
+ end
98
+ end
@@ -0,0 +1,3 @@
1
+ module NubeFact
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,34 @@
1
+ module NubeFact::Utils
2
+ def to_h
3
+ Hash[self.class::FIELDS.map{|field| [field, send(field)]}]
4
+ end
5
+
6
+ def to_json(options = {})
7
+ JSON.generate self.to_h, options
8
+ end
9
+
10
+ private
11
+ def set_default_data
12
+ self.class::DEFAULT_DATA.each do |field, value|
13
+ value = value.call if value.kind_of? Proc
14
+ instance_variable_set("@#{field}", value)
15
+ end
16
+ end
17
+
18
+ def load_data_from_param(data_hash)
19
+ set_default_data
20
+
21
+ data_hash.each do|key, value|
22
+ if self.class.const_defined?('AUTO_CALCULATED_FIELDS') \
23
+ && self.class::AUTO_CALCULATED_FIELDS.include?(key)
24
+ warn("field #{key} will be calculated automatically, you don't need to pass it.")
25
+ end
26
+
27
+ begin
28
+ send "#{key}=", value
29
+ rescue NoMethodError => e
30
+ raise NubeFact::InvalidField.new "Invalid Field: #{key}"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ module NubeFact::Validator
2
+ def validate!
3
+ #ToDO change for a real validator like ActiveModel::Validations or Hanami::Validations
4
+ self.class::REQUIRED_FIELDS.each do |field|
5
+ if send(field).nil?
6
+ raise NubeFact::ValidationError.new "#{field} it's a required field."
7
+ end
8
+ end
9
+ true
10
+ end
11
+ end
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nube_fact/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "nubefact"
8
+ spec.version = NubeFact::VERSION
9
+ spec.authors = ["Arnold Roa"]
10
+ spec.email = ["manolet@gmail.com"]
11
+
12
+ spec.summary = %q{Ruby gem to consume NubeFact API to generate electronic tax document in PERU.}
13
+ spec.description = %q{Ruby gem to consume NubeFact API to generate electronic tax document in PERU.}
14
+ spec.homepage = "https://github.com/neohunter/NubeFact"
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
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.13"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "rspec", "~> 3.6"
36
+ spec.add_development_dependency "simplecov"
37
+ spec.add_development_dependency "webmock"
38
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nubefact
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Arnold Roa
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-10-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Ruby gem to consume NubeFact API to generate electronic tax document
84
+ in PERU.
85
+ email:
86
+ - manolet@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - ".rspec"
93
+ - ".simplecov"
94
+ - CODE_OF_CONDUCT.md
95
+ - Gemfile
96
+ - Gemfile.lock
97
+ - LICENSE
98
+ - README.md
99
+ - Rakefile
100
+ - bin/console
101
+ - bin/setup
102
+ - lib/nube_fact.rb
103
+ - lib/nube_fact/exceptions.rb
104
+ - lib/nube_fact/invoice.rb
105
+ - lib/nube_fact/invoice/guia.rb
106
+ - lib/nube_fact/invoice/item.rb
107
+ - lib/nube_fact/version.rb
108
+ - lib/util/utils.rb
109
+ - lib/util/validator.rb
110
+ - nubefact.gemspec
111
+ homepage: https://github.com/neohunter/NubeFact
112
+ licenses:
113
+ - MIT
114
+ metadata:
115
+ allowed_push_host: https://rubygems.org
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 2.4.6
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: Ruby gem to consume NubeFact API to generate electronic tax document in PERU.
136
+ test_files: []