cfdi40 0.0.5 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d48bd150dec201d3a2b0812d49080313c5e4aec6efd836e5606e9e2edabd822f
4
- data.tar.gz: 3f437736ebc91684c7652f217f64a0e04c9e8b18519a18a02397ab4f95ca8db9
3
+ metadata.gz: 55ca7f3a64dc87b4b19cbb5d389f71ccd624b70e7c5af601d97dd4dd6e1599db
4
+ data.tar.gz: 9cab2e03e554d96d47ff328c6c520782036ee9b561f11586c42bd353a3112f1d
5
5
  SHA512:
6
- metadata.gz: 4491ff366eeb72c4c6d1792227750e5c3f333d6df52f7d974c05eff8d4d94f30a44e98dfefaf03b1aaa41a8d1407e2765a3ef026617faa071fb86049cbbec9f9
7
- data.tar.gz: 77c1ee1687c4b13af13768afa7a5b3ee0c7ab2071a4a3ddbf45d3bedcf4a18bb2a8e56b07bdf1762d6e833c052cf77c1b3272b04a75cb3f28d2c0494b76d66af
6
+ metadata.gz: '0310189ea57acabe4fffc77ed24d1b02aab3d49e0afafd47d1abf7df10856d19a5a00b89d302138c6b43b036e8af5d52671d922b274e10613f1d57d76b732e1e'
7
+ data.tar.gz: 719ed8d0e569dd621edf7ee702271b7c468c2e6b4606297f650cac39b6cb199d06d881f07b15e56599d214da3481651987348cfc24997e6a1843939ea933c711
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cfdi40 (0.0.5)
4
+ cfdi40 (0.0.6)
5
5
  nokogiri (>= 1.10.10)
6
6
 
7
7
  GEM
data/README_es-MX.md CHANGED
@@ -53,8 +53,58 @@ que esta herramienta:
53
53
  # Genera CFDI firmado
54
54
  xml_string = cfdi.to_xml
55
55
 
56
+ ## Ejemplo CFDI con complemento de pago
57
+
58
+ # Inicia un cfdi
59
+ cfdi = Cfdi40.new
60
+ cfdi.tipo_de_comprobante = 'P'
61
+
62
+ # Datos del emisor.
63
+ # RFC y Nombre se extraen del certificado si no existen
64
+ cfdi.lugar_expedicion = '06000'
65
+ cfdi.emisor.regimen_fiscal = '612'
66
+
67
+ # Datos del receptor
68
+ cfdi.receptor.nombre = 'JUAN PUEBLO BUENO'
69
+ cfdi.receptor.rfc = 'XAXX010101000'
70
+ cfdi.receptor.domicilio_fiscal = '06000'
71
+ cfdi.receptor.regimen_fiscal = '616'
72
+ cfdi.receptor.uso_cfdi = 'CP01'
73
+
74
+ # Agrega un concepto en pesos,
75
+ # precio final al cliente (neto)
76
+ # causa IVA con tasa de 16% (default)
77
+ cfdi.add_pago(
78
+ monto: 200.17,
79
+ uuid: 'e40229b3-5c4b-46fb-9ba8-707df828a5bc',
80
+ serie: 'A',
81
+ folio: '12345',
82
+ num_parcialidad: 2,
83
+ fecha_pago: '2023-04-01T12:20:34',
84
+ forma_pago: '01',
85
+ importe_saldo_anterior: 845.673
86
+ )
87
+
88
+ # Archivos CSD
89
+ cfdi.cert_path = '/path_to/certificado.cer'
90
+ cfdi.key_path = '/path_to/llave_privada.key'
91
+ cfdi.key_pass = 'contraseña'
92
+
93
+ # Genera CFDI firmado
94
+ xml_string = cfdi.to_xml
95
+
96
+
97
+ # Lo que sigue
98
+
99
+ * Nodo de Traslados cuando hay tasa de IEPS
100
+ * Retenciones de impuestos
101
+ * CFDI de pagos con varios pagos y varios documentos en cada pago
102
+
56
103
  # Cambios
57
104
 
105
+ # 0.0.6
106
+ * CFDi con complemento de pagos
107
+
58
108
  # 0.0.5
59
109
 
60
110
  * IVA tasa 0 e IVA excento. Los conceptos con iva tasa 0 deben llevar el
@@ -0,0 +1,18 @@
1
+ module Cfdi40
2
+ class Complemento < Node
3
+ # See Comprobante#add_pago
4
+ def add_pago(attributes={})
5
+ pagos.totales_node
6
+ pagos.add_pago(attributes)
7
+ end
8
+
9
+ def pagos
10
+ return @pagos if defined?(@pagos)
11
+
12
+ @pagos = Pagos.new
13
+ @pagos.parent_node = self
14
+ @children_nodes << @pagos
15
+ @pagos
16
+ end
17
+ end
18
+ end
@@ -119,6 +119,8 @@ module Cfdi40
119
119
  # +iedu_rfc_pago+::
120
120
  #
121
121
  def add_concepto(attributes = {})
122
+ raise Error, 'CFDi tipo pago no acepta conceptos' if tipo_de_comprobante == 'P'
123
+
122
124
  concepto = Concepto.new
123
125
  concepto.parent_node = @conceptos
124
126
  attributes.each do |key, value|
@@ -135,6 +137,23 @@ module Cfdi40
135
137
  concepto
136
138
  end
137
139
 
140
+ # TODO: Doc params add_pago
141
+ # monto
142
+ # uuid
143
+ # folio
144
+ # serie
145
+ # num_parcialidad
146
+ # fecha_pago
147
+ # forma_pago
148
+ # importe_saldo_anterior
149
+ # objeto_impuestos
150
+ def add_pago(attributes = {})
151
+ raise Error, "CFDi debe ser tipo 'P'" unless tipo_de_comprobante == 'P'
152
+
153
+ add_node_concepto_actividad_pago
154
+ complemento.add_pago(attributes)
155
+ end
156
+
138
157
  def to_s
139
158
  to_xml
140
159
  end
@@ -167,6 +186,23 @@ module Cfdi40
167
186
 
168
187
  private
169
188
 
189
+ def add_node_concepto_actividad_pago
190
+ return if defined?(@concepto_actividad)
191
+
192
+ @receptor.uso_cfdi = 'CP01'
193
+ @concepto_actividad = Concepto.new
194
+ @concepto_actividad.clave_prod_serv = '84111506'
195
+ @concepto_actividad.cantidad = 1
196
+ @concepto_actividad.clave_unidad = 'ACT'
197
+ @concepto_actividad.descripcion = 'Pago'
198
+ @concepto_actividad.precio_bruto = 0
199
+ @concepto_actividad.tasa_iva = nil
200
+ @concepto_actividad.objeto_impuestos = '01'
201
+ @concepto_actividad.calculate!
202
+ @conceptos.add_child_node @concepto_actividad
203
+ calculate!
204
+ end
205
+
170
206
  def docxml
171
207
  return @docxml if defined?(@docxml) && !@docxml.nil?
172
208
 
@@ -245,7 +281,7 @@ module Cfdi40
245
281
  impuestos_node.traslados
246
282
  end
247
283
 
248
- # Eliminar
284
+ # TODO: Eliminar
249
285
  def traslado_iva_node
250
286
  impuestos_node.traslado_iva
251
287
  end
@@ -256,5 +292,14 @@ module Cfdi40
256
292
  @sat_csd ||= SatCsd.new
257
293
  @sat_csd.set_private_key(@key_data, (defined?(@key_pass) ? @key_pass : nil))
258
294
  end
295
+
296
+ def complemento
297
+ return @complemento if defined?(@complemento)
298
+
299
+ @complemento = Complemento.new
300
+ @complemento.parent_node = self
301
+ @children_nodes << @complemento
302
+ @complemento
303
+ end
259
304
  end
260
305
  end
@@ -71,7 +71,9 @@ module Cfdi40
71
71
  def calculate_from_gross_price
72
72
  @precio_bruto = @precio_bruto.round(6)
73
73
  calculate_taxes
74
- @precio_neto = (@importe_neto / cantidad).round(2)
74
+ # May be can not be rounded with 2 decimals.
75
+ # Example gross_price = 1.99512
76
+ @precio_neto = (@importe_neto / cantidad).round(6)
75
77
  update_xml_attributes
76
78
  end
77
79
 
@@ -0,0 +1,66 @@
1
+ module Cfdi40
2
+ class DoctoRelacionado < Node
3
+ define_attribute :id_documento, xml_attribute: 'IdDocumento'
4
+ define_attribute :serie, xml_attribute: 'Serie'
5
+ define_attribute :folio, xml_attribute: 'Folio'
6
+ define_attribute :moneda_dr, xml_attribute: 'MonedaDR', default: 'MXN'
7
+ define_attribute :equivalencia_dr, xml_attribute: 'EquivalenciaDR'
8
+ define_attribute :num_parcialidad, xml_attribute: 'NumParcialidad'
9
+ define_attribute :imp_saldo_ant, xml_attribute: 'ImpSaldoAnt', format: :t_ImporteMXN
10
+ define_attribute :imp_pagado, xml_attribute: 'ImpPagado', format: :t_ImporteMXN
11
+ define_attribute :imp_saldo_insoluto, xml_attribute: 'ImpSaldoInsoluto', format: :t_ImporteMXN
12
+ define_attribute :objeto_imp_dr, xml_attribute: 'ObjetoImpDR', default: '02'
13
+
14
+ def calculate!
15
+ self.imp_saldo_insoluto = (imp_saldo_ant - imp_pagado).round(2)
16
+ add_impuestos
17
+ end
18
+
19
+ # Add nodes for 'traslado_dr' and/or 'retencion_dr' and intermetiate nodes
20
+ def add_impuestos
21
+ add_traslado if objeto_imp_dr == '02'
22
+ end
23
+
24
+ def add_traslado
25
+ return unless objeto_imp_dr == '02'
26
+
27
+ # Taxes values for IVA rate 0.16 assumming that all 'conceptos' in the realted document
28
+ # has the same tax rate. This could not be true but the is the most common case.
29
+ traslado_dr = TrasladoDR.new
30
+ traslado_dr.monto_pago = imp_pagado.round(2)
31
+ traslado_dr.calculate!
32
+ traslados_dr.add_child_node(traslado_dr)
33
+ traslado_dr
34
+ end
35
+
36
+ # Return a hash. The key is an array [impuesto, tipo_factor, tasa_o_cuot]
37
+ # and the value is another hash with the keys :base, :importe
38
+ def traslados_summary
39
+ return {} unless defined?(@traslados_dr)
40
+
41
+ summary = {}
42
+ @traslados_dr.children_nodes.each do |traslado_dr|
43
+ key = [traslado_dr.impuesto_dr, traslado_dr.tipo_factor_dr, traslado_dr.tasa_o_cuota_dr]
44
+ summary[key] ||= { base: 0, importe: 0 }
45
+ summary[key][:base] += traslado_dr.base_dr.to_f
46
+ summary[key][:importe] += traslado_dr.importe_dr.to_f
47
+ end
48
+ summary
49
+ end
50
+
51
+ def traslados_dr
52
+ return @traslados_dr if defined?(@traslados_dr)
53
+
54
+ @traslados_dr = impuestos_dr.traslados_dr
55
+ end
56
+
57
+ def impuestos_dr
58
+ return @impuestos_dr if defined?(@impuestos_dr)
59
+
60
+ @impuestos_dr = ImpuestosDR.new
61
+ @impuestos_dr.parent_node = self
62
+ @children_nodes << @impuestos_dr
63
+ @impuestos_dr
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,12 @@
1
+ module Cfdi40
2
+ class ImpuestosDR < Node
3
+ def traslados_dr
4
+ return @traslados_dr if defined?(@traslados_dr)
5
+
6
+ @traslados_dr = TrasladosDR.new
7
+ @traslados_dr.parent_node = self
8
+ @children_nodes << @traslados_dr
9
+ @traslados_dr
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Cfdi40
2
+ class ImpuestosP < Node
3
+
4
+ def traslados_p
5
+ return @traslados_p if defined?(@traslados_p)
6
+
7
+ @traslados_p = TrasladosP.new
8
+ add_child_node @traslados_p
9
+ @traslados_p
10
+ end
11
+ end
12
+ end
data/lib/cfdi40/node.rb CHANGED
@@ -7,6 +7,7 @@ module Cfdi40
7
7
  def initialize
8
8
  self.class.verify_class_variables
9
9
  @children_nodes = []
10
+ set_defaults
10
11
  end
11
12
 
12
13
  # Use class variables to define attributes used to create nodes
@@ -87,6 +88,13 @@ module Cfdi40
87
88
  instance_variable_get("@#{accessor}".to_sym).nil?
88
89
  end
89
90
 
91
+ def add_child_node(child_node)
92
+ raise Error, 'child_node must be a Node object' unless child_node.is_a?(Node)
93
+
94
+ child_node.parent_node = self
95
+ @children_nodes << child_node
96
+ end
97
+
90
98
  def current_namespace
91
99
  return unless self.class.respond_to?(:namespaces)
92
100
  if self.class.namespaces.empty?
@@ -97,7 +105,8 @@ module Cfdi40
97
105
  end
98
106
 
99
107
  def create_xml_node
100
- set_defaults
108
+ # TODO: Quitar la siguiente linea (set_defaults) si funciona poniendo los defaults en initialize
109
+ # set_defaults
101
110
  if self.respond_to?(:before_add, true)
102
111
  self.before_add
103
112
  end
@@ -0,0 +1,56 @@
1
+ module Cfdi40
2
+ class Pago < Node
3
+ define_attribute :monto, xml_attribute: 'Monto'
4
+ define_attribute :fecha_pago, xml_attribute: 'FechaPago'
5
+ define_attribute :forma_pago, xml_attribute: 'FormaDePagoP'
6
+ define_attribute :moneda, xml_attribute: 'MonedaP', readonly: true, default: 'MXN'
7
+ define_attribute :tipo_cambio, xml_attribute: 'TipoCambioP', readonly: true, default: '1'
8
+
9
+ attr_accessor :uuid, :serie, :folio, :num_parcialidad, :importe_saldo_anterior, :objeto_impuestos
10
+
11
+ # Generate docto_relacionado node
12
+ # Data for dcto_relacionado node is obtained from de accessors
13
+ # uuid, serie, folio
14
+ def add_docto_relacionado
15
+ docto_relacionado = DoctoRelacionado.new
16
+ docto_relacionado.parent_node = self
17
+ docto_relacionado.id_documento = uuid
18
+ docto_relacionado.serie = serie
19
+ docto_relacionado.folio = folio
20
+ docto_relacionado.num_parcialidad = num_parcialidad
21
+ docto_relacionado.imp_saldo_ant = importe_saldo_anterior.round(2)
22
+ docto_relacionado.imp_pagado = monto
23
+ docto_relacionado.calculate!
24
+ @children_nodes << docto_relacionado
25
+ end
26
+
27
+ def add_impuestos_p
28
+ impuestos_p = ImpuestosP.new
29
+ add_child_node impuestos_p
30
+ impuestos_p.traslados_p.add_traslado_p_nodes
31
+ end
32
+
33
+ def docto_relacionados
34
+ return @docto_relacionados if defined?(@docto_relacionados)
35
+
36
+ @docto_relacionados =
37
+ @children_nodes.select do |child|
38
+ child if child.class.name == 'Cfdi40::DoctoRelacionado'
39
+ end
40
+ end
41
+
42
+ def traslados_summary
43
+ return @summary if defined?(@summary)
44
+
45
+ summary = {}
46
+ docto_relacionados.each do |docto|
47
+ docto.traslados_summary.each do |key, data|
48
+ summary[key] ||= {base: 0, importe: 0}
49
+ summary[key][:base] += data[:base]
50
+ summary[key][:importe] += data[:importe]
51
+ end
52
+ end
53
+ @summary = summary
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,73 @@
1
+ module Cfdi40
2
+ class Pagos < Node
3
+ define_namespace "pago20", "http://www.sat.gob.mx/Pagos20"
4
+ define_attribute :schema_location,
5
+ xml_attribute: 'xsi:schemaLocation',
6
+ readonly: true,
7
+ default: "http://www.sat.gob.mx/Pagos20 " \
8
+ "http://www.sat.gob.mx/sitio_internet/cfd/Pagos/Pagos20.xsd"
9
+ define_attribute :version, xml_attribute: 'Version', readonly: true, default: '2.0'
10
+
11
+ def add_pago(attributes={})
12
+ pago = Pago.new
13
+ pago.parent_node = self
14
+ attributes.each do |key, value|
15
+ method_name = "#{key}=".to_sym
16
+ if pago.respond_to?(method_name)
17
+ pago.public_send(method_name, value)
18
+ else
19
+ raise Error, ":#{key} no se puede asignar al nodo Pago"
20
+ end
21
+ end
22
+ pago.monto = pago.monto.round(2)
23
+ pago.add_docto_relacionado
24
+ pago.add_impuestos_p
25
+ @children_nodes << pago
26
+ update_totales
27
+ true
28
+ end
29
+
30
+ def update_totales
31
+ update_totales_traslado_iva16
32
+ update_total_monto
33
+ end
34
+
35
+ def update_totales_traslado_iva16
36
+ key = ['002', 'Tasa', '0.160000']
37
+ return if traslados_summary[key].nil?
38
+
39
+ totales_node.base_iva16 = traslados_summary[key][:base]
40
+ totales_node.importe_iva16 = traslados_summary[key][:importe]
41
+ end
42
+
43
+ def update_total_monto
44
+ totales_node.monto_total = pago_nodes.map(&:monto).sum
45
+ end
46
+
47
+ def traslados_summary
48
+ @traslados_summary if defined?(@traslados_summary)
49
+
50
+ summary = {}
51
+ pago_nodes.each do |pago|
52
+ pago.traslados_summary.each do |key, data|
53
+ summary[key] ||= { base: 0, importe: 0 }
54
+ summary[key][:base] += data[:base]
55
+ summary[key][:importe] += data[:importe]
56
+ end
57
+ end
58
+ @traslados_summary = summary
59
+ end
60
+
61
+ def totales_node
62
+ return @totales_node if defined?(@totales_node)
63
+
64
+ @totales_node = Totales.new
65
+ add_child_node @totales_node
66
+ @totales_node
67
+ end
68
+
69
+ def pago_nodes
70
+ @children_nodes.select { |node| node.class.name == 'Cfdi40::Pago' }
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,15 @@
1
+ module Cfdi40
2
+ class Totales < Node
3
+ define_attribute :ret_iva, xml_attribute: 'TotalRetencionesIVA'
4
+ define_attribute :ret_isr, xml_attribute: 'TotalRetencionesISR'
5
+ define_attribute :ret_ieps, xml_attribute: 'TotalRetencionesIEPS'
6
+ define_attribute :base_iva16, xml_attribute: 'TotalTrasladosBaseIVA16'
7
+ define_attribute :importe_iva16, xml_attribute: 'TotalTrasladosImpuestoIVA16'
8
+ define_attribute :base_iva8, xml_attribute: 'TotalTrasladosBaseIVA8'
9
+ define_attribute :importe_iva8, xml_attribute: 'TotalTrasladosImpuestoIVA8'
10
+ define_attribute :base_iva0, xml_attribute: 'TotalTrasladosBaseIVA0'
11
+ define_attribute :importe_iva0, xml_attribute: 'TotalTrasladosImpuestoIVA0'
12
+ define_attribute :base_iva_excento, xml_attribute: 'TotalTrasladosBaseIVAExento'
13
+ define_attribute :monto_total, xml_attribute: 'MontoTotalPagos'
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ module Cfdi40
2
+ class TrasladoDR < Node
3
+ define_attribute :base_dr, xml_attribute: 'BaseDR', format: :t_ImporteMXN
4
+ define_attribute :impuesto_dr, xml_attribute: 'ImpuestoDR', default: '002'
5
+ define_attribute :tipo_factor_dr, xml_attribute: 'TipoFactorDR', default: 'Tasa'
6
+ define_attribute :tasa_o_cuota_dr, xml_attribute: 'TasaOCuotaDR', default: '0.160000', format: :t_Importe
7
+ define_attribute :importe_dr, xml_attribute: 'ImporteDR', format: :t_ImporteMXN
8
+
9
+ attr_accessor :monto_pago
10
+
11
+ def calculate!
12
+ self.base_dr = (monto_pago / (1 + tasa_o_cuota_dr.to_f)).round(2)
13
+ self.importe_dr = (monto_pago - base_dr).round(2)
14
+ end
15
+ end
16
+ end
17
+
18
+
@@ -0,0 +1,9 @@
1
+ module Cfdi40
2
+ class TrasladoP < Node
3
+ define_attribute :base_p, xml_attribute: 'BaseP', format: :t_ImporteMXN
4
+ define_attribute :impuesto_p, xml_attribute: 'ImpuestoP', default: '002'
5
+ define_attribute :tipo_factor_p, xml_attribute: 'TipoFactorP', default: 'Tasa'
6
+ define_attribute :tasa_o_cuota_p, xml_attribute: 'TasaOCuotaP', default: '0.160000', format: :t_Importe
7
+ define_attribute :importe_p, xml_attribute: 'ImporteP', format: :t_ImporteMXN
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module Cfdi40
2
+ class TrasladosDR < Node
3
+ end
4
+ end
5
+
@@ -0,0 +1,16 @@
1
+ module Cfdi40
2
+ class TrasladosP < Node
3
+ def add_traslado_p_nodes
4
+ pago = parent_node.parent_node
5
+ pago.traslados_summary.each do |key, data|
6
+ traslado_p = TrasladoP.new
7
+ traslado_p.impuesto_p = key[0]
8
+ traslado_p.tipo_factor_p = key[1]
9
+ traslado_p.tasa_o_cuota_p = key[2]
10
+ traslado_p.base_p = data[:base]
11
+ traslado_p.importe_p = data[:importe]
12
+ add_child_node traslado_p
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cfdi40
4
- VERSION = "0.0.5"
4
+ VERSION = "0.0.6"
5
5
  end
data/lib/cfdi40.rb CHANGED
@@ -17,6 +17,17 @@ require_relative "cfdi40/traslados"
17
17
  require_relative "cfdi40/traslado"
18
18
  require_relative "cfdi40/complemento_concepto"
19
19
  require_relative "cfdi40/inst_educativas"
20
+ require_relative "cfdi40/complemento"
21
+ require_relative "cfdi40/pagos"
22
+ require_relative "cfdi40/pago"
23
+ require_relative "cfdi40/docto_relacionado"
24
+ require_relative "cfdi40/impuestos_dr"
25
+ require_relative "cfdi40/traslados_dr"
26
+ require_relative "cfdi40/traslado_dr"
27
+ require_relative "cfdi40/impuestos_p"
28
+ require_relative "cfdi40/traslados_p"
29
+ require_relative "cfdi40/traslado_p"
30
+ require_relative "cfdi40/totales.rb"
20
31
 
21
32
  # Leading module and entry point for all features and classes
22
33
  #
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.5
4
+ version: 0.0.6
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-04-08 00:00:00.000000000 Z
11
+ date: 2023-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -43,19 +43,30 @@ files:
43
43
  - Rakefile
44
44
  - cfdi40.gemspec
45
45
  - lib/cfdi40.rb
46
+ - lib/cfdi40/complemento.rb
46
47
  - lib/cfdi40/complemento_concepto.rb
47
48
  - lib/cfdi40/comprobante.rb
48
49
  - lib/cfdi40/concepto.rb
49
50
  - lib/cfdi40/conceptos.rb
51
+ - lib/cfdi40/docto_relacionado.rb
50
52
  - lib/cfdi40/emisor.rb
51
53
  - lib/cfdi40/impuestos.rb
54
+ - lib/cfdi40/impuestos_dr.rb
55
+ - lib/cfdi40/impuestos_p.rb
52
56
  - lib/cfdi40/inst_educativas.rb
53
57
  - lib/cfdi40/node.rb
58
+ - lib/cfdi40/pago.rb
59
+ - lib/cfdi40/pagos.rb
54
60
  - lib/cfdi40/receptor.rb
55
61
  - lib/cfdi40/sat_csd.rb
56
62
  - lib/cfdi40/schema_validator.rb
63
+ - lib/cfdi40/totales.rb
57
64
  - lib/cfdi40/traslado.rb
65
+ - lib/cfdi40/traslado_dr.rb
66
+ - lib/cfdi40/traslado_p.rb
58
67
  - lib/cfdi40/traslados.rb
68
+ - lib/cfdi40/traslados_dr.rb
69
+ - lib/cfdi40/traslados_p.rb
59
70
  - lib/cfdi40/version.rb
60
71
  - lib/xsd/Pagos20.xsd
61
72
  - lib/xsd/README.md