cfdi40 0.4.4 → 0.4.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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/cfdi40/comprobante.rb +2 -7
- data/lib/cfdi40/concepto_rep.rb +192 -0
- data/lib/cfdi40/version.rb +1 -1
- data/lib/cfdi40.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e4048e33cf4c2c3afc08006ea141c96431a4d407db2c15c62f16af9ec443e261
|
|
4
|
+
data.tar.gz: 3d80d6b98b71753869048cf14eaa8fc8b7a6ead278b9d313ceebb1ea517cf701
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 266289fcbc480d8a0006b4847c72c18edd52deb6c343304a875cc1fc8335b90d5f16385fdeac70d94179e9efcdba9c4baef77efc1c200e107616f235f44ba2f1
|
|
7
|
+
data.tar.gz: 7ea20d0a5949da3af27660205edd3c25086d2f0afe3873031018b795fcb0f3da97bc57e6965b1eb4ebfbcc3cae02c09bd00a76e03a12505ccdde54e41669f302
|
data/Gemfile.lock
CHANGED
data/lib/cfdi40/comprobante.rb
CHANGED
|
@@ -314,17 +314,12 @@ module Cfdi40
|
|
|
314
314
|
private
|
|
315
315
|
|
|
316
316
|
def add_node_concepto_actividad_pago
|
|
317
|
-
return if
|
|
317
|
+
return if @conceptos.children_nodes.size > 0
|
|
318
318
|
|
|
319
319
|
@receptor.uso_cfdi = "CP01"
|
|
320
|
-
@concepto_actividad =
|
|
321
|
-
@concepto_actividad.clave_prod_serv = "84111506"
|
|
322
|
-
@concepto_actividad.cantidad = 1
|
|
323
|
-
@concepto_actividad.clave_unidad = "ACT"
|
|
324
|
-
@concepto_actividad.descripcion = "Pago"
|
|
320
|
+
@concepto_actividad = ConceptoRep.new
|
|
325
321
|
@concepto_actividad.precio_bruto = 0
|
|
326
322
|
@concepto_actividad.tasa_iva = nil
|
|
327
|
-
@concepto_actividad.objeto_impuestos = "01"
|
|
328
323
|
@concepto_actividad.calculate!
|
|
329
324
|
@conceptos.add_child_node @concepto_actividad
|
|
330
325
|
calculate!
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Represents node 'concepto'
|
|
4
|
+
#
|
|
5
|
+
# * Attribute +Importe+ represente gross amount. Gross amount is before taxes and the result of multiply
|
|
6
|
+
# +ValorUnitario+ by +Cantidad+
|
|
7
|
+
#
|
|
8
|
+
module Cfdi40
|
|
9
|
+
class ConceptoRep < Node
|
|
10
|
+
define_element_name 'Concepto'
|
|
11
|
+
define_attribute :clave_prod_serv, xml_attribute: "ClaveProdServ", default: "84111506"
|
|
12
|
+
define_attribute :no_identificacion, xml_attribute: "NoIdentificacion"
|
|
13
|
+
define_attribute :cantidad, xml_attribute: "Cantidad", default: 1
|
|
14
|
+
define_attribute :clave_unidad, xml_attribute: "ClaveUnidad", default: "ACT"
|
|
15
|
+
define_attribute :unidad, xml_attribute: "Unidad"
|
|
16
|
+
define_attribute :descripcion, xml_attribute: "Descripcion", no_writer: true, default: "Pago"
|
|
17
|
+
define_attribute :valor_unitario, xml_attribute: "ValorUnitario", format: :t_Importe
|
|
18
|
+
define_attribute :importe, xml_attribute: "Importe", format: :t_Importe
|
|
19
|
+
define_attribute :descuento, xml_attribute: "Descuento", format: :t_Importe
|
|
20
|
+
define_attribute :objeto_impuestos, xml_attribute: "ObjetoImp", default: "01"
|
|
21
|
+
|
|
22
|
+
attr_accessor :tasa_iva, :tasa_ieps, :precio_neto, :precio_bruto
|
|
23
|
+
attr_reader :iva, :ieps, :base_iva, :importe_neto, :importe_bruto
|
|
24
|
+
|
|
25
|
+
# accesors for instEducativas
|
|
26
|
+
attr_accessor :iedu_nombre_alumno, :iedu_curp, :iedu_nivel_educativo, :iedu_aut_rvoe, :iedu_rfc_pago
|
|
27
|
+
|
|
28
|
+
def initialize
|
|
29
|
+
@tasa_iva = 0.16
|
|
30
|
+
@tasa_ieps = nil
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Ver Comprobante#add_concepto
|
|
35
|
+
def update(attributes = {})
|
|
36
|
+
attributes.each do |key, value|
|
|
37
|
+
method_name = "#{key}=".to_sym
|
|
38
|
+
raise Error, ":#{key} no se puede asignar al concepto" unless respond_to?(method_name)
|
|
39
|
+
|
|
40
|
+
public_send(method_name, value)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
calculate!
|
|
44
|
+
parent_node.parent_node.calculate!
|
|
45
|
+
true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Calculate taxes, amounts from gross price
|
|
49
|
+
# or net price
|
|
50
|
+
def calculate!
|
|
51
|
+
set_defaults
|
|
52
|
+
assign_objeto_imp
|
|
53
|
+
# TODO: accept discount
|
|
54
|
+
if defined?(@precio_neto) && !@precio_neto.nil?
|
|
55
|
+
calculate_from_net_price
|
|
56
|
+
elsif defined?(@precio_bruto) && !@precio_bruto.nil?
|
|
57
|
+
calculate_from_gross_price
|
|
58
|
+
elsif !valor_unitario.nil?
|
|
59
|
+
@precio_bruto = valor_unitario
|
|
60
|
+
calculate_from_gross_price
|
|
61
|
+
end
|
|
62
|
+
add_info_to_traslado_iva
|
|
63
|
+
# TODO: add_info_to_traslado_ieps if @ieps > 0
|
|
64
|
+
add_inst_educativas
|
|
65
|
+
true
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def objeto_impuestos?
|
|
69
|
+
objeto_impuestos == "02"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def traslado_nodes
|
|
73
|
+
return [] if impuestos_node.nil?
|
|
74
|
+
|
|
75
|
+
impuestos_node.traslado_nodes
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def traslado_iva_node
|
|
79
|
+
return nil unless impuestos_node.is_a?(ConceptoImpuestos)
|
|
80
|
+
|
|
81
|
+
impuestos_node.traslado_iva
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def load_traslado_iva(ng_node)
|
|
85
|
+
traslado_iva_node.load_from_ng_node(ng_node)
|
|
86
|
+
calculate_from_gross_price
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def descripcion=(desc)
|
|
90
|
+
@descripcion = desc.to_s[0..999]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def calculate_from_net_price
|
|
96
|
+
set_defaults
|
|
97
|
+
@precio_neto = @precio_neto.round(6)
|
|
98
|
+
@precio_bruto = (@precio_neto / ((1 + tasa_iva.to_f) * (1 + tasa_ieps.to_f)))
|
|
99
|
+
calculate_taxes
|
|
100
|
+
|
|
101
|
+
@precio_bruto = (((@precio_neto * cantidad.to_f) - @iva - @ieps) / cantidad.to_f.round(6)).round(6)
|
|
102
|
+
update_xml_attributes
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def calculate_from_gross_price
|
|
106
|
+
@precio_bruto = @precio_bruto.round(6)
|
|
107
|
+
calculate_taxes
|
|
108
|
+
# May be can not be rounded with 2 decimals.
|
|
109
|
+
# Example gross_price = 1.99512
|
|
110
|
+
@precio_neto = (@importe_neto / cantidad.to_f).round(6)
|
|
111
|
+
update_xml_attributes
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def calculate_taxes
|
|
115
|
+
@base_ieps = (@precio_bruto * cantidad.to_f).round(6)
|
|
116
|
+
@ieps = (@base_ieps * tasa_ieps.to_f).round(6)
|
|
117
|
+
@base_iva = (@base_ieps + @ieps).round(6)
|
|
118
|
+
@iva = (@base_iva * tasa_iva.to_f).round(6)
|
|
119
|
+
@importe_bruto = @base_ieps
|
|
120
|
+
@importe_neto = (@base_iva + @iva).round(2)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def update_xml_attributes
|
|
124
|
+
self.importe = @importe_bruto
|
|
125
|
+
self.valor_unitario = @precio_bruto
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def add_info_to_traslado_iva
|
|
129
|
+
return if @tasa_iva.nil?
|
|
130
|
+
|
|
131
|
+
traslado_iva_node.importe = @iva
|
|
132
|
+
traslado_iva_node.base = @base_iva
|
|
133
|
+
traslado_iva_node.tasa_o_cuota = @tasa_iva
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def assign_objeto_imp
|
|
137
|
+
# 01 No objeto de impuesto.
|
|
138
|
+
# 02 Sí objeto de impuesto.
|
|
139
|
+
# 03 Sí objeto del impuesto y no obligado al desglose.
|
|
140
|
+
|
|
141
|
+
return if objeto_impuestos == "03"
|
|
142
|
+
|
|
143
|
+
self.objeto_impuestos = (!@tasa_iva.nil? || !@tasa_ieps.nil? ? "02" : "01")
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def impuestos_node
|
|
147
|
+
return @impuestos_node if defined?(@impuestos_node)
|
|
148
|
+
return nil unless objeto_impuestos?
|
|
149
|
+
|
|
150
|
+
@impuestos_node = children_nodes.select { |child| child.is_a?(ConceptoImpuestos) }.first
|
|
151
|
+
return if @impuestos_node
|
|
152
|
+
|
|
153
|
+
@impuestos_node = ConceptoImpuestos.new
|
|
154
|
+
@impuestos_node.parent_node = self
|
|
155
|
+
children_nodes << @impuestos_node
|
|
156
|
+
@impuestos_node
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def add_inst_educativas
|
|
160
|
+
return unless inst_educativas_present?
|
|
161
|
+
|
|
162
|
+
inst_educativas_node.nombre_alumno = iedu_nombre_alumno
|
|
163
|
+
inst_educativas_node.curp = iedu_curp
|
|
164
|
+
inst_educativas_node.nivel_educativo = iedu_nivel_educativo
|
|
165
|
+
inst_educativas_node.aut_rvoe = iedu_aut_rvoe
|
|
166
|
+
inst_educativas_node.rfc_pago = iedu_rfc_pago
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def inst_educativas_present?
|
|
170
|
+
return false if iedu_nombre_alumno.nil?
|
|
171
|
+
return false if iedu_nivel_educativo.nil?
|
|
172
|
+
return false if iedu_aut_rvoe.nil?
|
|
173
|
+
|
|
174
|
+
true
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def concepto_complemento_node
|
|
178
|
+
return @complemento_concepto_node if defined?(@complemento_concepto_node)
|
|
179
|
+
|
|
180
|
+
@complemento_concepto_node = ComplementoConcepto.new
|
|
181
|
+
@complemento_concepto_node.parent_node = self
|
|
182
|
+
children_nodes << @complemento_concepto_node
|
|
183
|
+
@complemento_concepto_node
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def inst_educativas_node
|
|
187
|
+
return nil unless concepto_complemento_node.is_a?(ComplementoConcepto)
|
|
188
|
+
|
|
189
|
+
concepto_complemento_node.inst_educativas_node
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
data/lib/cfdi40/version.rb
CHANGED
data/lib/cfdi40.rb
CHANGED
|
@@ -22,6 +22,7 @@ require_relative "cfdi40/traslado"
|
|
|
22
22
|
require_relative "cfdi40/complemento_concepto"
|
|
23
23
|
require_relative "cfdi40/inst_educativas"
|
|
24
24
|
require_relative "cfdi40/complemento"
|
|
25
|
+
require_relative "cfdi40/concepto_rep"
|
|
25
26
|
require_relative "cfdi40/pagos"
|
|
26
27
|
require_relative "cfdi40/pago"
|
|
27
28
|
require_relative "cfdi40/docto_relacionado"
|
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.4.
|
|
4
|
+
version: 0.4.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:
|
|
11
|
+
date: 2026-03-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: nokogiri
|
|
@@ -48,6 +48,7 @@ files:
|
|
|
48
48
|
- lib/cfdi40/comprobante.rb
|
|
49
49
|
- lib/cfdi40/concepto.rb
|
|
50
50
|
- lib/cfdi40/concepto_impuestos.rb
|
|
51
|
+
- lib/cfdi40/concepto_rep.rb
|
|
51
52
|
- lib/cfdi40/conceptos.rb
|
|
52
53
|
- lib/cfdi40/cp_totales.rb
|
|
53
54
|
- lib/cfdi40/docto_relacionado.rb
|