cfdi40 0.0.2 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README_es-MX.md +23 -1
- data/lib/cfdi40/complemento_concepto.rb +12 -0
- data/lib/cfdi40/comprobante.rb +21 -10
- data/lib/cfdi40/concepto.rb +38 -0
- data/lib/cfdi40/impuestos.rb +1 -0
- data/lib/cfdi40/inst_educativas.rb +17 -0
- data/lib/cfdi40/node.rb +37 -2
- data/lib/cfdi40/sat_csd.rb +11 -5
- data/lib/cfdi40/traslados.rb +1 -0
- data/lib/cfdi40/version.rb +1 -1
- data/lib/cfdi40.rb +2 -0
- data/lib/xsd/README.md +7 -3
- data/lib/xsd/cfdv40.xsd +1 -0
- data/lib/xsd/iedu.xsd +84 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c93f265a23f6c466d800ce90e2258525844b3f15451971b0140f8c2ee826d2c5
|
4
|
+
data.tar.gz: 1fcd506dfa5eefbffa1fec8ad3e98543cbc0045936859ca171b42caf46ff6649
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a13afec5754aeb24cf6168f66b23b658e79cb8d8cbf93c74a11bc592ae5913f77b3d6d5da45e19b69384c94a9221bb4f7b9897e0bc6672f7360b71a0538d759
|
7
|
+
data.tar.gz: 473a8ce2434b628e1fb61e8342cbdcdc1972fb00350a382e5b2b113c0d16018b804cd6d05438a2b26ddb54ba121491f9df94a75f976247eea682d7fcd7e461f2
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cfdi40 (0.0.
|
4
|
+
cfdi40 (0.0.4)
|
5
5
|
nokogiri (>= 1.10.10)
|
6
6
|
|
7
7
|
GEM
|
@@ -10,12 +10,12 @@ GEM
|
|
10
10
|
ast (2.4.2)
|
11
11
|
json (2.3.1)
|
12
12
|
minitest (5.15.0)
|
13
|
-
nokogiri (1.
|
13
|
+
nokogiri (1.14.2-x86_64-linux)
|
14
14
|
racc (~> 1.4)
|
15
15
|
parallel (1.20.1)
|
16
16
|
parser (3.1.2.1)
|
17
17
|
ast (~> 2.4.1)
|
18
|
-
racc (1.6.
|
18
|
+
racc (1.6.2)
|
19
19
|
rainbow (3.0.0)
|
20
20
|
rake (13.0.6)
|
21
21
|
regexp_parser (1.8.2)
|
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
|
data/lib/cfdi40/comprobante.rb
CHANGED
@@ -19,11 +19,11 @@ module Cfdi40
|
|
19
19
|
define_attribute :no_certificado, xml_attribute: 'NoCertificado'
|
20
20
|
define_attribute :certificado, xml_attribute: 'Certificado'
|
21
21
|
define_attribute :condiciones_de_pago, xml_attribute: 'CondicionesDePago'
|
22
|
-
define_attribute :subtotal, xml_attribute: 'SubTotal', format: :
|
23
|
-
define_attribute :descuento, xml_attribute: 'Descuento', format: :
|
22
|
+
define_attribute :subtotal, xml_attribute: 'SubTotal', format: :t_ImporteMXN
|
23
|
+
define_attribute :descuento, xml_attribute: 'Descuento', format: :t_ImporteMXN
|
24
24
|
define_attribute :moneda, xml_attribute: 'Moneda', default: 'MXN'
|
25
25
|
define_attribute :tipo_cambio, xml_attribute: 'TipoCambio'
|
26
|
-
define_attribute :total, xml_attribute: 'Total', format: :
|
26
|
+
define_attribute :total, xml_attribute: 'Total', format: :t_ImporteMXN
|
27
27
|
define_attribute :tipo_de_comprobante, xml_attribute: 'TipoDeComprobante', default: 'I'
|
28
28
|
define_attribute :exportacion, xml_attribute: 'Exportacion', default: '01'
|
29
29
|
define_attribute :metodo_pago, xml_attribute: 'MetodoPago'
|
@@ -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 :
|
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
|
-
@
|
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)
|
@@ -127,7 +133,8 @@ module Cfdi40
|
|
127
133
|
end
|
128
134
|
|
129
135
|
def original_content
|
130
|
-
|
136
|
+
xslt_path = File.join(File.dirname(__FILE__), '..', '..', 'lib/xslt/cadenaoriginal_local.xslt')
|
137
|
+
xslt = Nokogiri::XSLT(File.open(xslt_path))
|
131
138
|
transformed = xslt.transform(docxml)
|
132
139
|
# The ampersand (&) char must be used in original content
|
133
140
|
# even though the documentation indicates otherwise
|
@@ -154,15 +161,18 @@ module Cfdi40
|
|
154
161
|
def calculate!
|
155
162
|
@subtotal = @conceptos.children_nodes.map(&:importe).sum
|
156
163
|
@total = @conceptos.children_nodes.map(&:importe_neto).sum
|
157
|
-
|
164
|
+
add_traslados_summary_node
|
158
165
|
end
|
159
166
|
|
160
|
-
def
|
167
|
+
def add_traslados_summary_node
|
168
|
+
return if traslados_summary.empty?
|
169
|
+
|
161
170
|
impuestos.total_impuestos_trasladados = 0
|
162
171
|
traslados.children_nodes = []
|
163
172
|
traslados_summary.each do |key, value|
|
164
173
|
#TODO: Sumar los impuestos y agregarlos a los nodos globales de traslados
|
165
174
|
traslado = Traslado.new
|
175
|
+
traslado.parent_node = impuestos
|
166
176
|
traslado.impuesto, traslado.tasa_o_cuota, traslado.tipo_factor = key
|
167
177
|
traslado.base = value[:base]
|
168
178
|
traslado.importe = value[:importe]
|
@@ -196,6 +206,7 @@ module Cfdi40
|
|
196
206
|
return @impuestos if defined?(@impuestos)
|
197
207
|
|
198
208
|
@impuestos = Impuestos.new
|
209
|
+
@impuestos.parent_node = self
|
199
210
|
@children_nodes << @impuestos
|
200
211
|
@impuestos
|
201
212
|
end
|
@@ -216,10 +227,10 @@ module Cfdi40
|
|
216
227
|
end
|
217
228
|
|
218
229
|
def load_private_key
|
219
|
-
return unless defined?(@
|
230
|
+
return unless defined?(@key_data)
|
220
231
|
|
221
232
|
@sat_csd ||= SatCsd.new
|
222
|
-
@sat_csd.
|
233
|
+
@sat_csd.set_private_key(@key_data, (defined?(@key_pass) ? @key_pass : nil))
|
223
234
|
end
|
224
235
|
end
|
225
236
|
end
|
data/lib/cfdi40/concepto.rb
CHANGED
@@ -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
|
data/lib/cfdi40/impuestos.rb
CHANGED
@@ -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(
|
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
|
@@ -114,6 +147,8 @@ module Cfdi40
|
|
114
147
|
case self.class.formats[accessor]
|
115
148
|
when :t_Importe
|
116
149
|
sprintf("%0.6f", public_send(accessor).to_f)
|
150
|
+
when :t_ImporteMXN
|
151
|
+
sprintf("%0.2f", public_send(accessor).to_f)
|
117
152
|
else
|
118
153
|
public_send(accessor)
|
119
154
|
end
|
data/lib/cfdi40/sat_csd.rb
CHANGED
@@ -13,12 +13,12 @@ module Cfdi40
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def load_private_key(key_path, key_pass)
|
16
|
-
key_pem =
|
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
|
21
|
-
key_pem =
|
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
|
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
|
data/lib/cfdi40/traslados.rb
CHANGED
data/lib/cfdi40/version.rb
CHANGED
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
|
-
|
11
|
-
`
|
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,Ñ,&]{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.
|
4
|
+
version: 0.0.4
|
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-
|
11
|
+
date: 2023-03-20 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
|