cfdi 0.0.3 → 0.0.4
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 +4 -4
- data/examples/crear_factura.rb +3 -3
- data/examples/data/cfdi.xml +22 -0
- data/examples/desde_xml.rb +10 -0
- data/lib/cfdi.rb +3 -1
- data/lib/complemento.rb +10 -0
- data/lib/comprobante.rb +43 -2
- data/lib/concepto.rb +5 -1
- data/lib/entidad.rb +11 -0
- data/lib/xml.rb +122 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25a1f4d4b2e558810cd38ac482b6734bb6ea4edf
|
4
|
+
data.tar.gz: f0d4fb2f9c3ac631db4a6b559ad7628e06ec2646
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da77becc5fe650bde4ce2753069858ed2232df4e332c21998e0188affa1897f3eb83adcb67d89daef4a1c3de172711601b795caf558e4af317be266797fb8ebd
|
7
|
+
data.tar.gz: aa4347b4b3436239d9e5002abcd919ba298e328a23909b086955aa8ae1b695ffc530d1c538f0831be3b654941c9d802634793cce6abe331491ccbace94b054c3
|
data/examples/crear_factura.rb
CHANGED
@@ -3,11 +3,11 @@ require 'json'
|
|
3
3
|
require 'time'
|
4
4
|
|
5
5
|
# el archivo .cer, tal cual
|
6
|
-
certificado = CFDI::Certificado.new './
|
6
|
+
certificado = CFDI::Certificado.new './data/cert.cer'
|
7
7
|
# la llave en formato pem, porque no encontré como usar OpenSSL con llaves tipo PKCS8
|
8
8
|
# Esta se convierte de un archivo .key con:
|
9
9
|
# openssl pkcs8 -inform DER -in someKey.key -passin pass:somePassword -out key.pem
|
10
|
-
llave = CFDI::Key.new './
|
10
|
+
llave = CFDI::Key.new './data/key.pem', 'somePassword'
|
11
11
|
|
12
12
|
# Así instanciamos el comprobante nuevo
|
13
13
|
factura = CFDI::Comprobante.new ({
|
@@ -75,4 +75,4 @@ llave.sella factura
|
|
75
75
|
puts factura.to_xml
|
76
76
|
|
77
77
|
# Esto nos da un hash con todo lo que pusimos
|
78
|
-
puts JSON.pretty_generate factura.to_h
|
78
|
+
#puts JSON.pretty_generate factura.to_h
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd" version="3.2" folio="1" fecha="2013-10-15T01:33:32" formaDePago="PAGO EN UNA SOLA EXHIBICION" condicionesDePago="Sera marcada como pagada en cuanto el receptor haya cubierto el pago." subTotal="11000.00" Moneda="pesos" total="12760.00" metodoDePago="Transferencia Bancaria" tipoDeComprobante="ingreso" LugarExpedicion="Nutopia, Nutopia" noCertificado="20001000000200000293" certificado="MIIE2jCCA8KgAwIBAgIUMjAwMDEwMDAwMDAyMDAwMDAyOTMwDQYJKoZIhvcNAQEFBQAwggFcMRowGAYDVQQDDBFBLkMuIDIgZGUgcHJ1ZWJhczEvMC0GA1UECgwmU2VydmljaW8gZGUgQWRtaW5pc3RyYWNpw7NuIFRyaWJ1dGFyaWExODA2BgNVBAsML0FkbWluaXN0cmFjacOzbiBkZSBTZWd1cmlkYWQgZGUgbGEgSW5mb3JtYWNpw7NuMSkwJwYJKoZIhvcNAQkBFhphc2lzbmV0QHBydWViYXMuc2F0LmdvYi5teDEmMCQGA1UECQwdQXYuIEhpZGFsZ28gNzcsIENvbC4gR3VlcnJlcm8xDjAMBgNVBBEMBTA2MzAwMQswCQYDVQQGEwJNWDEZMBcGA1UECAwQRGlzdHJpdG8gRmVkZXJhbDESMBAGA1UEBwwJQ295b2Fjw6FuMTQwMgYJKoZIhvcNAQkCDCVSZXNwb25zYWJsZTogQXJhY2VsaSBHYW5kYXJhIEJhdXRpc3RhMB4XDTEyMTAyNjE5MjI0M1oXDTE2MTAyNjE5MjI0M1owggFTMUkwRwYDVQQDE0BBU09DSUFDSU9OIERFIEFHUklDVUxUT1JFUyBERUwgRElTVFJJVE8gREUgUklFR08gMDA0IERPTiBNQVJUSU4gMWEwXwYDVQQpE1hBU09DSUFDSU9OIERFIEFHUklDVUxUT1JFUyBERUwgRElTVFJJVE8gREUgUklFR08gMDA0IERPTiBNQVJUSU4gQ09BSFVJTEEgWSBOVUVWTyBMRU9OIEFDMUkwRwYDVQQKE0BBU09DSUFDSU9OIERFIEFHUklDVUxUT1JFUyBERUwgRElTVFJJVE8gREUgUklFR08gMDA0IERPTiBNQVJUSU4gMSUwIwYDVQQtExxBQUQ5OTA4MTRCUDcgLyBIRUdUNzYxMDAzNFMyMR4wHAYDVQQFExUgLyBIRUdUNzYxMDAzTURGUk5OMDkxETAPBgNVBAsTCFNlcnZpZG9yMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlrI9loozd+UcW7YHtqJimQjzX9wHIUcc1KZyBBB8/5fZsgZ/smWS4Sd6HnPs9GSTtnTmM4bEgx28N3ulUshaaBEtZo3tsjwkBV/yVQ3SRyMDkqBA2NEjbcum+e/MdCMHiPI1eSGHEpdESt55a0S6N24PW732Xm3ZbGgOp1tht1wIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIGwDANBgkqhkiG9w0BAQUFAAOCAQEAuoPXe+BBIrmJn+IGeI+m97OlP3RC4Ct3amjGmZICbvhI9BTBLCL/PzQjjWBwU0MG8uK6e/gcB9f+klPiXhQTeI1YKzFtWrzctpNEJYo0KXMgvDiputKphQ324dP0nzkKUfXlRIzScJJCSgRw9ZifKWN0D9qTdkNkjk83ToPgwnldg5lzU62woXo4AKbcuabAYOVoC7owM5bfNuWJe566UzD6i5PFY15jYMzi1+ICriDItCv3S+JdqyrBrX3RloZhdyXqs2Htxfw4b1OcYboPCu4+9qM3OV02wyGKlGQMhfrXNwYyj8huxS1pHghEROM2Zs0paZUOy+6ajM+Xh0LX2w==" sello="igFu7Q9Z98n6xFSLMv7a2y8ZlJCO+pgTX3xDAUt5xSpX3dHOKXkTHBAf4P/oHHDm3xkYkaNBfPEzpVFDrRVjL2rvkR5T9rsFqb4cl6DOo4RrRIpSR9vojLp7mFWiON9H6OFPi2b9PVAnyIx1Skb5iGIAmSQIhVYyt2DSauObY2c=">
|
3
|
+
<cfdi:Emisor nombre="Me cago en sus estándares S.A. de C.V." rfc="XAXX010101000">
|
4
|
+
<cfdi:DomicilioFiscal calle="Calle Feliz" noExterior="42" noInterior="314" colonia="Centro" localidad="No se que sea esto, pero va" referencia="Sin Referencia" municipio="Nutopía" estado="Nutopía" pais="Nutopía" codigoPostal="31415"/>
|
5
|
+
<cfdi:ExpedidoEn calle="Calle Feliz" noExterior="42" noInterior="314" colonia="Centro" localidad="No se que sea esto, pero va" referencia="Sin Referencia" municipio="Nutopía" estado="Nutopía" pais="Nutopía" codigoPostal="31415"/>
|
6
|
+
<cfdi:RegimenFiscal Regimen="Pruebas Fiscales"/>
|
7
|
+
</cfdi:Emisor>
|
8
|
+
<cfdi:Receptor nombre="El SAT apesta S. de R.L." rfc="XAXX010101000">
|
9
|
+
<cfdi:Domicilio referencia="Sin Referencia" estado="Nutopía" pais="Nutopía"/>
|
10
|
+
</cfdi:Receptor>
|
11
|
+
<cfdi:Conceptos>
|
12
|
+
<cfdi:Concepto cantidad="2" unidad="Kilos" noIdentificacion="KDV" descripcion="Verga" valorUnitario="5500.00" importe="11000.00">
|
13
|
+
<cfdi:ComplementoConcepto/>
|
14
|
+
</cfdi:Concepto>
|
15
|
+
</cfdi:Conceptos>
|
16
|
+
<cfdi:Impuestos totalImpuestosTrasladados="1760.00">
|
17
|
+
<cfdi:Traslados>
|
18
|
+
<cfdi:Traslado impuesto="IVA" tasa="16.00" importe="1760.00"/>
|
19
|
+
</cfdi:Traslados>
|
20
|
+
</cfdi:Impuestos>
|
21
|
+
<cfdi:Complemento/>
|
22
|
+
</cfdi:Comprobante>
|
data/lib/cfdi.rb
CHANGED
@@ -5,6 +5,8 @@ require_relative 'comun.rb'
|
|
5
5
|
require_relative 'comprobante.rb'
|
6
6
|
require_relative 'entidad.rb'
|
7
7
|
require_relative 'concepto.rb'
|
8
|
+
require_relative 'complemento.rb'
|
9
|
+
require_relative 'xml.rb'
|
8
10
|
require_relative 'certificado.rb'
|
9
11
|
require_relative 'key.rb'
|
10
12
|
|
@@ -14,6 +16,6 @@ module CFDI
|
|
14
16
|
require 'time'
|
15
17
|
require 'base64'
|
16
18
|
|
17
|
-
VERSION = '0.0.
|
19
|
+
VERSION = '0.0.4'
|
18
20
|
|
19
21
|
end
|
data/lib/complemento.rb
ADDED
data/lib/comprobante.rb
CHANGED
@@ -2,7 +2,7 @@ module CFDI
|
|
2
2
|
class Comprobante
|
3
3
|
|
4
4
|
@@datosCadena = [:version, :fecha, :tipoDeComprobante, :formaDePago, :condicionesDePago, :subTotal, :moneda, :total, :metodoDePago, :lugarExpedicion]
|
5
|
-
@@data = @@datosCadena+[:emisor, :receptor, :conceptos, :serie, :folio, :sello, :noCertificado, :certificado, :impuestos]
|
5
|
+
@@data = @@datosCadena+[:emisor, :receptor, :conceptos, :serie, :folio, :sello, :noCertificado, :certificado, :impuestos, :complemento]
|
6
6
|
attr_accessor *@@data
|
7
7
|
|
8
8
|
@@options = {
|
@@ -40,6 +40,35 @@ module CFDI
|
|
40
40
|
def total
|
41
41
|
self.subTotal+(self.subTotal*@opciones[:tasa])
|
42
42
|
end
|
43
|
+
|
44
|
+
def emisor= emisor
|
45
|
+
emisor = Entidad.new emisor unless emisor.is_a? Entidad
|
46
|
+
@emisor = emisor;
|
47
|
+
end
|
48
|
+
|
49
|
+
def receptor= receptor
|
50
|
+
receptor = Entidad.new receptor unless receptor.is_a? Entidad
|
51
|
+
@receptor = receptor;
|
52
|
+
end
|
53
|
+
|
54
|
+
def conceptos= conceptos
|
55
|
+
if conceptos.is_a? Array
|
56
|
+
conceptos.map! do |concepto|
|
57
|
+
concepto = Concepto.new concepto unless concepto.is_a? Concepto
|
58
|
+
end
|
59
|
+
elsif conceptos.is_a? Hash
|
60
|
+
conceptos = [Concepto.new(concepto)]
|
61
|
+
elsif conceptos.is_a? Concepto
|
62
|
+
conceptos = [conceptos]
|
63
|
+
end
|
64
|
+
|
65
|
+
@conceptos = conceptos
|
66
|
+
end
|
67
|
+
|
68
|
+
def complemento= complemento
|
69
|
+
complemento = Complemento.new complemento unless complemento.is_a? Complemento
|
70
|
+
@complemento = complemento
|
71
|
+
end
|
43
72
|
|
44
73
|
def fecha= fecha
|
45
74
|
fecha = fecha.strftime('%FT%R:%S') unless fecha.is_a? String
|
@@ -100,7 +129,19 @@ module CFDI
|
|
100
129
|
end
|
101
130
|
}
|
102
131
|
}
|
103
|
-
xml.Complemento
|
132
|
+
xml.Complemento {
|
133
|
+
|
134
|
+
if @complemento
|
135
|
+
nsTFD = {
|
136
|
+
'xsi:schemaLocation' => 'http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/TimbreFiscalDigital/TimbreFiscalDigital.xsd',
|
137
|
+
'xmlns:tfd' => 'http://www.sat.gob.mx/TimbreFiscalDigital',
|
138
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
|
139
|
+
}
|
140
|
+
xml['tfd'].TimbreFiscalDigital(@complemento.to_h.merge nsTFD) {
|
141
|
+
}
|
142
|
+
|
143
|
+
end
|
144
|
+
}
|
104
145
|
end
|
105
146
|
end
|
106
147
|
@builder.to_xml
|
data/lib/concepto.rb
CHANGED
@@ -3,7 +3,7 @@ module CFDI
|
|
3
3
|
class Concepto < ElementoComprobante
|
4
4
|
|
5
5
|
@cadenaOriginal = [:cantidad, :unidad, :noIdentificacion, :descripcion, :valorUnitario, :importe]
|
6
|
-
|
6
|
+
#@data = @cadenaOriginal
|
7
7
|
attr_accessor *@cadenaOriginal
|
8
8
|
|
9
9
|
def cadena_original
|
@@ -17,6 +17,10 @@ module CFDI
|
|
17
17
|
]
|
18
18
|
end
|
19
19
|
|
20
|
+
def valorUnitario= vu
|
21
|
+
@valorUnitario = vu.to_f
|
22
|
+
end
|
23
|
+
|
20
24
|
def importe
|
21
25
|
return @valorUnitario*@cantidad
|
22
26
|
end
|
data/lib/entidad.rb
CHANGED
@@ -16,6 +16,17 @@ module CFDI
|
|
16
16
|
].flatten
|
17
17
|
end
|
18
18
|
|
19
|
+
def domicilioFiscal= domicilio
|
20
|
+
domicilio = Domicilio.new domicilio unless domicilio.is_a? domicilio
|
21
|
+
@domicilioFiscal = domicilio
|
22
|
+
end
|
23
|
+
|
24
|
+
def expedidoEn= domicilio
|
25
|
+
domicilio = Domicilio.new domicilio unless domicilio.is_a? domicilio
|
26
|
+
@expedidoEn = domicilio
|
27
|
+
end
|
28
|
+
|
29
|
+
|
19
30
|
def ns
|
20
31
|
return ({
|
21
32
|
nombre: @nombre,
|
data/lib/xml.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
module CFDI
|
2
|
+
|
3
|
+
def self.from_xml(data)
|
4
|
+
xml = Nokogiri::XML(data);
|
5
|
+
xml.remove_namespaces!
|
6
|
+
factura = Comprobante.new
|
7
|
+
|
8
|
+
comprobante = xml.at_xpath('//Comprobante')
|
9
|
+
emisor = xml.at_xpath('//Emisor')
|
10
|
+
de = emisor.at_xpath('//DomicilioFiscal')
|
11
|
+
exp = emisor.at_xpath('//ExpedidoEn')
|
12
|
+
receptor = xml.at_xpath('//Receptor')
|
13
|
+
dr = receptor.at_xpath('//Domicilio')
|
14
|
+
|
15
|
+
factura.version = comprobante.attr('version')
|
16
|
+
factura.serie = comprobante.attr('serie')
|
17
|
+
factura.folio = comprobante.attr('folio')
|
18
|
+
factura.fecha = Time.parse(comprobante.attr('fecha'))
|
19
|
+
factura.noCertificado = comprobante.attr('noCertificado')
|
20
|
+
factura.certificado = comprobante.attr('certificado')
|
21
|
+
factura.sello = comprobante.attr('sello')
|
22
|
+
#factura.subTotal = comprobante.attr('subTotal').to_f
|
23
|
+
factura.formaDePago = comprobante.attr('formaDePago')
|
24
|
+
factura.condicionesDePago = comprobante.attr('condicionesDePago')
|
25
|
+
factura.tipoDeComprobante = comprobante.attr('tipoDeComprobante')
|
26
|
+
factura.lugarExpedicion = comprobante.attr('LugarExpedicion')
|
27
|
+
factura.metodoDePago = comprobante.attr('metodoDePago')
|
28
|
+
factura.moneda = comprobante.attr('Moneda')
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
emisor = {
|
34
|
+
rfc: emisor.attr('rfc'),
|
35
|
+
nombre: emisor.attr('nombre'),
|
36
|
+
regimenFiscal: emisor.at_xpath('//RegimenFiscal').attr('Regimen'),
|
37
|
+
domicilioFiscal: {
|
38
|
+
calle: de.attr('calle'),
|
39
|
+
noExterior: de.attr('noExterior'),
|
40
|
+
noInterior: de.attr('noInterior'),
|
41
|
+
colonia: de.attr('colonia'),
|
42
|
+
localidad: de.attr('localidad'),
|
43
|
+
referencia: de.attr('referencia'),
|
44
|
+
municipio: de.attr('municipio'),
|
45
|
+
estado: de.attr('estado'),
|
46
|
+
pais: de.attr('pais'),
|
47
|
+
cp: de.attr('codigoPostal')
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
if exp
|
52
|
+
emisor[:expedidoEn] = {
|
53
|
+
calle: exp.attr('calle'),
|
54
|
+
no_ext: exp.attr('noExterior'),
|
55
|
+
no_int: exp.attr('noInterior'),
|
56
|
+
colonia: exp.attr('colonia'),
|
57
|
+
localidad: exp.attr('localidad'),
|
58
|
+
referencia: exp.attr('referencia'),
|
59
|
+
municipio: exp.attr('municipio'),
|
60
|
+
estado: exp.attr('estado'),
|
61
|
+
pais: exp.attr('pais'),
|
62
|
+
cp: exp.attr('codigoPostal')
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
factura.emisor = emisor;
|
67
|
+
|
68
|
+
factura.receptor = {
|
69
|
+
rfc: receptor.attr('rfc'),
|
70
|
+
nombre: receptor.attr('nombre'),
|
71
|
+
domicilioFiscal: {
|
72
|
+
calle: dr.attr('calle'),
|
73
|
+
no_ext: dr.attr('noExterior'),
|
74
|
+
no_int: dr.attr('noInterior'),
|
75
|
+
colonia: dr.attr('colonia'),
|
76
|
+
localidad: dr.attr('localidad'),
|
77
|
+
referencia: dr.attr('referencia'),
|
78
|
+
municipio: dr.attr('municipio'),
|
79
|
+
estado: dr.attr('estado'),
|
80
|
+
pais: dr.attr('pais'),
|
81
|
+
cp: dr.attr('codigoPostal')
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
|
86
|
+
xml.xpath('//Concepto').each do |concepto|
|
87
|
+
total = concepto.attr('importe').to_f
|
88
|
+
factura.conceptos << Concepto.new({
|
89
|
+
cantidad: concepto.attr('cantidad').to_f,
|
90
|
+
unidad: concepto.attr('unidad'),
|
91
|
+
noIdentificacion: concepto.attr('noIdentificacion'),
|
92
|
+
descripcion: concepto.attr('descripcion'),
|
93
|
+
valorUnitario: concepto.attr('valorUnitario').to_f
|
94
|
+
})
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
timbre = xml.at_xpath('//TimbreFiscalDigital')
|
100
|
+
if timbre
|
101
|
+
version = timbre.attr('version');
|
102
|
+
uuid = timbre.attr('UUID')
|
103
|
+
fecha = timbre.attr('FechaTimbrado')
|
104
|
+
sello = timbre.attr('selloCFD')
|
105
|
+
certificado = timbre.attr('noCertificadoSAT')
|
106
|
+
factura.complemento = {
|
107
|
+
UUID: uuid,
|
108
|
+
selloCFD: sello,
|
109
|
+
FechaTimbrado: fecha,
|
110
|
+
noCertificadoSAT: certificado,
|
111
|
+
version: version,
|
112
|
+
selloSAT: timbre.attr('selloSAT')
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
factura.impuestos << {impuesto: 'IVA'}
|
117
|
+
|
118
|
+
factura
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cfdi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roberto Hidalgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -38,13 +38,17 @@ files:
|
|
38
38
|
- cfdi.gemspec
|
39
39
|
- examples/crear_factura.rb
|
40
40
|
- examples/data/_empty
|
41
|
+
- examples/data/cfdi.xml
|
42
|
+
- examples/desde_xml.rb
|
41
43
|
- lib/certificado.rb
|
42
44
|
- lib/cfdi.rb
|
45
|
+
- lib/complemento.rb
|
43
46
|
- lib/comprobante.rb
|
44
47
|
- lib/comun.rb
|
45
48
|
- lib/concepto.rb
|
46
49
|
- lib/entidad.rb
|
47
50
|
- lib/key.rb
|
51
|
+
- lib/xml.rb
|
48
52
|
- readme.md
|
49
53
|
homepage: https://github.com/unRob/cfdi
|
50
54
|
licenses:
|