facturas_xml 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0ca5c9a705fe233cb614e91afb3870f12756cc8c9ef87338bba53fed907d2911
4
+ data.tar.gz: 39d644eaee2264ea9851137898006196206d247f31f5651708cf724abc174d5b
5
+ SHA512:
6
+ metadata.gz: '0368a5ed225ca14b5df7d5011ee45c93de95a76a625353cb801cc1d84e792c2eff3c060d61d2a0b2c75dc2e0beafd256578f7eea93dea5c264c5462c93b23996'
7
+ data.tar.gz: 9fe9025dde8eeb61171b4c6d0600cef4a4f6734ca29009a2c60093a8ad0389743986a300169b79f8b525dd673c07a48e1f23cc90003fa1b99d3b1c91856d1838
@@ -0,0 +1,69 @@
1
+ require 'nokogiri'
2
+ require_relative 'invoice_data'
3
+
4
+ class FacturasXML
5
+ attr_accessor :invoice_data, :signature
6
+
7
+ def self.compra_venta(invoice_data, signature)
8
+ @invoice_data = InvoiceData.new(invoice_data).data
9
+ @signature = signature
10
+
11
+ template = Nokogiri::XML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>')
12
+ Nokogiri::XML::Builder.with(template) do |xml|
13
+ xml.facturaElectronicaCompraVenta('xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance", 'xsi:noNamespaceSchemaLocation': "facturaElectronicaCompraVenta.xsd") {
14
+ self.cabecera(xml)
15
+ @invoice_data[:detalles].each do |data|
16
+ self.detalle(xml, data)
17
+ end
18
+ self.signature(xml)
19
+ }
20
+ end
21
+ end
22
+
23
+ private
24
+ def self.cabecera(xml)
25
+ xml.cabecera {
26
+ InvoiceData.allowed_cabecera_fields.each do |field_name|
27
+ self.invoice_field(xml, @invoice_data[:cabecera], field_name)
28
+ end
29
+ xml.codigoDocumentoSector 1
30
+ }
31
+ end
32
+
33
+ def self.detalle(xml, data)
34
+ xml.detalle {
35
+ InvoiceData.allowed_detalle_fields.each do |field_name|
36
+ self.invoice_field(xml, data, field_name)
37
+ end
38
+ }
39
+ end
40
+
41
+ def self.invoice_field(xml, data, field_name)
42
+ value = data[field_name.to_sym]
43
+ attributes = value ? {} : {'xsi:nil': "true"}
44
+ xml.send(field_name, value, attributes)
45
+ end
46
+
47
+ def self.signature(xml)
48
+ xml.Signature('xmlns': "http://www.w3.org/2000/09/xmldsig#") {
49
+ xml.SignedInfo {
50
+ xml.CanonicalizationMethod('Algorithm': "http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
51
+ xml.SignatureMethod('Algorithm': "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")
52
+ xml.Reference('URI': "") {
53
+ xml.Transforms {
54
+ xml.Transform('Algorithm': "http://www.w3.org/2000/09/xmldsig#enveloped-signature")
55
+ xml.Transform('Algorithm': "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments")
56
+ }
57
+ xml.DigestMethod('Algorithm': "http://www.w3.org/2001/04/xmlenc#sha256")
58
+ xml.DigestValue(@signature[:DiggestValue])
59
+ }
60
+ }
61
+ xml.SignatureValue(@signature[:SignatureValue])
62
+ xml.KeyInfo {
63
+ xml.X509Data {
64
+ xml.X509Certificate(@signature[:X509Certificate])
65
+ }
66
+ }
67
+ }
68
+ end
69
+ end
@@ -0,0 +1,93 @@
1
+ class InvoiceData
2
+ attr_accessor :data
3
+
4
+ ALLOWED_CABECERA_FIELDS = {
5
+ nitEmisor: {mandatory: true},
6
+ razonSocialEmisor: {mandatory: true},
7
+ municipio: {mandatory: true},
8
+ telefono: {mandatory: true},
9
+ numeroFactura: {mandatory: false},
10
+ cuf: {mandatory: true},
11
+ cufd: {mandatory: true},
12
+ codigoSucursal: {mandatory: true},
13
+ direccion: {mandatory: true},
14
+ codigoPuntoVenta: {mandatory: false},
15
+ fechaEmision: {mandatory: true},
16
+ nombreRazonSocial: {mandatory: false},
17
+ codigoTipoDocumentoIdentidad: {mandatory: true},
18
+ numeroDocumento: {mandatory: true},
19
+ complemento: {mandatory: false},
20
+ codigoCliente: {mandatory: true},
21
+ codigoMetodoPago: {mandatory: true},
22
+ numeroTarjeta: {mandatory: false},
23
+ montoTotal: {mandatory: true},
24
+ montoTotalSujetoIva: {mandatory: true},
25
+ codigoMoneda: {mandatory: true},
26
+ tipoCambio: {mandatory: true},
27
+ montoTotalMoneda: {mandatory: true},
28
+ montoGiftCard: {mandatory: false},
29
+ descuentoAdicional: {mandatory: false},
30
+ codigoExcepcion: {mandatory: false},
31
+ cafc: {mandatory: false},
32
+ leyenda: {mandatory: true},
33
+ usuario: {mandatory: true}
34
+ }
35
+
36
+ ALLOWED_DETALLE_FIELDS = {
37
+ actividadEconomica: {mandatory: true},
38
+ codigoProductoSin: {mandatory: true},
39
+ codigoProducto: {mandatory: true},
40
+ descripcion: {mandatory: true},
41
+ cantidad: {mandatory: true},
42
+ unidadMedida: {mandatory: true},
43
+ precioUnitario: {mandatory: true},
44
+ montoDescuento: {mandatory: false},
45
+ subTotal: {mandatory: true},
46
+ numeroSerie: {mandatory: false},
47
+ numeroImei: {mandatory: false}
48
+ }
49
+
50
+ def self.allowed_cabecera_fields
51
+ ALLOWED_CABECERA_FIELDS.keys
52
+ end
53
+
54
+ def self.allowed_detalle_fields
55
+ ALLOWED_DETALLE_FIELDS.keys
56
+ end
57
+
58
+ def initialize(data = {})
59
+ @data = data
60
+
61
+ validate_data
62
+ end
63
+
64
+ private
65
+ def validate_data
66
+ validate_cabecera
67
+ validate_detalles
68
+ end
69
+
70
+ def validate_detalles
71
+ unless @data[:detalles]
72
+ raise "invoice_data debe conteter el attributo detalles"
73
+ end
74
+ end
75
+
76
+ def validate_cabecera
77
+ unless @data[:cabecera]
78
+ raise "invoice_data debe conteter el attributo cabecera"
79
+ end
80
+
81
+ missing_fields = []
82
+
83
+ InvoiceData.allowed_cabecera_fields.each do |field|
84
+ if @data[:cabecera][field.to_sym].nil? && ALLOWED_CABECERA_FIELDS[field.to_sym][:mandatory]
85
+ missing_fields << field
86
+ end
87
+ end
88
+
89
+ if missing_fields.any?
90
+ raise "La cabecera no tiene los campos: #{missing_fields.join(', ')}"
91
+ end
92
+ end
93
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: facturas_xml
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jorge Arteaga Carvalho
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-01-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: codecov
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dotenv
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '13.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.16'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.16'
97
+ - !ruby/object:Gem::Dependency
98
+ name: vcr
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '6.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '6.0'
111
+ description: Permite crear facturas en formato XML válidas para su envión al Servicio
112
+ de Imputestos Nacionales de Bolivia
113
+ email: me@jorgelabs.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - lib/facturas_xml/facturas_xml.rb
119
+ - lib/facturas_xml/invoice_data.rb
120
+ homepage: https://rubygems.org/gems/facturas_xml
121
+ licenses:
122
+ - MIT
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 3.2.3
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Permite crear facturas en formato XML
143
+ test_files: []