fm_timbrado_cfdi 0.0.1.alpha → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3f2b840f296b634da2bbba4dde5e1fc075cb9c70
4
- data.tar.gz: 5af90d177466131f1d1085a0bd2961f5febc5fc7
3
+ metadata.gz: d2582e25a56146d9dc81168d01ee98697244367b
4
+ data.tar.gz: 2c34955c53b3db7c4c21f8540259510924421991
5
5
  SHA512:
6
- metadata.gz: 2ab5cbf56f9372c4789b95275809a45291fea49926d3e43d32ecca900b513428f92f5800b1c7999b302d5abe5a4bbbd6b83de0b7812905d4dd5e57ce77b586a9
7
- data.tar.gz: abd639e1e09925c9f75bfe37e405c012f0fa65d041c838cb26097d24900f85884bbb9095c062c95140d69e627770c873edb62031782e059b780a65144f04843d
6
+ metadata.gz: fb32a28f691f19aef58e428385bbc3299a4b0dcdc146fdfc790f787ffa23b1797c3b7d6ed93bd08046fd8c1964da7ec6b4354c00a8a03c7e3d1616d8ebed6813
7
+ data.tar.gz: 7de560ae159cc58026ad86e2a4b2e45894a523cc0996d3f0319d895f0d7fc0afc1918156c9c04296b312f10d12541bac9b61be1de4f22e86248b9c09bef2f76d
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem 'coveralls', require: false
3
4
  # Specify your gem's dependencies in fm_timbrado_cfdi.gemspec
4
5
  gemspec
data/README.md CHANGED
@@ -1,4 +1,7 @@
1
1
  # FmTimbradoCfdi
2
+ [![Build Status](https://travis-ci.org/LogicalBricks/fm_timbrado_cfdi.png?branch=master)](https://travis-ci.org/LogicalBricks/fm_timbrado_cfdi)
3
+ [![Code Climate](https://codeclimate.com/github/LogicalBricks/fm_timbrado_cfdi.png)](https://codeclimate.com/github/LogicalBricks/fm_timbrado_cfdi)
4
+ [![Coverage Status](https://coveralls.io/repos/LogicalBricks/fm_timbrado_cfdi/badge.png)](https://coveralls.io/r/LogicalBricks/fm_timbrado_cfdi)
2
5
 
3
6
  Implementa la conexión con el servicio de timbrado cfdi con el PAC Facturación Moderna [Guía de Desarrollo de FM](http://developers.facturacionmoderna.com).
4
7
 
@@ -22,7 +25,7 @@ o instala de forma independiente:
22
25
 
23
26
  Para usar la gema es necesario realizar la configuración con los valores de conexión:
24
27
 
25
- ```
28
+ ```ruby
26
29
  FmTimbradoCfdi.configurar do |config|
27
30
  config.user_id = 'user_id'
28
31
  config.user_pass = 'password'
@@ -36,27 +39,27 @@ end # configurar
36
39
 
37
40
  Y realizar la petición de timbrado:
38
41
 
39
- ```
42
+ ```ruby
40
43
  respuesta = FmTimbradoCfdi.timbra_cfdi_layout rfc, 'layout_file', false
41
- => # Petición sin generación del CBB
44
+ # => Petición sin generación del CBB
42
45
  respuesta = FmTimbradoCfdi.timbra_cfdi_layout rfc, 'layout_file', true
43
- => # Petición con generación del CBB
46
+ # => Petición con generación del CBB
44
47
  ```
45
48
 
46
49
  Si cuentas con el XML sellado puedes hacer lo siguiente:
47
50
 
48
- ```
51
+ ```ruby
49
52
  respuesta = FmTimbradoCfdi.timbra_cfdi_xml 'archivo_xml', false
50
- => # Petición sin generación del CBB
53
+ # => Petición sin generación del CBB
51
54
  respuesta = FmTimbradoCfdi.timbra_cfdi_xml 'archivo_xml', true
52
- => # Petición con generación del CBB
55
+ # => Petición con generación del CBB
53
56
  ```
54
57
 
55
58
  Para un método más general de timbrado que se encuentre más acorde a la documentación de [Facturación Moderna](http://developers.facturacionmoderna.com):
56
59
 
57
- ```
60
+ ```ruby
58
61
  respuesta = FmTimbradoCfdi.timbrar rfc_emisor, 'archivo_xml_o_layout', 'generarCBB' => false, 'generarPDF' => true, 'generarTXT' => false
59
- => # Generar la respuesta con formato PDF, pero sin formato CBB ni TXT
62
+ # => Generar la respuesta con formato PDF, pero sin formato CBB ni TXT
60
63
  ```
61
64
 
62
65
 
@@ -6,7 +6,7 @@ require 'fm_timbrado_cfdi/version'
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "fm_timbrado_cfdi"
8
8
  gem.version = FmTimbradoCfdi::VERSION
9
- gem.authors = ["Carlos García", "Hermes Ojeda Ruiz"]
9
+ gem.authors = ["Carlos García", "Hermes Ojeda Ruiz", "Crisóforo Gaspar Hernández @mitogh"]
10
10
  gem.email = ["hermes.ojeda@logicalbricks.com"]
11
11
  gem.homepage = "https://github.com/LogicalBricks/fm_timbrado_cfdi"
12
12
  gem.summary = %q{Implementación en ruby de la conexión con el servicio de timbrado de cfdi con el PAC Facturación Moderna}
@@ -1,9 +1,9 @@
1
1
  require 'savon'
2
2
  require 'fm_timbrado_cfdi/fm_respuesta'
3
+ require 'fm_timbrado_cfdi/fm_respuesta_cancelacion'
3
4
 
4
5
  module FmTimbradoCfdi
5
6
  class FmCliente
6
- #attrs
7
7
  attr_accessor :user_id, :user_pass, :namespace, :fm_wsdl, :endpoint, :ssl_verify_mode, :log, :log_level
8
8
 
9
9
  def initialize
@@ -39,10 +39,37 @@ module FmTimbradoCfdi
39
39
  FmRespuesta.new(response)
40
40
  end
41
41
 
42
- def peticion_timbrar rfc_emisor, documento, generar_cbb
43
- timbrar(rfc_emisor, documento, 'generarCBB' => generar_cbb)
42
+ def subir_certificado(rfc, certificado, llave, password, opciones = {})
43
+ configurar_cliente
44
+ respuesta = @client.call(:activar_cancelacion,
45
+ message:
46
+ { "param0" => {
47
+ "UserPass" => user_pass,
48
+ "UserID" => user_id,
49
+ "emisorRFC" => rfc,
50
+ "archivoCer" => Base64::encode64(certificado),
51
+ "archivoKey" => Base64::encode64(llave),
52
+ "clave" => password,
53
+ }.merge(opciones)
54
+ })
55
+ FmRespuestaCancelacion.new(respuesta)
44
56
  end
45
57
 
58
+ def cancelar(rfc, uuid, opciones = {})
59
+ configurar_cliente
60
+ respuesta = @client.call(:request_cancelar_cfdi,
61
+ message:
62
+ { "param0" => {
63
+ "UserPass" => user_pass,
64
+ "UserID" => user_id,
65
+ "emisorRFC" => rfc,
66
+ "uuid" => uuid,
67
+ }.merge(opciones)
68
+ })
69
+ FmRespuestaCancelacion.new(respuesta)
70
+ end
71
+
72
+
46
73
  private
47
74
  def configurar_cliente
48
75
  @client = Savon.client(
@@ -55,5 +82,5 @@ module FmTimbradoCfdi
55
82
  )
56
83
  end
57
84
 
58
- end #class
59
- end#module
85
+ end
86
+ end
@@ -17,11 +17,11 @@ module FmTimbradoCfdi
17
17
  @doc = Nokogiri::XML(savon_response.to_xml)
18
18
  @xml = obtener_xml(@doc)
19
19
  @no_csd_emisor = obtener_no_csd_emisor(@xml) if @xml
20
- @timbre = obtener_timbre(@doc)
20
+ @timbre = obtener_timbre(@xml)
21
21
  @pdf = obtener_pdf(@doc)
22
22
  @cbb = obtener_cbb(@doc)
23
23
  else
24
- @errors << savon_response.soap_fault.to_s if savon_response.soap_fault.present?
24
+ @errors << savon_response.soap_fault.to_s if savon_response.soap_fault?
25
25
  @doc = @xml = @no_csd_emisor = @timbre = @pdf = @cbb = nil
26
26
  end
27
27
  rescue Exception => e
@@ -34,27 +34,27 @@ module FmTimbradoCfdi
34
34
  end
35
35
 
36
36
  def xml?
37
- @xml
37
+ !!@xml
38
38
  end
39
39
  alias :xml_present? :xml?
40
40
 
41
41
  def cbb?
42
- @cbb
42
+ !!@cbb
43
43
  end
44
44
  alias :cbb_present? :cbb?
45
45
 
46
46
  def pdf?
47
- @pdf
47
+ !!@pdf
48
48
  end
49
49
  alias :pdf_present? :pdf?
50
50
 
51
51
  def timbre?
52
- @timbre
52
+ !!@timbre
53
53
  end
54
54
  alias :timbre_present? :timbre?
55
55
 
56
56
  def no_csd_emisor?
57
- @no_csd_emisor
57
+ !!@no_csd_emisor
58
58
  end
59
59
  alias :no_csd_emisor_present? :no_csd_emisor?
60
60
 
@@ -69,10 +69,8 @@ module FmTimbradoCfdi
69
69
  end
70
70
  end
71
71
 
72
- def obtener_timbre(doc)
73
- unless doc.xpath("//txt").empty?
74
- FmTimbre.new Base64::decode64( doc.xpath("//txt")[0].content )
75
- end
72
+ def obtener_timbre(xml)
73
+ FmTimbre.new(xml) if xml
76
74
  end
77
75
 
78
76
  def obtener_pdf(doc)
@@ -0,0 +1,29 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'nokogiri'
3
+ require 'savon'
4
+
5
+ module FmTimbradoCfdi
6
+ class FmRespuestaCancelacion
7
+ attr_reader :error
8
+ def initialize(savon_response)
9
+ @respuesta = savon_response
10
+ unless valid?
11
+ #@error = @respuesta.http_error.to_s if @respuesta.http_error?
12
+ @error = @respuesta.to_s if @respuesta.soap_fault?
13
+ end
14
+ end
15
+
16
+ def codigo
17
+ @error.match(/\((.*)\).*/)[0] if @error
18
+ end
19
+
20
+ def mensaje
21
+ @error
22
+ end
23
+
24
+ def valid?
25
+ @respuesta.success?
26
+ end
27
+
28
+ end
29
+ end
@@ -6,50 +6,75 @@ module FmTimbradoCfdi
6
6
  attr_reader :no_certificado_sat, :fecha_timbrado, :uuid, :sello_sat, :sello_cfd, :fecha_comprobante, :serie, :folio, :trans_id
7
7
 
8
8
  def initialize ( nodo_timbre )
9
- parse( nodo_timbre )
10
- end # initialize
11
-
9
+ parse( nodo_timbre )
10
+ end
11
+
12
12
  def parse ( nodo_timbre )
13
- valores = nodo_timbre.split("\n")
14
- return unless valores.size == 9
13
+ xml = Nokogiri::XML(nodo_timbre)
14
+ ns = generar_namespaces(xml)
15
+ atributos.each do |variable|
16
+ instance_variable_set("@#{variable}", send("obtener_#{variable}", xml, ns))
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def generar_namespaces(xml)
23
+ namespaces = xml.collect_namespaces
24
+ ns = {}
25
+ namespaces.each_pair do |key, value|
26
+ ns[key.sub(/^xmlns:/, '')] = value
27
+ end
28
+ ns
29
+ end
15
30
 
16
- # TransID
17
- temp_value = valores[0].chomp.split('|')
18
- @trans_id = temp_value[1] if temp_value.size > 1
31
+ def atributos
32
+ [ 'trans_id',
33
+ 'no_certificado_sat',
34
+ 'fecha_timbrado',
35
+ 'uuid',
36
+ 'sello_sat',
37
+ 'sello_cfd',
38
+ 'fecha_comprobante',
39
+ 'serie',
40
+ 'folio' ]
41
+ end
19
42
 
20
- # noCertificadoSAT
21
- temp_value = valores[1].chomp.split('|')
22
- @no_certificado_sat = temp_value[1] if temp_value.size > 1
43
+ def obtener_trans_id(xml,ns)
44
+ xml.xpath("//cfdi:Comprobante",ns).attribute('TransID').value rescue nil
45
+ end
23
46
 
24
- # FechaTimbrado
25
- temp_value = valores[2].chomp.split('|')
26
- @fecha_timbrado = temp_value[1] if temp_value.size > 1
47
+ def obtener_no_certificado_sat(xml, ns)
48
+ xml.xpath("//tfd:TimbreFiscalDigital", ns).attribute('noCertificadoSAT').value rescue nil
49
+ end
27
50
 
28
- # uuid
29
- temp_value = valores[3].chomp.split('|')
30
- @uuid = temp_value[1] if temp_value.size > 1
51
+ def obtener_uuid(xml,ns)
52
+ xml.xpath("//tfd:TimbreFiscalDigital", ns).attribute('UUID').value rescue nil
53
+ end
31
54
 
32
- # selloSAT
33
- temp_value = valores[4].chomp.split('|')
34
- @sello_sat = temp_value[1] if temp_value.size > 1
55
+ def obtener_fecha_timbrado(xml, ns)
56
+ xml.xpath("//tfd:TimbreFiscalDigital", ns).attribute('FechaTimbrado').value rescue nil
57
+ end
35
58
 
36
- # selloCFD
37
- temp_value = valores[5].chomp.split('|')
38
- @sello_cfd = temp_value[1] if temp_value.size > 1
59
+ def obtener_sello_sat(xml, ns)
60
+ xml.xpath("//tfd:TimbreFiscalDigital", ns).attribute('selloSAT').value rescue nil
61
+ end
39
62
 
40
- # Fecha
41
- temp_value = valores[6].chomp.split('|')
42
- @fecha_comprobante = temp_value[1] if temp_value.size > 1
63
+ def obtener_fecha_comprobante(xml, ns)
64
+ xml.xpath("//cfdi:Comprobante", ns).attribute('fecha').value rescue nil
65
+ end
43
66
 
44
- # Serie
45
- temp_value = valores[7].chomp.split('|')
46
- @serie = temp_value[1] if temp_value.size > 1
67
+ def obtener_sello_cfd(xml, ns)
68
+ xml.xpath("//tfd:TimbreFiscalDigital", ns).attribute('selloCFD').value rescue nil
69
+ end
47
70
 
48
- # folio
49
- temp_value = valores[8].chomp.split('|')
50
- @folio = temp_value[1] if temp_value.size > 1
51
- end # parse
71
+ def obtener_serie(xml, ns )
72
+ xml.xpath("//cfdi:Comprobante", ns).attribute('serie').value rescue nil
73
+ end
52
74
 
53
- end # class
54
- end # module
75
+ def obtener_folio(xml, ns)
76
+ xml.xpath("//cfdi:Comprobante", ns).attribute('folio').value rescue nil
77
+ end
78
+ end
79
+ end
55
80
 
@@ -1,3 +1,3 @@
1
1
  module FmTimbradoCfdi
2
- VERSION = "0.0.1.alpha"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -50,8 +50,27 @@ module FmTimbradoCfdi
50
50
  respuesta = cliente.timbrar rfc, archivo, opciones
51
51
  end
52
52
 
53
- #no implementado todavía
54
- def cancela_cfdi (uuid)
53
+ # Public: Envía CSD para que lo almacene el PAC
54
+ #
55
+ # rfc - Es el RFC del emisor
56
+ # certificado - El contenido del archivo de certificado
57
+ # llave - La llave privada del certificado
58
+ # password - Contraseña de la llave privada
59
+ #
60
+ # Regresa un objeto de tipo FmRespuestaCancelacion
61
+ def activar_cancelacion(rfc, certificado, llave, password)
62
+ respuesta = cliente.subir_certificado rfc, certificado, llave, password
63
+ end
64
+ alias :subir_certificado :activar_cancelacion
65
+
66
+ # Public: Envía una petición de cancelación de factura
67
+ #
68
+ # rfc - Es el RFC del emisor
69
+ # uuid - Es el identificador de la factura a cancelar
70
+ #
71
+ # Regresa una respuesta SOAP
72
+ def cancelar(rfc, uuid)
73
+ respuesta = cliente.cancelar(rfc, uuid)
55
74
  end
56
75
 
57
76
  end
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXQIBAAKBgQCumKgINyxzj6QCg/ThZHDYAecI/t5OKBzyt2xX5LuEwhLMLTIS
3
+ LeS52QreFCtHKfUmKSjGtpGVWJupOs6YVoPW8796bx8LfZgepBRsgKVO9XDpNerp
4
+ 6i9qP6Q4+uczbVAXw8ipCgVBkDGILar1aumlyYqaijkvzbAyhFLdKtYIUwIDAQAB
5
+ AoGAdvLn35j/PsfInDIcXoZYXsGFDlrdR3AKsM2IEaVyn7K8rb/I0hvULU2SGtSw
6
+ 223ZZ6M49ZCiRJY2jqfS4nRmoqYNRqxYhYt9r2caoqtyL2ZOsmFil1uuzueeYi0r
7
+ Sj6WvLwlmET+EC6acHBvvo5Y/hsZrtxCTWmOY9LFtn32+KECQQDYZ4l6VnwAc6gV
8
+ XPqedRrm7Htpam334lKKvomkSCdnYfcaUB6OZ0iGR5T43DLq0VbUk2Sj6L7LIRh/
9
+ 2fAO6hzRAkEAzorPuHnoTuHhGcSU9KDgG6tuQ0YYM/kUktlwaKgTNURZB6BXXr8W
10
+ 0i36pLuAJ/6wJB1GtgB7fem8g0eR3EmL4wJBAIqUQwWEvIPNjKWhlRxEAaY/aghn
11
+ j2ReGl2fBqWdTx51Lbg79lVa7qaO0GdNG44j4GbgvGH6ebO6zeWRupjScwECQQCH
12
+ 30dg+0l4wx2bHvhCqaZkbXU+6li3sA75v/Mz1gW0z/6lhrSTTrALmlW9kt9u8Bwd
13
+ 1eiTiGO05FOwJR/uQ6+zAkBkVwBY0+2ONgEff7gJKLNHEvG2DdQdDS+Pl1/udDyW
14
+ /GqzhGFeif2+IjROyLwsqbRD5hMynXVwc60YnMIcALNr
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,2 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="https://t2demo.facturacionmoderna.com/timbrado/soap" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:requestTimbrarCFDIResponse><return xsi:type="SOAP-ENC:Struct"><xml xsi:type="xsd:string">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPGNmZGk6Q29tcHJvYmFudGUgeG1sbnM6Y2ZkaT0iaHR0cDovL3d3dy5zYXQuZ29iLm14L2NmZC8zIiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3d3dy5zYXQuZ29iLm14L2NmZC8zIGh0dHA6Ly93d3cuc2F0LmdvYi5teC9zaXRpb19pbnRlcm5ldC9jZmQvMy9jZmR2MzIueHNkIiB2ZXJzaW9uPSIzLjIiIGZlY2hhPSIyMDEzLTEyLTI3VDE2OjEzOjQ2IiBmb2xpbz0iMTAxIiBzZXJpZT0iQTEiIHN1YlRvdGFsPSIxMDAuMDAiIGRlc2N1ZW50bz0iMC4wMCIgdG90YWw9IjExNi4wMCIgTW9uZWRhPSJNWE4iIFRpcG9DYW1iaW89IjAuMDAiIGNvbmRpY2lvbmVzRGVQYWdvPSJQYWdvIGVuIHVuYSBzb2xhIEV4aGliaWNpw7NuIiB0aXBvRGVDb21wcm9iYW50ZT0iaW5ncmVzbyIgbm9DZXJ0aWZpY2Fkbz0iMjAwMDEwMDAwMDAyMDAwMDAxOTIiIGNlcnRpZmljYWRvPSJNSUlFUmpDQ0F5NmdBd0lCQWdJVU1qQXdNREV3TURBd01EQXlNREF3TURBeE9USXdEUVlKS29aSWh2Y05BUUVGQlFBd2dnRmNNUm93R0FZRFZRUUREQkZCTGtNdUlESWdaR1VnY0hKMVpXSmhjekV2TUMwR0ExVUVDZ3dtVTJWeWRtbGphVzhnWkdVZ1FXUnRhVzVwYzNSeVlXTnB3N051SUZSeWFXSjFkR0Z5YVdFeE9EQTJCZ05WQkFzTUwwRmtiV2x1YVhOMGNtRmphY096YmlCa1pTQlRaV2QxY21sa1lXUWdaR1VnYkdFZ1NXNW1iM0p0WVdOcHc3TnVNU2t3SndZSktvWklodmNOQVFrQkZocGhjMmx6Ym1WMFFIQnlkV1ZpWVhNdWMyRjBMbWR2WWk1dGVERW1NQ1FHQTFVRUNRd2RRWFl1SUVocFpHRnNaMjhnTnpjc0lFTnZiQzRnUjNWbGNuSmxjbTh4RGpBTUJnTlZCQkVNQlRBMk16QXdNUXN3Q1FZRFZRUUdFd0pOV0RFWk1CY0dBMVVFQ0F3UVJHbHpkSEpwZEc4Z1JtVmtaWEpoYkRFU01CQUdBMVVFQnd3SlEyOTViMkZqdzZGdU1UUXdNZ1lKS29aSWh2Y05BUWtDRENWU1pYTndiMjV6WVdKc1pUb2dRWEpoWTJWc2FTQkhZVzVrWVhKaElFSmhkWFJwYzNSaE1CNFhEVEV5TVRBeU1qSXdORGd3TmxvWERURTJNVEF5TWpJd05EZ3dObG93Z2NBeElUQWZCZ05WQkFNVEdFVkVTVlJQVWtsQlRDQlRTVk5VUVNCVFFTQkVSU0JEVmpFaE1COEdBMVVFS1JNWVJVUkpWRTlTU1VGTUlGTkpVMVJCSUZOQklFUkZJRU5XTVNFd0h3WURWUVFLRXhoRlJFbFVUMUpKUVV3Z1UwbFRWRUVnVTBFZ1JFVWdRMVl4SlRBakJnTlZCQzBUSEVWVFNUa3lNRFF5TnpnNE5pQXZJRWhGUjFRM05qRXdNRE0wVXpJeEhqQWNCZ05WQkFVVEZTQXZJRWhGUjFRM05qRXdNRE5OUkVaU1RrNHdPVEVPTUF3R0ExVUVDeE1GUVcxcFoyRXdnWjh3RFFZSktvWklodmNOQVFFQkJRQURnWTBBTUlHSkFvR0JBSzZZcUFnM0xIT1BwQUtEOU9Ga2NOZ0I1d2orM2s0b0hQSzNiRmZrdTRUQ0Vzd3RNaEl0NUxuWkN0NFVLMGNwOVNZcEtNYTJrWlZZbTZrNnpwaFdnOWJ6djNwdkh3dDltQjZrRkd5QXBVNzFjT2sxNnVucUwyby9wRGo2NXpOdFVCZkR5S2tLQlVHUU1ZZ3RxdlZxNmFYSmlwcUtPUy9Oc0RLRVV0MHExZ2hUQWdNQkFBR2pIVEFiTUF3R0ExVWRFd0VCL3dRQ01BQXdDd1lEVlIwUEJBUURBZ2JBTUEwR0NTcUdTSWIzRFFFQkJRVUFBNElCQVFDZ0NDcFlEYm1OOG5wTFg2dkhDRUpBRi8xRzNLaHVBR1k0OHdWdDF2YTFZWFJ5NnlqK3RKWjlIWjNsOFRZN0o2bjEwWGtyYnplZE9Bckt5amRwZnFXYk5hYlpIdzZiMklsU044SHJIbGlpQUVvcjVod1RVSm5rZzZTMW5tMG1taXJJbnhDbVdvVlYrcXJFWC9YSHlsSitPaklxbC9HeVpySDlzRVBDWStMWUZmVmhPMFU3M2pLcWFqTUVlWnRXWXE1d3JvNFVoUFVobFlnd2hselVONlhOV3RpQzhvaGpFNlFKYWY4allSc0pqSHJhWkwyNTdPMW81VC8zVUxNSmhBU043UjIxMUZteUF1aVlzcThIM2J1UEUwa2wrRW1OOERVTnBURGtCOVhmMWJhNmdYWjBQUlhGMW9HVXd4dlg5RmlJNWVJYXUyUkxmeTlBZkpQY3BBWE4iIGZvcm1hRGVQYWdvPSJDb250YWRvIiBtZXRvZG9EZVBhZ289IkVmZWN0aXZvIiBOdW1DdGFQYWdvPSIwMDA5IC0gQmFuYW1leCIgTHVnYXJFeHBlZGljaW9uPSJTYW4gUGVkcm8gR2FyemEgR2FyY8OtYSIgc2VsbG89ImZXb1RaN1NUWlpCb09hbHJ4SnF0V0hDckxYYW4vMWE4RnNiMkpDNjhqc3pSZ3VKclkrdXpYVDAxd2ZWZ1ZmM2lCdFM2MVVjTStNVlk4R21UQWVPOE9OaVJMc3lMci9kYjk4aVdRWlZ0OFlha3dySVJlT1Z0UVdnS0pZR3Z5cmx6U1BVYWJsS0E5bUtaWTVVNGtNd0ZzVXZmWmdBR3N5UGRxV0JDaUV3OFU3VT0iPjxjZmRpOkVtaXNvciBub21icmU9IkNPTUVSQ0lBTElaQURPUkEgU0EgREUgQ1YiIHJmYz0iRVNJOTIwNDI3ODg2Ij48Y2ZkaTpEb21pY2lsaW9GaXNjYWwgY2FsbGU9IkNhbHphZGEgZGVsIFZhbGxlIiBub0V4dGVyaW9yPSI5MCIgbm9JbnRlcmlvcj0iaW50LTEwIiBjb2xvbmlhPSJDb2wuIERlbCBWYWxsZSIgbXVuaWNpcGlvPSJTYW4gUGVkcm8gR2FyemEgR2FyY2lhLiIgZXN0YWRvPSJOdWV2byBMZcOzbiIgcGFpcz0iTcOpeGljbyIgY29kaWdvUG9zdGFsPSI3Njg4OCIvPjxjZmRpOkV4cGVkaWRvRW4gY2FsbGU9IkNhbHphZGEgZGVsIFZhbGxlKFN1Y3Vyc2FsKSIgbm9FeHRlcmlvcj0iOTAiIG5vSW50ZXJpb3I9ImludC0xMCIgY29sb25pYT0iQ29sLiBEZWwgVmFsbGUiIG11bmljaXBpbz0iU2FuIFBlZHJvIEdhcnphIEdhcmNpYS4iIGVzdGFkbz0iTnVldm8gTGXDs24iIHBhaXM9Ik3DqXhpY28iIGNvZGlnb1Bvc3RhbD0iNzY4ODgiLz48Y2ZkaTpSZWdpbWVuRmlzY2FsIFJlZ2ltZW49IlBFUlNPTkEgTU9SQUwgUkVHSU1FTiBHRU5FUkFMIERFIExFWS4iLz48L2NmZGk6RW1pc29yPjxjZmRpOlJlY2VwdG9yIG5vbWJyZT0iUFVCTElDTyBFTiBHRU5FUkFMIiByZmM9IlhBWFgwMTAxMDEwMDAiPjxjZmRpOkRvbWljaWxpbyBjYWxsZT0iQ2FsbGUiIG5vRXh0ZXJpb3I9Ik51bSBFeHQiIG5vSW50ZXJpb3I9Ik51bSBJbnQiIGNvbG9uaWE9IkNvbG9uaWEiIG11bmljaXBpbz0iTXVuaWNpcGlvIiBlc3RhZG89IkVzdGFkbyIgcGFpcz0iUGFpcyIgY29kaWdvUG9zdGFsPSI2MDAwMCIvPjwvY2ZkaTpSZWNlcHRvcj48Y2ZkaTpDb25jZXB0b3M+PGNmZGk6Q29uY2VwdG8gbm9JZGVudGlmaWNhY2lvbj0iNzg5OTcwMSIgdW5pZGFkPSJQaWV6YSIgZGVzY3JpcGNpb249IkNhamEgZGUgQ2hvY29sYXRlcyIgY2FudGlkYWQ9IjEuMDAiIHZhbG9yVW5pdGFyaW89IjUwLjAwIiBpbXBvcnRlPSI1MC4wMCIvPjxjZmRpOkNvbmNlcHRvIHVuaWRhZD0iTm8gYXBsaWNhIiBkZXNjcmlwY2lvbj0iRW52aW8iIGNhbnRpZGFkPSIxLjAwIiB2YWxvclVuaXRhcmlvPSI1MC4wMCIgaW1wb3J0ZT0iNTAuMDAiLz48L2NmZGk6Q29uY2VwdG9zPjxjZmRpOkltcHVlc3RvcyB0b3RhbEltcHVlc3Rvc1JldGVuaWRvcz0iMjAwLjAwIiB0b3RhbEltcHVlc3Rvc1RyYXNsYWRhZG9zPSIxNi4wMCI+PGNmZGk6UmV0ZW5jaW9uZXM+PGNmZGk6UmV0ZW5jaW9uIGltcHVlc3RvPSJJU1IiIGltcG9ydGU9IjIwMC4wMCIvPjwvY2ZkaTpSZXRlbmNpb25lcz48Y2ZkaTpUcmFzbGFkb3M+PGNmZGk6VHJhc2xhZG8gaW1wdWVzdG89IklWQSIgdGFzYT0iMTYuMDAiIGltcG9ydGU9IjE2LjAwIi8+PC9jZmRpOlRyYXNsYWRvcz48L2NmZGk6SW1wdWVzdG9zPjxjZmRpOkNvbXBsZW1lbnRvPjx0ZmQ6VGltYnJlRmlzY2FsRGlnaXRhbCB4bWxuczp0ZmQ9Imh0dHA6Ly93d3cuc2F0LmdvYi5teC9UaW1icmVGaXNjYWxEaWdpdGFsIiB4c2k6c2NoZW1hTG9jYXRpb249Imh0dHA6Ly93d3cuc2F0LmdvYi5teC9UaW1icmVGaXNjYWxEaWdpdGFsIGh0dHA6Ly93d3cuc2F0LmdvYi5teC9UaW1icmVGaXNjYWxEaWdpdGFsL1RpbWJyZUZpc2NhbERpZ2l0YWwueHNkIiB2ZXJzaW9uPSIxLjAiIFVVSUQ9IjZGMzI4QjY1LTY1RDMtNDI3RS04NTYzLTZDQkFCRURBODZFQyIgRmVjaGFUaW1icmFkbz0iMjAxMy0xMi0yN1QxNjoxMzo0NiIgc2VsbG9DRkQ9ImZXb1RaN1NUWlpCb09hbHJ4SnF0V0hDckxYYW4vMWE4RnNiMkpDNjhqc3pSZ3VKclkrdXpYVDAxd2ZWZ1ZmM2lCdFM2MVVjTStNVlk4R21UQWVPOE9OaVJMc3lMci9kYjk4aVdRWlZ0OFlha3dySVJlT1Z0UVdnS0pZR3Z5cmx6U1BVYWJsS0E5bUtaWTVVNGtNd0ZzVXZmWmdBR3N5UGRxV0JDaUV3OFU3VT0iIG5vQ2VydGlmaWNhZG9TQVQ9IjIwMDAxMDAwMDAwMTAwMDA1NzYxIiBzZWxsb1NBVD0icEhyOXcwNWpwSnRGeVRUc0tURTRxYytsWW0rL3B6Y2VBOXNobXpEQXYrc0tlbU1wU3YyWjI2UFBiNlp1TFBEdUVKZGpsZ05leDJROUpmMXVxM2Z4aXdYSEZLM1JlK3paZHNYdWRjbTVjaTNNSU5VU21pNkpLVWx2OGpSajdRbGFHTFdqTWNsMFo5RjJ6RlMrQjljTDNzV1d1OWtrVEJYcjdFSHFHWmduaThJPSIvPjwvY2ZkaTpDb21wbGVtZW50bz48L2NmZGk6Q29tcHJvYmFudGU+Cg==</xml></return></ns1:requestTimbrarCFDIResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
@@ -0,0 +1,2 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="https://t2demo.facturacionmoderna.com/timbrado/soap" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:requestTimbrarCFDIResponse><return xsi:type="SOAP-ENC:Struct"></return></ns1:requestTimbrarCFDIResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'ostruct'
4
+
5
+ describe FmTimbradoCfdi::FmRespuesta do
6
+ context "respuesta no satisfactoria" do
7
+ let(:respuesta_cliente) do
8
+ prueba = OpenStruct.new
9
+ prueba.stub(:success?).and_return(false)
10
+ prueba.stub_chain(:soap_fault?).and_return(true)
11
+ prueba.stub_chain(:soap_fault, :to_s).and_return('Test Error')
12
+ prueba
13
+ end
14
+ let(:respuesta) { FmTimbradoCfdi::FmRespuesta.new(respuesta_cliente) }
15
+ it { expect(respuesta.valid?).to eq(false) }
16
+ it { expect(respuesta.xml?).to eq(false) }
17
+ it { expect(respuesta.pdf?).to eq(false) }
18
+ it { expect(respuesta.cbb?).to eq(false) }
19
+ it { expect(respuesta.timbre?).to eq(false) }
20
+ it { expect(respuesta.no_csd_emisor?).to eq(false) }
21
+ end
22
+
23
+ context "respuesta sin xml" do
24
+ let(:texto_respuesta){File.open('spec/fixtures/soap_response_sin_xml.txt').read}
25
+ let(:respuesta) { FmTimbradoCfdi::FmRespuesta.new(texto_respuesta) }
26
+ it { expect(respuesta.valid?).to eq(false) }
27
+ end
28
+
29
+ end
@@ -3,8 +3,10 @@ require 'spec_helper'
3
3
 
4
4
  describe FmTimbradoCfdi::FmTimbre do
5
5
  context "debe crear un objeto válido" do
6
- let(:timbre_as_text) { File.open('spec/fixtures/timbre_example.txt').read }
7
- let(:timbre) { FmTimbradoCfdi::FmTimbre.new timbre_as_text }
6
+ let(:plantilla){File.open('spec/fixtures/layout_example.txt').read}
7
+ let(:layout){ plantilla.gsub('--fecha-comprobante--', 'asignarFecha' )}
8
+ let(:respuesta){ FmTimbradoCfdi.timbra_cfdi_layout 'ESI920427886', layout }
9
+ let(:timbre) { FmTimbradoCfdi::FmTimbre.new(respuesta.xml)}
8
10
  it { timbre.no_certificado_sat.should_not be_nil }
9
11
  it { timbre.fecha_timbrado.should_not be_nil }
10
12
  it { timbre.uuid.should_not be_nil }
@@ -10,7 +10,7 @@ describe FmTimbradoCfdi do
10
10
  FmTimbradoCfdi.cliente.endpoint.should == 'https://t2demo.facturacionmoderna.com/timbrado/soap'
11
11
  FmTimbradoCfdi.cliente.fm_wsdl.should == 'https://t2demo.facturacionmoderna.com/timbrado/wsdl'
12
12
  end
13
- end #describe .cliente"
13
+ end
14
14
 
15
15
 
16
16
  describe ".timbra_cfdi_layout" do
@@ -91,29 +91,84 @@ describe FmTimbradoCfdi do
91
91
 
92
92
  context 'timbrado incorrecto' do
93
93
  it "no timbra el comprobante si tiene más de 72 horas de haber sido generado" do
94
- fecha_comprobante = Time.now - 73*3600
94
+ fecha_comprobante = Time.now - 120*3600
95
95
  layout = File.open('spec/fixtures/layout_example.txt').read.gsub('--fecha-comprobante--', fecha_comprobante.strftime("%FT%T"))
96
96
  respuesta = FmTimbradoCfdi.timbrar 'ESI920427886', layout
97
97
  respuesta.should_not be_valid
98
98
  end
99
99
  end
100
- end
101
100
 
102
- describe ".configurar" do
103
- it "cambia los valores de conexión por los proporcionados" do
104
- FmTimbradoCfdi.configurar do |config|
105
- config.user_id = "mi_usuario"
106
- config.user_pass = "secret"
107
- config.namespace = "http://logicalbricks.com/soap"
108
- config.endpoint = "http://logicalbricks.com/endpoint"
109
- config.fm_wsdl = "http://logicalbricks.com/wsdl"
101
+ context 'subir certificados' do
102
+ let(:archivo_certificado) { File.read('spec/fixtures/certificados/20001000000200000192.cer') }
103
+ let(:archivo_llave) { File.read('spec/fixtures/certificados/20001000000200000192.key') }
104
+ let(:password) { '12345678a' }
105
+ describe '.activar_cancelacion' do
106
+ context 'petición válida' do
107
+ let(:respuesta){ FmTimbradoCfdi.activar_cancelacion('ESI920427886', archivo_certificado, archivo_llave, password) }
108
+ it{ expect(respuesta.valid?).to eq(true) }
109
+ end
110
+
111
+ context 'petición inválida' do
112
+ let(:respuesta){ FmTimbradoCfdi.activar_cancelacion('ESI920427886', archivo_llave, archivo_certificado, password) }
113
+ it{ expect(respuesta.valid?).to eq(false) }
114
+ end
115
+ end
116
+
117
+ describe '.subir_certificado' do
118
+ context 'petición válida' do
119
+ let(:respuesta){ FmTimbradoCfdi.subir_certificado('ESI920427886', archivo_certificado, archivo_llave, password) }
120
+ it{ expect(respuesta.valid?).to eq(true) }
121
+ end
122
+
123
+ context 'petición inválida' do
124
+ let(:respuesta){ FmTimbradoCfdi.subir_certificado('ESI920427886', archivo_llave, archivo_certificado, password) }
125
+ it{ expect(respuesta.valid?).to eq(false) }
126
+ end
110
127
  end
111
128
 
112
- FmTimbradoCfdi.cliente.user_id.should == 'mi_usuario'
113
- FmTimbradoCfdi.cliente.user_pass.should == 'secret'
114
- FmTimbradoCfdi.cliente.namespace.should == 'http://logicalbricks.com/soap'
115
- FmTimbradoCfdi.cliente.endpoint.should == 'http://logicalbricks.com/endpoint'
116
- FmTimbradoCfdi.cliente.fm_wsdl.should == 'http://logicalbricks.com/wsdl'
117
129
  end
130
+
131
+ describe ".cancelar" do
132
+ context "petición inválida" do
133
+ let(:respuesta){ FmTimbradoCfdi.cancelar('ESI920427886', 'asdasasdsa') }
134
+ it{ expect(respuesta.valid?).to eq(false) }
135
+ end
136
+
137
+ context "formato válido" do
138
+ let(:respuesta){ FmTimbradoCfdi.cancelar('ESI920427886', '00000000-0000-0000-0000-00000000000000') }
139
+ it{ expect(respuesta.valid?).to eq(false) }
140
+ end
141
+
142
+ context "peticion válida" do
143
+ let(:uuid) do
144
+ plantilla = File.open('spec/fixtures/layout_example.txt').read
145
+ layout = plantilla.gsub('--fecha-comprobante--', 'asignarFecha' )
146
+ respuesta = FmTimbradoCfdi.timbrar 'ESI920427886', layout
147
+ respuesta.timbre.uuid
148
+ end
149
+ let(:respuesta){ FmTimbradoCfdi.cancelar('ESI920427886', uuid) }
150
+ it{ expect(respuesta.valid?).to eq(true) }
151
+ end
152
+ end
153
+
154
+ describe ".configurar" do
155
+ it "cambia los valores de conexión por los proporcionados" do
156
+ FmTimbradoCfdi.configurar do |config|
157
+ config.user_id = "mi_usuario"
158
+ config.user_pass = "secret"
159
+ config.namespace = "http://logicalbricks.com/soap"
160
+ config.endpoint = "http://logicalbricks.com/endpoint"
161
+ config.fm_wsdl = "http://logicalbricks.com/wsdl"
162
+ end
163
+
164
+ FmTimbradoCfdi.cliente.user_id.should == 'mi_usuario'
165
+ FmTimbradoCfdi.cliente.user_pass.should == 'secret'
166
+ FmTimbradoCfdi.cliente.namespace.should == 'http://logicalbricks.com/soap'
167
+ FmTimbradoCfdi.cliente.endpoint.should == 'http://logicalbricks.com/endpoint'
168
+ FmTimbradoCfdi.cliente.fm_wsdl.should == 'http://logicalbricks.com/wsdl'
169
+ end
170
+ end
171
+
118
172
  end
119
173
 
174
+
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,4 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
1
3
  require 'fm_timbrado_cfdi'
2
4
 
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fm_timbrado_cfdi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.alpha
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos García
8
8
  - Hermes Ojeda Ruiz
9
+ - Crisóforo Gaspar Hernández @mitogh
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2013-12-26 00:00:00.000000000 Z
13
+ date: 2014-01-02 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: nokogiri
@@ -64,6 +65,7 @@ files:
64
65
  - .gitignore
65
66
  - .ruby-gemset
66
67
  - .ruby-version
68
+ - .travis.yml
67
69
  - Gemfile
68
70
  - LICENSE.txt
69
71
  - README.md
@@ -72,13 +74,20 @@ files:
72
74
  - lib/fm_timbrado_cfdi.rb
73
75
  - lib/fm_timbrado_cfdi/fm_cliente.rb
74
76
  - lib/fm_timbrado_cfdi/fm_respuesta.rb
77
+ - lib/fm_timbrado_cfdi/fm_respuesta_cancelacion.rb
75
78
  - lib/fm_timbrado_cfdi/fm_timbre.rb
76
79
  - lib/fm_timbrado_cfdi/version.rb
80
+ - spec/fixtures/certificados/20001000000200000192.cer
81
+ - spec/fixtures/certificados/20001000000200000192.key
82
+ - spec/fixtures/certificados/20001000000200000192.key.pem
77
83
  - spec/fixtures/constructora_layout_example.txt
78
84
  - spec/fixtures/layout_example.txt
79
85
  - spec/fixtures/layout_example.txt~
80
86
  - spec/fixtures/pipes.txt
87
+ - spec/fixtures/soap_response.txt
88
+ - spec/fixtures/soap_response_sin_xml.txt
81
89
  - spec/fixtures/timbre_example.txt
90
+ - spec/fm_timbrado_cfdi/fm_respuesta_spec.rb
82
91
  - spec/fm_timbrado_cfdi/fm_timbre_spec.rb
83
92
  - spec/fm_timbrado_cfdi_spec.rb
84
93
  - spec/spec_helper.rb
@@ -96,9 +105,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
96
105
  version: '0'
97
106
  required_rubygems_version: !ruby/object:Gem::Requirement
98
107
  requirements:
99
- - - '>'
108
+ - - '>='
100
109
  - !ruby/object:Gem::Version
101
- version: 1.3.1
110
+ version: '0'
102
111
  requirements: []
103
112
  rubyforge_project:
104
113
  rubygems_version: 2.1.11
@@ -107,11 +116,17 @@ specification_version: 4
107
116
  summary: Implementación en ruby de la conexión con el servicio de timbrado de cfdi
108
117
  con el PAC Facturación Moderna
109
118
  test_files:
119
+ - spec/fixtures/certificados/20001000000200000192.cer
120
+ - spec/fixtures/certificados/20001000000200000192.key
121
+ - spec/fixtures/certificados/20001000000200000192.key.pem
110
122
  - spec/fixtures/constructora_layout_example.txt
111
123
  - spec/fixtures/layout_example.txt
112
124
  - spec/fixtures/layout_example.txt~
113
125
  - spec/fixtures/pipes.txt
126
+ - spec/fixtures/soap_response.txt
127
+ - spec/fixtures/soap_response_sin_xml.txt
114
128
  - spec/fixtures/timbre_example.txt
129
+ - spec/fm_timbrado_cfdi/fm_respuesta_spec.rb
115
130
  - spec/fm_timbrado_cfdi/fm_timbre_spec.rb
116
131
  - spec/fm_timbrado_cfdi_spec.rb
117
132
  - spec/spec_helper.rb