cfdi40 0.0.2 → 0.0.3

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
  SHA256:
3
- metadata.gz: 000e715fcb57e869f47058bb05bc2cadc558f188db6da41e1c0d0240873d910b
4
- data.tar.gz: 2ab314d7b2477308a4cc073f8ebe35a31098b8ac5ecb23aa0dd4d43babc95ae8
3
+ metadata.gz: bb9a12ec72926735a554f302b13993914393c626cc4dcd797791dfcf0ed8191a
4
+ data.tar.gz: 4bc4708eb4c2c0671fa11c81dbcb40a8a8c9a585d2fa02531137efeee942a9d0
5
5
  SHA512:
6
- metadata.gz: fccd3b919ade4540d90a2b9ff81778e68cd900f121c7e92d4e4bb192585d5bb0d921a1a148bca0df23a5f26ab7da0dc5de165d7f068352701a93f2936d65792e
7
- data.tar.gz: ae39a825b18d9f3cbbbd8403b6afb4a920bc4abd61479777d35d774bf5fe44426dd1b472856f966f95b10b50b04ee28773c121431f6d3c4990127bacb02fd09a
6
+ metadata.gz: f41d5ee33e1e705d2b12b2c623cd6b197d2c93c1a9e5d994ffc38630954fc4cb6ed6a1c2ae084513bfa6991f7c1bf67b4cc609ebbca3c2d1c99d74167897f470
7
+ data.tar.gz: 9f55e7a93233c1c8121d26424c2a7604d36b58f6695b104dc64ea39091e16bb45f3da10231ff4367e75c56d843fd724284b2adae053617244a2295227d3bc41d
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cfdi40 (0.0.1.alfa)
4
+ cfdi40 (0.0.3)
5
5
  nokogiri (>= 1.10.10)
6
6
 
7
7
  GEM
data/README_es-MX.md CHANGED
@@ -24,7 +24,7 @@ que esta herramienta:
24
24
  # Inicia un cfdi
25
25
  cfdi = Cfdi40.new
26
26
 
27
- # Datos del emisor
27
+ # Datos del emisor. RFC y Nombre se extraen del certificado
28
28
  cfdi.lugar_expedicion = '06000'
29
29
  cfdi.emisor.regimen_fiscal = '612'
30
30
 
@@ -53,6 +53,28 @@ que esta herramienta:
53
53
  # Genera CFDI firmado
54
54
  xml_string = cfdi.to_xml
55
55
 
56
+ # Cambios
57
+
58
+ # 0.0.3
59
+
60
+ * Lee RFC en certificados de personas morales. Los certificados de
61
+ personas morales tienen el RFC de la persona moral y el del
62
+ representante legal en el `UniqueIdentifier` del `Subject` del
63
+ certificado
64
+ * Actepta llaves previamente descifradas en formato PEM.
65
+
66
+ # 0.0.2
67
+
68
+ * Definición básica de la intefaz.
69
+ * Carga certificado y llave desde archivo.
70
+ * Acepta certificado y llave previamente leídos.
71
+ * Genera CFDI de ingresos básico. Con desglose de impuestos, sello
72
+ digital
73
+ * Valida correspondencia de certificado y llave
74
+
75
+ # 0.0.1
76
+
77
+ * Versión inicial. Esqueleto para desarrollo
56
78
 
57
79
  # ¿Que sigue?
58
80
 
@@ -0,0 +1,12 @@
1
+ module Cfdi40
2
+ class ComplementoConcepto < Node
3
+ def inst_educativas_node
4
+ return @inst_educativas_node if defined?(@inst_educativas_node)
5
+
6
+ @inst_educativas_node = InstEducativas.new
7
+ @inst_educativas_node.parent_node = self
8
+ self.children_nodes << @inst_educativas_node
9
+ @inst_educativas_node
10
+ end
11
+ end
12
+ end
@@ -32,14 +32,17 @@ module Cfdi40
32
32
 
33
33
  attr_reader :emisor, :receptor, :x509_cert, :conceptos, :private_key
34
34
  attr_reader :errors
35
- attr_writer :key_der, :key_pass
35
+ attr_writer :key_data, :key_pass
36
36
 
37
37
  def initialize
38
38
  super
39
39
  @errors = []
40
40
  @conceptos = Conceptos.new
41
+ @conceptos.parent_node = self
41
42
  @emisor = Emisor.new
43
+ @emisor.parent_node = self
42
44
  @receptor = Receptor.new
45
+ @receptor.parent_node = self
43
46
  @sat_csd = SatCsd.new
44
47
  @fecha ||= Time.now.strftime("%Y-%m-%dT%H:%M:%S")
45
48
  @children_nodes = [@emisor, @receptor, @conceptos]
@@ -64,7 +67,7 @@ module Cfdi40
64
67
  end
65
68
 
66
69
  def key_path=(path)
67
- @key_der = File.read(path)
70
+ @key_data = File.read(path)
68
71
  end
69
72
 
70
73
  def sign
@@ -89,8 +92,11 @@ module Cfdi40
89
92
  # importe
90
93
  # descuento
91
94
  # objeto_imp
95
+ #
96
+ # TODO: Document accepted attributes and its use
92
97
  def add_concepto(attributes = {})
93
98
  concepto = Concepto.new
99
+ concepto.parent_node = @conceptos
94
100
  attributes.each do |key, value|
95
101
  method_name = "#{key}=".to_sym
96
102
  if concepto.respond_to?(method_name)
@@ -154,15 +160,18 @@ module Cfdi40
154
160
  def calculate!
155
161
  @subtotal = @conceptos.children_nodes.map(&:importe).sum
156
162
  @total = @conceptos.children_nodes.map(&:importe_neto).sum
157
- summarize_traslados
163
+ add_traslados_summary_node
158
164
  end
159
165
 
160
- def summarize_traslados
166
+ def add_traslados_summary_node
167
+ return if traslados_summary.empty?
168
+
161
169
  impuestos.total_impuestos_trasladados = 0
162
170
  traslados.children_nodes = []
163
171
  traslados_summary.each do |key, value|
164
172
  #TODO: Sumar los impuestos y agregarlos a los nodos globales de traslados
165
173
  traslado = Traslado.new
174
+ traslado.parent_node = impuestos
166
175
  traslado.impuesto, traslado.tasa_o_cuota, traslado.tipo_factor = key
167
176
  traslado.base = value[:base]
168
177
  traslado.importe = value[:importe]
@@ -196,6 +205,7 @@ module Cfdi40
196
205
  return @impuestos if defined?(@impuestos)
197
206
 
198
207
  @impuestos = Impuestos.new
208
+ @impuestos.parent_node = self
199
209
  @children_nodes << @impuestos
200
210
  @impuestos
201
211
  end
@@ -216,10 +226,10 @@ module Cfdi40
216
226
  end
217
227
 
218
228
  def load_private_key
219
- return unless defined?(@key_der) && defined?(@key_pass)
229
+ return unless defined?(@key_data) && defined?(@key_pass)
220
230
 
221
231
  @sat_csd ||= SatCsd.new
222
- @sat_csd.set_crypted_private_key(@key_der, @key_pass)
232
+ @sat_csd.set_private_key(@key_data, @key_pass)
223
233
  end
224
234
  end
225
235
  end
@@ -19,6 +19,9 @@ module Cfdi40
19
19
  attr_accessor :tasa_iva, :tasa_ieps, :precio_neto, :precio_bruto
20
20
  attr_reader :iva, :ieps, :base_iva, :importe_neto, :importe_bruto
21
21
 
22
+ # accesors for instEducativas
23
+ attr_accessor :iedu_nombre_alumno, :iedu_curp, :iedu_nivel_educativo, :iedu_aut_rvoe, :iedu_rfc_pago
24
+
22
25
  def initialize
23
26
  @tasa_iva = 0.16
24
27
  @tasa_ieps = 0
@@ -40,6 +43,7 @@ module Cfdi40
40
43
  end
41
44
  add_info_to_traslado_iva
42
45
  # TODO: add_info_to_traslado_ieps if @ieps > 0
46
+ add_inst_educativas
43
47
  true
44
48
  end
45
49
 
@@ -113,6 +117,7 @@ module Cfdi40
113
117
  return if @impuestos_node
114
118
 
115
119
  @impuestos_node = Impuestos.new
120
+ @impuestos_node.parent_node = self
116
121
  self.children_nodes << @impuestos_node
117
122
  @impuestos_node
118
123
  end
@@ -122,5 +127,38 @@ module Cfdi40
122
127
 
123
128
  impuestos_node.traslado_iva
124
129
  end
130
+
131
+ def add_inst_educativas
132
+ return unless inst_educativas_present?
133
+
134
+ inst_educativas_node.nombre_alumno = iedu_nombre_alumno
135
+ inst_educativas_node.curp = iedu_curp
136
+ inst_educativas_node.nivel_educativo = iedu_nivel_educativo
137
+ inst_educativas_node.aut_rvoe = iedu_aut_rvoe
138
+ inst_educativas_node.rfc_pago = iedu_rfc_pago
139
+ end
140
+
141
+ def inst_educativas_present?
142
+ return false if iedu_nombre_alumno.nil?
143
+ return false if iedu_nivel_educativo.nil?
144
+ return false if iedu_aut_rvoe.nil?
145
+
146
+ true
147
+ end
148
+
149
+ def concepto_complemento_node
150
+ return @complemento_concepto_node if defined?(@complemento_concepto_node)
151
+
152
+ @complemento_concepto_node = ComplementoConcepto.new
153
+ @complemento_concepto_node.parent_node = self
154
+ self.children_nodes << @complemento_concepto_node
155
+ @complemento_concepto_node
156
+ end
157
+
158
+ def inst_educativas_node
159
+ return nil unless concepto_complemento_node.is_a?(ComplementoConcepto)
160
+
161
+ concepto_complemento_node.inst_educativas_node
162
+ end
125
163
  end
126
164
  end
@@ -7,6 +7,7 @@ module Cfdi40
7
7
  return @traslados if defined?(@traslados)
8
8
 
9
9
  @traslados = Traslados.new
10
+ @traslados.parent_node = self
10
11
  self.children_nodes << @traslados
11
12
  @traslados
12
13
  end
@@ -0,0 +1,17 @@
1
+ module Cfdi40
2
+ class InstEducativas < Node
3
+ define_element_name 'instEducativas'
4
+ define_namespace "xsi", "http://www.w3.org/2001/XMLSchema-instance"
5
+ define_namespace "iedu", "http://www.sat.gob.mx/iedu"
6
+ define_attribute :schema_location,
7
+ xml_attribute: 'xsi:schemaLocation',
8
+ readonly: true,
9
+ default: "http://www.sat.gob.mx/iedu http://www.sat.gob.mx/sitio_internet/cfd/iedu/iedu.xsd"
10
+ define_attribute :version, xml_attribute: 'version', readonly: true, default: '1.0'
11
+ define_attribute :nombre_alumno, xml_attribute: 'nombreAlumno'
12
+ define_attribute :curp, xml_attribute: 'CURP'
13
+ define_attribute :nivel_educativo, xml_attribute: 'nivelEducativo'
14
+ define_attribute :aut_rvoe, xml_attribute: 'autRVOE'
15
+ define_attribute :rfc_pago, xml_attribute: 'rfcPago'
16
+ end
17
+ end
data/lib/cfdi40/node.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  module Cfdi40
2
2
  class Node
3
3
  # Nokigir XML Document for the xml_node
4
- attr_accessor :xml_document, :xml_parent, :children_nodes
4
+ attr_accessor :xml_document, :xml_parent, :children_nodes, :parent_node
5
+ attr_writer :element_name
5
6
 
6
7
  def initialize
7
8
  self.class.verify_class_variables
@@ -20,6 +21,7 @@ module Cfdi40
20
21
  @@default_values[name] ||= {}
21
22
  @@formats ||= {}
22
23
  @@formats[name] ||= {}
24
+ @@element_names ||= {}
23
25
  end
24
26
 
25
27
  def self.define_attribute(accessor, xml_attribute:, default: nil, format: nil, readonly: false)
@@ -43,6 +45,11 @@ module Cfdi40
43
45
  @@namespaces[name][namespace] = value
44
46
  end
45
47
 
48
+ def self.define_element_name(value)
49
+ verify_class_variables
50
+ @@element_names[name] = value.to_s
51
+ end
52
+
46
53
  def self.namespaces
47
54
  @@namespaces[name]
48
55
  end
@@ -59,6 +66,11 @@ module Cfdi40
59
66
  @@formats[name]
60
67
  end
61
68
 
69
+ def self.element_name
70
+ verify_class_variables
71
+ @@element_names[name]
72
+ end
73
+
62
74
  def set_defaults
63
75
  return if self.class.default_values.nil?
64
76
 
@@ -75,18 +87,39 @@ module Cfdi40
75
87
  instance_variable_get("@#{accessor}".to_sym).nil?
76
88
  end
77
89
 
90
+ def current_namespace
91
+ return unless self.class.respond_to?(:namespaces)
92
+ if self.class.namespaces.empty?
93
+ return parent_node.current_namespace unless parent_node.nil?
94
+ end
95
+
96
+ self.class.namespaces.keys.last
97
+ end
98
+
78
99
  def create_xml_node
79
100
  set_defaults
80
101
  if self.respond_to?(:before_add, true)
81
102
  self.before_add
82
103
  end
83
- xml_node = xml_document.create_element("cfdi:#{self.class.name.split('::').last}")
104
+ xml_node = xml_document.create_element(expanded_element_name)
84
105
  add_namespaces_to(xml_node)
85
106
  add_attributes_to(xml_node)
86
107
  add_children_to(xml_node)
87
108
  xml_parent.add_child xml_node
88
109
  end
89
110
 
111
+ # Returns setted @element_name or use class_name
112
+ def element_name
113
+ return self.class.element_name unless self.class.element_name.nil? || self.class.element_name == ''
114
+
115
+ self.class.name.split('::').last
116
+ end
117
+
118
+ def expanded_element_name
119
+ return element_name unless current_namespace
120
+ "#{current_namespace}:#{element_name}"
121
+ end
122
+
90
123
  def add_namespaces_to(xml_node)
91
124
  self.class.namespaces.each do |namespace, value|
92
125
  xml_node.add_namespace namespace, value
@@ -13,12 +13,12 @@ module Cfdi40
13
13
  end
14
14
 
15
15
  def load_private_key(key_path, key_pass)
16
- key_pem = load_key_to_pem(File.read(key_path))
16
+ key_pem = key_to_pem(File.read(key_path))
17
17
  @private_key = OpenSSL::PKey::RSA.new(key_pem, key_pass)
18
18
  end
19
19
 
20
- def set_crypted_private_key(key_der, key_pass)
21
- key_pem = load_key_to_pem(key_der)
20
+ def set_private_key(key_data, key_pass = nil)
21
+ key_pem = (pem_format?(key_data) ? key_data : key_to_pem(key_data))
22
22
  @private_key = OpenSSL::PKey::RSA.new(key_pem, key_pass)
23
23
  end
24
24
 
@@ -28,7 +28,7 @@ module Cfdi40
28
28
  unique_identifier = subject_data.select { |data| data[0] == "x500UniqueIdentifier" }.first
29
29
  return unless unique_identifier
30
30
 
31
- unique_identifier[1]
31
+ unique_identifier[1].split(" / ").first
32
32
  end
33
33
 
34
34
  def name
@@ -72,12 +72,18 @@ module Cfdi40
72
72
  x509_cert.subject.to_a
73
73
  end
74
74
 
75
- def load_key_to_pem(key_der)
75
+ def key_to_pem(key_der)
76
76
  array_key_pem = []
77
77
  array_key_pem << '-----BEGIN ENCRYPTED PRIVATE KEY-----'
78
78
  array_key_pem += Base64.strict_encode64(key_der).scan(/.{1,64}/)
79
79
  array_key_pem << '-----END ENCRYPTED PRIVATE KEY-----'
80
80
  array_key_pem.join("\n")
81
81
  end
82
+
83
+ def pem_format?(data)
84
+ return false unless data.valid_encoding?
85
+
86
+ data.match?(/BEGIN/)
87
+ end
82
88
  end
83
89
  end
@@ -6,6 +6,7 @@ module Cfdi40
6
6
  @traslado_iva = Traslado.new
7
7
  # TODO: FIX magic number
8
8
  @traslado_iva.impuesto = '002'
9
+ @traslado_iva.parent_node = self
9
10
  self.children_nodes << @traslado_iva
10
11
  @traslado_iva
11
12
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cfdi40
4
- VERSION = "0.0.2"
4
+ VERSION = "0.0.3"
5
5
  end
data/lib/cfdi40.rb CHANGED
@@ -15,6 +15,8 @@ require_relative "cfdi40/concepto"
15
15
  require_relative "cfdi40/impuestos"
16
16
  require_relative "cfdi40/traslados"
17
17
  require_relative "cfdi40/traslado"
18
+ require_relative "cfdi40/complemento_concepto"
19
+ require_relative "cfdi40/inst_educativas"
18
20
 
19
21
  # Leading module and entry point for all features and classes
20
22
  #
data/lib/xsd/README.md CHANGED
@@ -6,9 +6,13 @@ In order to avoid innecesary and redundant reading from SAT site the
6
6
  file `cfdv40.xsd` referenced in cfdi standard, has been
7
7
  prepared for local access.
8
8
 
9
- The `cfdv40.xsd` has been modified to reference the local files
10
- `tdCFDI.xsd`, `catCFDI.xsd` which are imported schemas. The schema
11
- `catCFDI.xsd` has 5.8MB
9
+ The `cfdv40.xsd` has been modified to reference the local files:
10
+
11
+ * `tdCFDI.xsd`,
12
+ * `catCFDI.xsd` this file has 5.8MB
13
+ * `iedu.xsd`
14
+
15
+ Local files are imported schemas.
12
16
 
13
17
  ## Use external files
14
18
 
data/lib/xsd/cfdv40.xsd CHANGED
@@ -7,6 +7,7 @@
7
7
  -->
8
8
  <xs:import namespace="http://www.sat.gob.mx/sitio_internet/cfd/catalogos" schemaLocation="catCFDI.xsd"/>
9
9
  <xs:import namespace="http://www.sat.gob.mx/sitio_internet/cfd/tipoDatos/tdCFDI" schemaLocation="tdCFDI.xsd"/>
10
+ <xs:import namespace="http://www.sat.gob.mx/iedu" schemaLocation="iedu.xsd"/>
10
11
 
11
12
  <xs:element name="Comprobante">
12
13
  <xs:annotation>
data/lib/xsd/iedu.xsd ADDED
@@ -0,0 +1,84 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:iedu="http://www.sat.gob.mx/iedu" targetNamespace="http://www.sat.gob.mx/iedu" elementFormDefault="qualified" attributeFormDefault="unqualified">
3
+ <xs:element name="instEducativas">
4
+ <xs:annotation>
5
+ <xs:documentation>Complemento concepto para la expedición de comprobantes fiscales por parte de Instituciones Educativas Privadas, para los efectos del artículo primero y cuarto del decreto por el que se otorga un estímulo fiscal a las personas físicas en relación con los pagos por servicios educativos </xs:documentation>
6
+ </xs:annotation>
7
+ <xs:complexType>
8
+ <xs:attribute name="version" use="required" fixed="1.0">
9
+ <xs:annotation>
10
+ <xs:documentation>Atributo requerido con valor prefijado a 1.0 que indica la versión del estándar bajo el que se encuentra expresado el complemento concepto al comprobante.</xs:documentation>
11
+ </xs:annotation>
12
+ <xs:simpleType>
13
+ <xs:restriction base="xs:string">
14
+ <xs:whiteSpace value="collapse"/>
15
+ </xs:restriction>
16
+ </xs:simpleType>
17
+ </xs:attribute>
18
+ <xs:attribute name="nombreAlumno" use="required">
19
+ <xs:annotation>
20
+ <xs:documentation>Atributo requerido para indicar el nombre del Alumno </xs:documentation>
21
+ </xs:annotation>
22
+ <xs:simpleType>
23
+ <xs:restriction base="xs:string"/>
24
+ </xs:simpleType>
25
+ </xs:attribute>
26
+ <xs:attribute name="CURP" type="iedu:tCURP" use="required">
27
+ <xs:annotation>
28
+ <xs:documentation>Atributo requerido para indicar la CURP del alumno de la institución educativa</xs:documentation>
29
+ </xs:annotation>
30
+ </xs:attribute>
31
+ <xs:attribute name="nivelEducativo" use="required">
32
+ <xs:annotation>
33
+ <xs:documentation>Atributo requerido para indicar el nivel educativo que cursa el alumno</xs:documentation>
34
+ </xs:annotation>
35
+ <xs:simpleType>
36
+ <xs:restriction base="xs:string">
37
+ <xs:enumeration value="Preescolar"/>
38
+ <xs:enumeration value="Primaria"/>
39
+ <xs:enumeration value="Secundaria"/>
40
+ <xs:enumeration value="Profesional técnico"/>
41
+ <xs:enumeration value="Bachillerato o su equivalente"/>
42
+ </xs:restriction>
43
+ </xs:simpleType>
44
+ </xs:attribute>
45
+ <xs:attribute name="autRVOE" use="required">
46
+ <xs:annotation>
47
+ <xs:documentation>Atributo requerido para especificar la clave del centro de trabajo o el reconocimiento de validez oficial de estudios en los términos de la Ley General de Educación que tenga la institución educativa privada donde se realiza el pago.</xs:documentation>
48
+ </xs:annotation>
49
+ <xs:simpleType>
50
+ <xs:restriction base="xs:string">
51
+ <xs:minLength value="1"/>
52
+ <xs:whiteSpace value="collapse"/>
53
+ </xs:restriction>
54
+ </xs:simpleType>
55
+ </xs:attribute>
56
+ <xs:attribute name="rfcPago" type="iedu:tRFC" use="optional">
57
+ <xs:annotation>
58
+ <xs:documentation>Atributo opcional para indicar el RFC de quien realiza el pago cuando sea diferente a quien recibe el servicio</xs:documentation>
59
+ </xs:annotation>
60
+ </xs:attribute>
61
+ </xs:complexType>
62
+ </xs:element>
63
+ <xs:simpleType name="tRFC">
64
+ <xs:annotation>
65
+ <xs:documentation>Tipo definido para la expresión de RFC's de contribuyentes. Cabe hacer la mención que debido a las reglas definidas por el estándar XML en el caso de que un RFC dado incluya un caracter ampersand, dicho caracter deberá ser expresado mediante la secuencia de escape especificado como parte del estándar. En la definición del tipo se expresa una longitud mínima y máxima, sin embargo la longitud puede ser redefinida como una extensión según se determina el uso particular</xs:documentation>
66
+ </xs:annotation>
67
+ <xs:restriction base="xs:string">
68
+ <xs:minLength value="12"/>
69
+ <xs:maxLength value="13"/>
70
+ <xs:whiteSpace value="collapse"/>
71
+ <xs:pattern value="[A-Z,Ñ,&amp;]{3,4}[0-9]{2}[0-1][0-9][0-3][0-9][A-Z,0-9]?[A-Z,0-9]?[0-9,A-Z]?"/>
72
+ </xs:restriction>
73
+ </xs:simpleType>
74
+ <xs:simpleType name="tCURP">
75
+ <xs:annotation>
76
+ <xs:documentation>Tipo definido para la expresión de una CURP. </xs:documentation>
77
+ </xs:annotation>
78
+ <xs:restriction base="xs:string">
79
+ <xs:whiteSpace value="collapse"/>
80
+ <xs:length value="18"/>
81
+ <xs:pattern value="[A-Z][A,E,I,O,U,X][A-Z]{2}[0-9]{2}[0-1][0-9][0-3][0-9][M,H][A-Z]{2}[B,C,D,F,G,H,J,K,L,M,N,Ñ,P,Q,R,S,T,V,W,X,Y,Z]{3}[0-9,A-Z][0-9]"/>
82
+ </xs:restriction>
83
+ </xs:simpleType>
84
+ </xs:schema>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfdi40
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Israel Benítez
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-03-17 00:00:00.000000000 Z
11
+ date: 2023-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -43,11 +43,13 @@ files:
43
43
  - Rakefile
44
44
  - cfdi40.gemspec
45
45
  - lib/cfdi40.rb
46
+ - lib/cfdi40/complemento_concepto.rb
46
47
  - lib/cfdi40/comprobante.rb
47
48
  - lib/cfdi40/concepto.rb
48
49
  - lib/cfdi40/conceptos.rb
49
50
  - lib/cfdi40/emisor.rb
50
51
  - lib/cfdi40/impuestos.rb
52
+ - lib/cfdi40/inst_educativas.rb
51
53
  - lib/cfdi40/node.rb
52
54
  - lib/cfdi40/receptor.rb
53
55
  - lib/cfdi40/sat_csd.rb
@@ -58,6 +60,7 @@ files:
58
60
  - lib/xsd/README.md
59
61
  - lib/xsd/catCFDI.xsd
60
62
  - lib/xsd/cfdv40.xsd
63
+ - lib/xsd/iedu.xsd
61
64
  - lib/xsd/tdCFDI.xsd
62
65
  - lib/xslt/CartaPorte20.xslt
63
66
  - lib/xslt/GastosHidrocarburos10.xslt