facturacr 1.0.6 → 1.1.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.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/facturacr.gemspec +2 -2
  3. data/lib/facturacr.rb +25 -19
  4. data/lib/facturacr/api.rb +5 -4
  5. data/lib/facturacr/builder.rb +4 -4
  6. data/lib/facturacr/configuration.rb +18 -9
  7. data/lib/facturacr/credit_note.rb +24 -13
  8. data/lib/facturacr/data.rb +41 -0
  9. data/lib/facturacr/data_provider.rb +1 -1
  10. data/lib/facturacr/debit_note.rb +25 -13
  11. data/lib/facturacr/document.rb +120 -69
  12. data/lib/facturacr/document/exoneration.rb +17 -12
  13. data/lib/facturacr/document/fax.rb +1 -4
  14. data/lib/facturacr/document/identification_document.rb +7 -10
  15. data/lib/facturacr/document/issuer.rb +31 -32
  16. data/lib/facturacr/document/item.rb +77 -20
  17. data/lib/facturacr/document/location.rb +19 -23
  18. data/lib/facturacr/document/other_charges.rb +56 -0
  19. data/lib/facturacr/document/other_content.rb +30 -0
  20. data/lib/facturacr/document/other_content/price_smart.rb +58 -0
  21. data/lib/facturacr/document/other_text.rb +4 -8
  22. data/lib/facturacr/document/phone.rb +1 -3
  23. data/lib/facturacr/document/phone_type.rb +6 -9
  24. data/lib/facturacr/document/receiver.rb +28 -19
  25. data/lib/facturacr/document/reference.rb +36 -18
  26. data/lib/facturacr/document/regulation.rb +3 -3
  27. data/lib/facturacr/document/summary.rb +54 -22
  28. data/lib/facturacr/document/tax.rb +43 -21
  29. data/lib/facturacr/element.rb +9 -0
  30. data/lib/facturacr/error.rb +11 -0
  31. data/lib/facturacr/export_invoice.rb +38 -0
  32. data/lib/facturacr/invoice.rb +27 -15
  33. data/lib/facturacr/purchase_invoice.rb +39 -0
  34. data/lib/facturacr/reception_message.rb +73 -28
  35. data/lib/facturacr/signed_document.rb +4 -4
  36. data/lib/facturacr/signer/signer.rb +20 -8
  37. data/lib/facturacr/ticket.rb +27 -14
  38. data/lib/facturacr/version.rb +1 -1
  39. data/lib/facturacr/xml_document.rb +46 -29
  40. metadata +15 -9
@@ -22,14 +22,24 @@ module FE
22
22
 
23
23
  XADES = "http://uri.etsi.org/01903/v1.3.2#"
24
24
  XADES141 = "http://uri.etsi.org/01903/v1.4.1#"
25
- SIGNATURE_POLICY = "https://tribunet.hacienda.go.cr/docs/esquemas/2016/v4/Resolucion%20Comprobantes%20Electronicos%20%20DGT-R-48-2016.pdf"
25
+ SIGNATURE_POLICY_42 = "https://tribunet.hacienda.go.cr/docs/esquemas/2016/v4/Resolucion%20Comprobantes%20Electronicos%20%20DGT-R-48-2016.pdf"
26
26
 
27
- XMLNS_MAP = {
27
+ XMLNS_MAP_42 = {
28
28
  "FacturaElectronica" => "https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/facturaElectronica",
29
29
  "NotaCreditoElectronica" => "https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/notaCreditoElectronica",
30
30
  "TiqueteElectronico" => "https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/tiqueteElectronico",
31
31
  "NotaDebitoElectronica" => "https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/notaDebitoElectronica",
32
32
  "MensajeReceptor" => "https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/mensajeReceptor"
33
+ }
34
+
35
+ XMLNS_MAP_43 = {
36
+ "FacturaElectronica" => "https://cdn.comprobanteselectronicos.go.cr/xml-schemas/v4.3/facturaElectronica",
37
+ "NotaCreditoElectronica" => "https://cdn.comprobanteselectronicos.go.cr/xml-schemas/v4.3/notaCreditoElectronica",
38
+ "TiqueteElectronico" => "https://cdn.comprobanteselectronicos.go.cr/xml-schemas/v4.3/tiqueteElectronico",
39
+ "NotaDebitoElectronica" => "https://cdn.comprobanteselectronicos.go.cr/xml-schemas/v4.3/notaDebitoElectronica",
40
+ "MensajeReceptor" => "https://cdn.comprobanteselectronicos.go.cr/xml-schemas/v4.3/mensajeReceptor",
41
+ "FacturaElectronicaCompra" => "https://cdn.comprobanteselectronicos.go.cr/xml-schemas/v4.3/facturaElectronicaCompra",
42
+ "FacturaElectronicaExportacion" => "https://cdn.comprobanteselectronicos.go.cr/xml-schemas/v4.3/facturaElectronicaExportacion"
33
43
  }
34
44
 
35
45
  def initialize(args = {})
@@ -44,6 +54,9 @@ module FE
44
54
  @x509 = @p12.certificate
45
55
  @output_path = args[:output_path]
46
56
  @document_tag = @doc.elements.first.name
57
+ @version = @doc.elements.first.namespace.href.scan(/v4\..{1}/).first[1..-1]
58
+ @xmlns_map = XMLNS_MAP_42 if @version.eql?("4.2")
59
+ @xmlns_map = XMLNS_MAP_43 if @version.eql?("4.3")
47
60
  end
48
61
 
49
62
  def sign
@@ -96,7 +109,7 @@ module FE
96
109
  def build_key_info_element
97
110
  builder = Nokogiri::XML::Builder.new
98
111
  attributes = {
99
- "xmlns" => XMLNS_MAP[@document_tag],
112
+ "xmlns" => @xmlns_map[@document_tag],
100
113
  "xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#",
101
114
  "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
102
115
  "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
@@ -119,11 +132,10 @@ module FE
119
132
 
120
133
  def build_signed_properties_element
121
134
  cert_digest = compute_digest(@x509.to_der,algorithm(SHA256))
122
- policy_digest = compute_digest(@x509.to_der,algorithm(SHA256))
123
135
  signing_time = DateTime.now.rfc3339
124
136
  builder = Nokogiri::XML::Builder.new
125
137
  attributes = {
126
- "xmlns"=>XMLNS_MAP[@document_tag],
138
+ "xmlns"=>@xmlns_map[@document_tag],
127
139
  "xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#",
128
140
  "xmlns:xades" => "http://uri.etsi.org/01903/v1.3.2#",
129
141
  "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
@@ -140,7 +152,7 @@ module FE
140
152
  xcd.send("ds:DigestValue", cert_digest)
141
153
  end
142
154
  c.send("xades:IssuerSerial") do |is|
143
- is.send("ds:X509IssuerName", @x509.issuer.to_a.reverse.map{|c| c[0..1].join("=")}.join(", "))
155
+ is.send("ds:X509IssuerName", @x509.issuer.to_a.reverse.map{|x| x[0..1].join("=")}.join(", "))
144
156
  is.send("ds:X509SerialNumber", @x509.serial.to_s)
145
157
  end
146
158
  end
@@ -149,7 +161,7 @@ module FE
149
161
  ssp.send("xades:SignaturePolicyIdentifier") do |spi|
150
162
  spi.send("xades:SignaturePolicyId") do |spi2|
151
163
  spi2.send("xades:SigPolicyId") do |spi3|
152
- spi3.send("xades:Identifier", SIGNATURE_POLICY)
164
+ spi3.send("xades:Identifier", SIGNATURE_POLICY_42)
153
165
  spi3.send("xades:Description")
154
166
  end
155
167
 
@@ -176,7 +188,7 @@ module FE
176
188
 
177
189
  builder = builder = Nokogiri::XML::Builder.new
178
190
  attributes = {
179
- "xmlns"=>XMLNS_MAP[@document_tag],
191
+ "xmlns"=>@xmlns_map[@document_tag],
180
192
  "xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#",
181
193
  "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
182
194
  "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance"
@@ -1,34 +1,47 @@
1
- require 'facturacr/document'
1
+ require 'facturacr/document'
2
2
 
3
3
  module FE
4
-
4
+
5
5
  class Ticket < Document
6
-
6
+ NAMESPACES ={
7
+ "4.2" => {
8
+ "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
9
+ "xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
10
+ "xmlns"=>"https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/tiqueteElectronico"
11
+ },
12
+ "4.3" => {
13
+ "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
14
+ "xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
15
+ "xmlns"=>"https://cdn.comprobanteselectronicos.go.cr/xml-schemas/v4.3/tiqueteElectronico"#,
16
+ }
17
+ }
18
+ DOCUMENT_TYPE = "04"
19
+
7
20
  def initialize(args={})
21
+ @version = args[:version]
22
+ @economic_activity = args[:economic_activity]
8
23
  @date = args[:date]
9
24
  @issuer = args[:issuer]
10
25
  @receiver = args[:receiver]
11
26
  @items = args[:items]
12
27
  @number = args[:number]
13
28
  @condition = args[:condition]
14
- @payment_type = args[:payment_type] || "01"
15
- @document_type = "04"
29
+ @payment_type = args[:payment_type] || ["01"]
30
+ @document_type = DOCUMENT_TYPE
16
31
  @credit_term = args[:credit_term]
17
32
  @summary = args[:summary]
33
+ @other_charges = args[:other_charges]
18
34
  @regulation = args[:regulation] ||= FE::Document::Regulation.new
19
35
  @security_code = args[:security_code]
20
36
  @document_situation = args[:document_situation]
21
- @namespaces = {
22
- "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
23
- "xmlns:xsd"=>"http://www.w3.org/2001/XMLSchema",
24
- "xmlns"=>"https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/tiqueteElectronico"
25
- }
37
+ @namespaces = NAMESPACES[@version]
26
38
  @others = args[:others] || []
39
+ @references = args[:references] || []
27
40
  end
28
-
41
+
29
42
  def document_tag
30
43
  "TiqueteElectronico"
31
44
  end
32
-
33
- end
34
- end
45
+
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module FE
2
- VERSION = "1.0.6"
2
+ VERSION = "1.1.1"
3
3
  end
@@ -2,24 +2,24 @@ require 'nokogiri'
2
2
 
3
3
  require 'facturacr/document'
4
4
 
5
- module FE
5
+ module FE
6
6
  class XmlDocument
7
-
8
- attr_accessor :document, :root_tag
9
-
7
+
8
+ attr_accessor :document, :root_tag, :doc, :xml
9
+
10
10
  def initialize(xml_provider)
11
11
  # Backwards compatibility with v0.1.4
12
12
  if xml_provider.is_a?(String)
13
- raise ArgumentError, "File: #{xml_provider} does not exist" unless File.exists?(xml_provider)
13
+ raise ArgumentError, "File: #{xml_provider} does not exist" unless File.exist?(xml_provider)
14
14
  xml_provider = FE::DataProvider.new(:file, xml_provider)
15
15
  end
16
16
  raise ArgumentError, "Invalid Argument" unless xml_provider.is_a?(FE::DataProvider)
17
-
18
- @doc = Nokogiri::XML(xml_provider.contents) do |config|
17
+ @xml = xml_provider.contents
18
+ @doc = Nokogiri::XML(@xml) do |config|
19
19
  config.options = Nokogiri::XML::ParseOptions::NOBLANKS | Nokogiri::XML::ParseOptions::NOENT
20
20
  end
21
21
  root_tag = @doc.elements.first.name
22
-
22
+
23
23
  if root_tag.eql?('FacturaElectronica')
24
24
  @document = FE::Invoice.new
25
25
  elsif root_tag.eql?("NotaCreditoElectronica")
@@ -30,10 +30,16 @@ module FE
30
30
  @document = FE::Ticket.new
31
31
  elsif root_tag.eql?("MensajeReceptor")
32
32
  @document = FE::ReceptionMessage.new
33
+ else
34
+ @document = nil
33
35
  end
34
-
36
+
35
37
  if @document.is_a?(FE::Document)
36
- @document.date = DateTime.parse(@doc.css("#{root_tag} FechaEmision").text)
38
+ @document.version = @doc.elements.first.namespace.href.scan(/v4\..{1}/).first[1..-1]
39
+ @document.date = DateTime.parse(@doc.css("#{root_tag} FechaEmision").first&.text)
40
+ if @document.version_43?
41
+ @document.economic_activity = @doc.css("#{root_tag} CodigoActividad").text
42
+ end
37
43
  @key = @doc.css("#{root_tag} Clave").text
38
44
  @document.key = @key if @key.present?
39
45
  @document.headquarters = @key[21..23]
@@ -54,7 +60,7 @@ module FE
54
60
  location.district = @doc.css("#{root_tag} Emisor Ubicacion Distrito").text
55
61
  location.others = @doc.css("#{root_tag} Emisor Ubicacion OtrasSenas").text
56
62
  @issuer.location = location
57
-
63
+
58
64
  if !@doc.css("#{root_tag} Emisor Telefono").empty?
59
65
  @issuer.phone = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text
60
66
  end
@@ -62,19 +68,19 @@ module FE
62
68
  @issuer.fax = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Emisor Telefono CodigoPais").text
63
69
  end
64
70
  @issuer.email = @doc.css("#{root_tag} Emisor CorreoElectronico").text
65
-
71
+
66
72
  unless @doc.css("#{root_tag} Receptor").empty?
67
73
  @receiver = FE::Document::Receiver.new
68
74
  @receiver.name = @doc.css("#{root_tag} Receptor Nombre").text
69
75
  unless @doc.css("#{root_tag} Receptor Identificacion").empty?
70
76
  @receiver.identification_document = FE::Document::IdentificationDocument.new type: @doc.css("#{root_tag} Receptor Identificacion Tipo").text, number: @doc.css("#{root_tag} Receptor Identificacion Numero").text.to_i
71
77
  end
72
-
78
+
73
79
  unless @doc.css("#{root_tag} Receptor IdentificacionExtranjero").empty?
74
80
  @receiver.foreign_id_number = @doc.css("#{root_tag} Receptor IdentificacionExtranjero").text
75
81
  end
76
82
  @receiver.comercial_name = @doc.css("#{root_tag} Receptor NombreComercial").text unless @doc.css("#{root_tag} Receptor NombreComercial").empty?
77
-
83
+
78
84
  unless @doc.css("#{root_tag} Receptor Ubicacion").empty?
79
85
  location = FE::Document::Location.new
80
86
  location.province = @doc.css("#{root_tag} Receptor Ubicacion Provincia").text
@@ -83,7 +89,7 @@ module FE
83
89
  location.others = @doc.css("#{root_tag} Receptor Ubicacion OtrasSenas").text
84
90
  @receiver.location = location
85
91
  end
86
-
92
+
87
93
  if !@doc.css("#{root_tag} Receptor Telefono").empty?
88
94
  @issuer.phone = FE::Document::Phone.new country_code: @doc.css("#{root_tag} Receptor Telefono CodigoPais").text, number: @doc.css("#{root_tag} Receptor Telefono CodigoPais").text
89
95
  end
@@ -96,7 +102,13 @@ module FE
96
102
  @doc.css("#{root_tag} DetalleServicio LineaDetalle").each do |line|
97
103
  item = FE::Document::Item.new
98
104
  item.line_number = line.css("NumeroLinea").text.to_i
99
- item.code = line.css("Codigo Codigo").text
105
+ if @document.version_42?
106
+ item.code = line.css("Codigo Codigo").text
107
+ elsif @document.version_43?
108
+ code = line > "Codigo"
109
+ item.code = code.text
110
+ item.comercial_code = line.css("CodigoComercial Codigo").text
111
+ end
100
112
  item.quantity = line.css("Cantidad").text
101
113
  item.unit = line.css("UnidadMedida").text
102
114
  item.description = line.css("Detalle").text
@@ -120,17 +132,22 @@ module FE
120
132
  exo.percentage = line.css("Exoneracion PorcentajeCompra").text.to_i
121
133
  t_args[:exoneration] = exo
122
134
  end
123
-
135
+
124
136
  item.taxes << FE::Document::Tax.new(t_args)
125
137
  end
126
138
  @items << item
127
139
  end
128
140
 
129
-
141
+
130
142
  @summary = FE::Document::Summary.new
131
143
  sum = @doc.css("#{root_tag} ResumenFactura")
132
- @summary.currency = sum.css("CodigoMoneda").text
133
- @summary.exchange_rate = sum.css("TipoCambio").text.to_f
144
+ if @document.version_42?
145
+ @summary.currency = sum.css("CodigoMoneda").text
146
+ @summary.exchange_rate = sum.css("TipoCambio").text.to_f
147
+ elsif @document.version_43?
148
+ @summary.currency = sum.css("CodigoTipoMoneda CodigoMoneda").text
149
+ @summary.exchange_rate = sum.css("CodigoTipoMoneda TipoCambio").text.to_f
150
+ end
134
151
  @summary.services_taxable_total = sum.css("TotalServGravados").text.to_f
135
152
  @summary.services_exent_total = sum.css("TotalServExentos").text.to_f
136
153
  @summary.goods_taxable_total = sum.css("TotalMercanciasGravadas").text.to_f
@@ -142,7 +159,7 @@ module FE
142
159
  @summary.gross_total = sum.css("TotalVentaNeta").text.to_f
143
160
  @summary.tax_total = sum.css("TotalImpuesto").text.to_f
144
161
  @summary.net_total = sum.css("TotalComprobante").text.to_f
145
-
162
+
146
163
  refs = @doc.css("#{root_tag} InformacionReferencia")
147
164
  @references = []
148
165
  unless refs.empty?
@@ -156,20 +173,20 @@ module FE
156
173
  @references << reference
157
174
  end
158
175
  end
159
-
176
+
160
177
  reg = @doc.css("#{root_tag} Normativa")
161
178
  @regulation = FE::Document::Regulation.new
162
179
  @regulation.number = reg.css("NumeroResolucion").text
163
180
  @regulation.date = reg.css("FechaResolucion").text
164
-
165
-
181
+
182
+
166
183
  @document.issuer = @issuer
167
184
  @document.receiver = @receiver
168
185
  @document.items = @items
169
186
  @document.summary = @summary
170
187
  @document.references = @references
171
- @document.regulation = @regulation
172
- else
188
+ @document.regulation = @regulation
189
+ elsif @document.present?
173
190
  @document.date = DateTime.parse(@doc.css("#{root_tag} FechaEmisionDoc").text)
174
191
  @key = @doc.css("#{root_tag} Clave").text
175
192
  @document.key = @key
@@ -182,11 +199,11 @@ module FE
182
199
  @document.security_code = @key[42..-1]
183
200
  @document.total = @doc.css("#{root_tag} TotalFactura").text
184
201
  @document.tax = @doc.css("#{root_tag} MontoTotalImpuesto").text
185
- end
202
+ end
186
203
  end
187
-
204
+
188
205
  def has_tax_node?
189
206
  @doc.css("#{root_tag} ResumenFactura TotalImpuesto").any?
190
207
  end
191
208
  end
192
- end
209
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: facturacr
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josef Sauter
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-12 00:00:00.000000000 Z
11
+ date: 2020-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: 12.3.3
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: 12.3.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +178,7 @@ files:
178
178
  - lib/facturacr/cli/generate.rb
179
179
  - lib/facturacr/configuration.rb
180
180
  - lib/facturacr/credit_note.rb
181
+ - lib/facturacr/data.rb
181
182
  - lib/facturacr/data_provider.rb
182
183
  - lib/facturacr/debit_note.rb
183
184
  - lib/facturacr/document.rb
@@ -188,6 +189,9 @@ files:
188
189
  - lib/facturacr/document/issuer.rb
189
190
  - lib/facturacr/document/item.rb
190
191
  - lib/facturacr/document/location.rb
192
+ - lib/facturacr/document/other_charges.rb
193
+ - lib/facturacr/document/other_content.rb
194
+ - lib/facturacr/document/other_content/price_smart.rb
191
195
  - lib/facturacr/document/other_text.rb
192
196
  - lib/facturacr/document/phone.rb
193
197
  - lib/facturacr/document/phone_type.rb
@@ -196,7 +200,11 @@ files:
196
200
  - lib/facturacr/document/regulation.rb
197
201
  - lib/facturacr/document/summary.rb
198
202
  - lib/facturacr/document/tax.rb
203
+ - lib/facturacr/element.rb
204
+ - lib/facturacr/error.rb
205
+ - lib/facturacr/export_invoice.rb
199
206
  - lib/facturacr/invoice.rb
207
+ - lib/facturacr/purchase_invoice.rb
200
208
  - lib/facturacr/reception_message.rb
201
209
  - lib/facturacr/signed_document.rb
202
210
  - lib/facturacr/signer/signer.rb
@@ -233,10 +241,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
233
241
  - !ruby/object:Gem::Version
234
242
  version: '0'
235
243
  requirements: []
236
- rubyforge_project:
237
- rubygems_version: 2.4.6
244
+ rubygems_version: 3.0.6
238
245
  signing_key:
239
246
  specification_version: 4
240
247
  summary: Facturación Electrónica de Costa Rica
241
248
  test_files: []
242
- has_rdoc: