Skip to content
This repository has been archived by the owner on Jul 22, 2020. It is now read-only.

Refactor variables de clase #10

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 40 additions & 26 deletions lib/comprobante.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@ module CFDI
# La clase principal para crear Comprobantes
class Comprobante

# los datos para la cadena original en el órden correcto
# @private
@@datosCadena = [:version, :fecha, :tipoDeComprobante, :formaDePago, :condicionesDePago, :subTotal, :TipoCambio, :moneda, :total, :metodoDePago, :lugarExpedicion, :NumCtaPago]
# Todos los datos del comprobante
# @private
@@data = @@datosCadena+[:emisor, :receptor, :conceptos, :serie, :folio, :sello, :noCertificado, :certificado, :conceptos, :complemento, :cancelada, :impuestos]
attr_accessor(*@@data)

@addenda = nil

@@options = {
Expand All @@ -33,7 +25,7 @@ class Comprobante
#
# @return [Hash]
#
def self.configure (options)
def self.configure(options)
@@options = Comprobante.rmerge @@options, options
@@options
end
Expand All @@ -56,7 +48,8 @@ def self.configure (options)
# @see [Comprobante@@options] Opciones
#
# @return {CFDI::Comprobante}
def initialize (data={}, options={})
def initialize(data={}, options={})
add_accessors_as_inherited_module!
#hack porque dup se caga con instance variables
opts = Marshal::load(Marshal.dump(@@options))
data = opts[:defaults].merge data
Expand All @@ -68,8 +61,7 @@ def initialize (data={}, options={})
end
end


def addenda= addenda
def addenda=(addenda)
addenda = Addenda.new addenda unless addenda.is_a? Addenda
@addenda = addenda
end
Expand Down Expand Up @@ -101,7 +93,7 @@ def total
# @param emisor [Hash, CFDI::Entidad] Los datos de un emisor
#
# @return [CFDI::Entidad] Una entidad
def emisor= emisor
def emisor=(emisor)
emisor = Entidad.new emisor unless emisor.is_a? Entidad
@emisor = emisor;
end
Expand All @@ -111,7 +103,7 @@ def emisor= emisor
# @param receptor [Hash, CFDI::Entidad] Los datos de un receptor
#
# @return [CFDI::Entidad] Una entidad
def receptor= receptor
def receptor=(receptor)
receptor = Entidad.new receptor unless receptor.is_a? Entidad
@receptor = receptor;
receptor
Expand All @@ -123,27 +115,30 @@ def receptor= receptor
# En caso de darle un Hash o un {CFDI::Concepto}, agrega este a los conceptos, de otro modo, sobreescribe los conceptos pre-existentes
#
# @return [Array] Los conceptos de este comprobante
def conceptos= conceptos
def conceptos=(conceptos)
if conceptos.is_a? Array
conceptos.map! do |concepto|
concepto = Concepto.new concepto unless concepto.is_a? Concepto
end
elsif conceptos.is_a? Hash
concepto = conceptos
conceptos = @conceptos
conceptos << Concepto.new(concepto)
elsif conceptos.is_a? Concepto
conceptos << conceptos
concepto = conceptos
conceptos = @conceptos
conceptos << concepto
end

@conceptos = conceptos
conceptos
end


# Asigna un complemento al comprobante
# @param complemento [Hash, CFDI::Complemento] El complemento a agregar
#
# @return [CFDI::Complemento]
def complemento= complemento
def complemento=(complemento)
complemento = Complemento.new complemento unless complemento.is_a? Complemento
@complemento = complemento
complemento
Expand All @@ -154,7 +149,7 @@ def complemento= complemento
# @param fecha [Time, String] La fecha y hora (YYYY-MM-DDTHH:mm:SS) de la emisión
#
# @return [String] la fecha en formato '%FT%R:%S'
def fecha= fecha
def fecha=(fecha)
fecha = fecha.strftime('%FT%R:%S') unless fecha.is_a? String
@fecha = fecha
end
Expand Down Expand Up @@ -282,7 +277,7 @@ def to_xml
# @return [Hash] El comprobante como Hash
def to_h
hash = {}
@@data.each do |key|
atributos.each do |key|
data = deep_to_h send(key)
hash[key] = data
end
Expand All @@ -297,7 +292,7 @@ def to_h
def cadena_original
params = []

@@datosCadena.each {|key| params.push send(key) }
datos_cadena.each {|key| params.push send(key) }
params += @emisor.cadena_original
params << @regimen
params += @receptor.cadena_original
Expand All @@ -322,15 +317,15 @@ def cadena_original
elem
end

return "||#{params.join '|'}||"
"||#{params.join '|'}||"
end


# Revisa que el timbre de un comprobante sea válido
# @param [String] El certificado del PAC
#
# @return [Boolean] El resultado de la validación
def timbre_valido? cert=nil
def timbre_valido?(cert=nil)
return false unless complemento && complemento.selloSAT

unless cert
Expand Down Expand Up @@ -361,9 +356,9 @@ def self.rmerge defaults, other_hash
result
end

private
def deep_to_h value
private

def deep_to_h(value)
if value.is_a? ElementoComprobante
original = value.to_h
value = {}
Expand All @@ -387,5 +382,24 @@ def deep_to_h value
value
end

def add_accessors_as_inherited_module!
attrs = atributos

accessors_module = Module.new do
attr_accessor *attrs
end

Comprobante.class_eval do
include accessors_module
end
end

def datos_cadena
[:version, :fecha, :tipoDeComprobante, :formaDePago, :condicionesDePago, :subTotal, :TipoCambio, :moneda, :total, :metodoDePago, :lugarExpedicion, :NumCtaPago]
end

def atributos
datos_cadena + [:emisor, :receptor, :conceptos, :serie, :folio, :sello, :noCertificado, :certificado, :conceptos, :complemento, :cancelada, :impuestos]
end
end
end
end
10 changes: 5 additions & 5 deletions lib/concepto.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ class Concepto < ElementoComprobante

# @private
def cadena_original
return [
@cantidad.to_i,
[
@cantidad,
@unidad,
@noIdentificacion,
@descripcion,
self.valorUnitario,
self.importe
valorUnitario,
importe
]
end

Expand Down Expand Up @@ -58,4 +58,4 @@ def cantidad= qty

end

end
end
11 changes: 3 additions & 8 deletions lib/entidad.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,8 @@ class Entidad < ElementoComprobante
# @private
def cadena_original
expedido = @expedidoEn ? @expedidoEn.cadena_original : nil
return [
@rfc,
@nombre,
*@domicilioFiscal.cadena_original,
expedido,
@regimenFiscal
].flatten
domicilio = @domicilioFiscal ? @domicilioFiscal.cadena_original : nil
[@rfc, @nombre, *domicilio, expedido, @regimenFiscal].flatten
end


Expand Down Expand Up @@ -78,4 +73,4 @@ class Domicilio < ElementoComprobante

end

end
end
100 changes: 98 additions & 2 deletions test/comprobante_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
:cancelada=>nil,
:impuestos=>[]
}
puts comprobante.to_h
expect(comprobante.to_h).to be_eql(defaults)
end

Expand All @@ -40,6 +39,103 @@
expect(comprobante.version).to eq '2.0'
end

context 'conceptos' do
it "empieza con una lista vacía e conceptos" do
comprobante = CFDI::Comprobante.new
expect(comprobante.conceptos).to be_empty
end

it "acepta un arreglo de hashes y agrega un concepto por cada hash a la lista de conceptos" do
conceptos = [
{cantidad: 1, unidad: 'Pieza', noIdentificacion: nil, descripcion: 'Un producto', valorUnitario: 432.23, importe: 432.23},
{cantidad: 1, unidad: 'Pieza', noIdentificacion: nil, descripcion: 'Otro producto', valorUnitario: 234.43, importe: 324.43}
]
comprobante = CFDI::Comprobante.new
comprobante.conceptos = conceptos
expect(comprobante.conceptos.size).to eq 2
expect(comprobante.conceptos[0]).to be_a CFDI::Concepto
expect(comprobante.conceptos[1]).to be_a CFDI::Concepto
end

it "acepta un arreglo de objetos Concepto y los agrega la lista de conceptos" do
conceptos = [
CFDI::Concepto.new(cantidad: 1, unidad: 'Pieza', noIdentificacion: nil, descripcion: 'Un producto', valorUnitario: 432.23, importe: 432.23),
CFDI::Concepto.new(cantidad: 1, unidad: 'Pieza', noIdentificacion: nil, descripcion: 'Otro producto', valorUnitario: 234.43, importe: 324.43)
]
comprobante = CFDI::Comprobante.new
comprobante.conceptos = conceptos
expect(comprobante.conceptos.size).to eq 2
expect(comprobante.conceptos).to match_array conceptos
end

it "acepta un hash, construye un objeto Concepto con esa inforamación y lo agrega la lista de conceptos" do
comprobante = CFDI::Comprobante.new
comprobante.conceptos = {cantidad: 1, unidad: 'Pieza', noIdentificacion: nil, descripcion: 'Un producto', valorUnitario: 432.23, importe: 432.23}
expect(comprobante.conceptos.size).to eq 1
expect(comprobante.conceptos.first).to be_a CFDI::Concepto
end

it "acepta un objeto Concepto y lo agrega a la lista de conceptos" do
concepto = CFDI::Concepto.new(cantidad: 1, unidad: 'Pieza', noIdentificacion: nil, descripcion: 'Un producto', valorUnitario: 432.23, importe: 432.23)
comprobante = CFDI::Comprobante.new
comprobante.conceptos = concepto
expect(comprobante.conceptos).to include(concepto)
end
end # context conceptos

describe '#cadena_original' do
it "genera la cadena con domicilio fiscal" do
comprobante = CFDI::Comprobante.new
comprobante.version = '2.0'
comprobante.fecha = Date.today
comprobante.tipoDeComprobante = 'ingreso'
comprobante.formaDePago = 'contado'
comprobante.condicionesDePago = 'sd'
comprobante.subTotal = 100.0
comprobante.TipoCambio = 1
comprobante.moneda = 'mxn'
comprobante.total = 116.00
comprobante.metodoDePago = 'efectivo'
comprobante.lugarExpedicion = 'una ciudad'
comprobante.NumCtaPago = '1234'
comprobante.emisor = CFDI::Entidad.new rfc: 'AAAA111111AAA', domicilioFiscal: { calle: "Calle emisor", noExterior: "123", colonia: "Colonia receptor", localidad: "localidad receptor", municipio: "Municipio receptor", estado: "Estado receptor", pais: "Pais receptor", codigoPostal: "12345"}
comprobante.receptor = CFDI::Entidad.new rfc: 'AAAA111111BBB', domicilioFiscal: { calle: "Calle receptor", noExterior: "123", colonia: "Colonia receptor", localidad: "localidad receptor", municipio: "Municipio receptor", estado: "Estado receptor", pais: "Pais receptor", codigoPostal: "12345" }
comprobante.conceptos = [
{cantidad: 1, unidad: 'Pieza', noIdentificacion: nil, descripcion: 'Un producto', valorUnitario: 432.23, importe: 432.23},
{cantidad: 1, unidad: 'Pieza', noIdentificacion: nil, descripcion: 'Otro producto', valorUnitario: 234.43, importe: 324.43}
]
comprobante.impuestos = [ { impuesto: "IVA" } ]

expect(comprobante.cadena_original).to eq "||2.0|2015-09-09T00:00:00|ingreso|contado|sd|666.66|1|mxn|773.33|efectivo|una ciudad|1234|AAAA111111AAA|Calle emisor|123|Colonia receptor|localidad receptor|Municipio receptor|Estado receptor|Pais receptor|12345|AAAA111111BBB|Calle receptor|123|Colonia receptor|localidad receptor|Municipio receptor|Estado receptor|Pais receptor|12345|1|Pieza|Un producto|432.23|432.23|1|Pieza|Otro producto|234.43|234.43|IVA|16|106.67|106.67||"
end

it "genera la cadena sin domicilio fiscal si éste no existe" do
comprobante = CFDI::Comprobante.new
comprobante.version = '2.0'
comprobante.fecha = Date.today
comprobante.tipoDeComprobante = 'ingreso'
comprobante.formaDePago = 'contado'
comprobante.condicionesDePago = 'sd'
comprobante.subTotal = 100.0
comprobante.TipoCambio = 1
comprobante.moneda = 'mxn'
comprobante.total = 116.00
comprobante.metodoDePago = 'efectivo'
comprobante.lugarExpedicion = 'una ciudad'
comprobante.NumCtaPago = '1234'
comprobante.emisor = CFDI::Entidad.new rfc: 'AAAA111111AAA'
comprobante.receptor = CFDI::Entidad.new rfc: 'AAAA111111BBB'
comprobante.conceptos = [
{cantidad: 1, unidad: 'Pieza', noIdentificacion: nil, descripcion: 'Un producto', valorUnitario: 432.23, importe: 432.23},
{cantidad: 1, unidad: 'Pieza', noIdentificacion: nil, descripcion: 'Otro producto', valorUnitario: 234.43, importe: 324.43}
]
comprobante.impuestos = [ { impuesto: "IVA" } ]

expect(comprobante.cadena_original).to eq "||2.0|2015-09-09T00:00:00|ingreso|contado|sd|666.66|1|mxn|773.33|efectivo|una ciudad|1234|AAAA111111AAA|AAAA111111BBB|1|Pieza|Un producto|432.23|432.23|1|Pieza|Otro producto|234.43|234.43|IVA|16|106.67|106.67||"
end

end # describe #cadena_original

it "debe de generar un comprobante desde XML" do
comprobante = CFDI.from_xml(File.read('./examples/data/cfdi.xml'))
returns = {:version=>"3.2", :fecha=>"2013-10-15T01:33:32", :tipoDeComprobante=>"ingreso", :formaDePago=>"PAGO EN UNA SOLA EXHIBICION", :condicionesDePago=>"Sera marcada como pagada en cuanto el receptor haya cubierto el pago.", :subTotal=>11000.0, :TipoCambio=>1, :moneda=>"pesos", :total=>12760.0, :metodoDePago=>"Transferencia Bancaria", :lugarExpedicion=>"Nutopia, Nutopia", :NumCtaPago=>nil, :emisor=>{:rfc=>"XAXX010101000", :nombre=>"Me cago en sus estándares S.A. de C.V.", :domicilioFiscal=>{:calle=>"Calle Feliz", :noExterior=>"42", :noInterior=>"314", :colonia=>"Centro", :localidad=>"No se que sea esto, pero va", :referencia=>"Sin Referencia", :municipio=>"Nutopía", :estado=>"Nutopía", :pais=>"Nutopía", :codigoPostal=>"31415"}, :expedidoEn=>{:calle=>"Calle Feliz", :noExterior=>"42", :noInterior=>nil, :colonia=>"Centro", :localidad=>"No se que sea esto, pero va", :referencia=>"Sin Referencia", :municipio=>"Nutopía", :estado=>"Nutopía", :pais=>"Nutopía", :codigoPostal=>"31415"}, :regimenFiscal=>"Pruebas Fiscales"}, :receptor=>{:rfc=>"XAXX010101000", :nombre=>"El SAT apesta S. de R.L.", :domicilioFiscal=>{:calle=>nil, :noExterior=>nil, :noInterior=>nil, :colonia=>nil, :localidad=>nil, :referencia=>"Sin Referencia", :municipio=>nil, :estado=>"Nutopía", :pais=>"Nutopía", :codigoPostal=>nil}, :expedidoEn=>nil, :regimenFiscal=>nil}, :conceptos=>[{:cantidad=>2, :unidad=>"Kilos", :noIdentificacion=>"KDV", :descripcion=>"Verga Ción", :valorUnitario=>5500.0, :importe=>11000.0}], :serie=>nil, :folio=>"1", :sello=>"igFu7Q9Z98n6xFSLMv7a2y8ZlJCO+pgTX3xDAUt5xSpX3dHOKXkTHBAf4P/oHHDm3xkYkaNBfPEzpVFDrRVjL2rvkR5T9rsFqb4cl6DOo4RrRIpSR9vojLp7mFWiON9H6OFPi2b9PVAnyIx1Skb5iGIAmSQIhVYyt2DSauObY2c=", :noCertificado=>"20001000000200000293", :certificado=>"MIIE2jCCA8KgAwIBAgIUMjAwMDEwMDAwMDAyMDAwMDAyOTMwDQYJKoZIhvcNAQEFBQAwggFcMRowGAYDVQQDDBFBLkMuIDIgZGUgcHJ1ZWJhczEvMC0GA1UECgwmU2VydmljaW8gZGUgQWRtaW5pc3RyYWNpw7NuIFRyaWJ1dGFyaWExODA2BgNVBAsML0FkbWluaXN0cmFjacOzbiBkZSBTZWd1cmlkYWQgZGUgbGEgSW5mb3JtYWNpw7NuMSkwJwYJKoZIhvcNAQkBFhphc2lzbmV0QHBydWViYXMuc2F0LmdvYi5teDEmMCQGA1UECQwdQXYuIEhpZGFsZ28gNzcsIENvbC4gR3VlcnJlcm8xDjAMBgNVBBEMBTA2MzAwMQswCQYDVQQGEwJNWDEZMBcGA1UECAwQRGlzdHJpdG8gRmVkZXJhbDESMBAGA1UEBwwJQ295b2Fjw6FuMTQwMgYJKoZIhvcNAQkCDCVSZXNwb25zYWJsZTogQXJhY2VsaSBHYW5kYXJhIEJhdXRpc3RhMB4XDTEyMTAyNjE5MjI0M1oXDTE2MTAyNjE5MjI0M1owggFTMUkwRwYDVQQDE0BBU09DSUFDSU9OIERFIEFHUklDVUxUT1JFUyBERUwgRElTVFJJVE8gREUgUklFR08gMDA0IERPTiBNQVJUSU4gMWEwXwYDVQQpE1hBU09DSUFDSU9OIERFIEFHUklDVUxUT1JFUyBERUwgRElTVFJJVE8gREUgUklFR08gMDA0IERPTiBNQVJUSU4gQ09BSFVJTEEgWSBOVUVWTyBMRU9OIEFDMUkwRwYDVQQKE0BBU09DSUFDSU9OIERFIEFHUklDVUxUT1JFUyBERUwgRElTVFJJVE8gREUgUklFR08gMDA0IERPTiBNQVJUSU4gMSUwIwYDVQQtExxBQUQ5OTA4MTRCUDcgLyBIRUdUNzYxMDAzNFMyMR4wHAYDVQQFExUgLyBIRUdUNzYxMDAzTURGUk5OMDkxETAPBgNVBAsTCFNlcnZpZG9yMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlrI9loozd+UcW7YHtqJimQjzX9wHIUcc1KZyBBB8/5fZsgZ/smWS4Sd6HnPs9GSTtnTmM4bEgx28N3ulUshaaBEtZo3tsjwkBV/yVQ3SRyMDkqBA2NEjbcum+e/MdCMHiPI1eSGHEpdESt55a0S6N24PW732Xm3ZbGgOp1tht1wIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIGwDANBgkqhkiG9w0BAQUFAAOCAQEAuoPXe+BBIrmJn+IGeI+m97OlP3RC4Ct3amjGmZICbvhI9BTBLCL/PzQjjWBwU0MG8uK6e/gcB9f+klPiXhQTeI1YKzFtWrzctpNEJYo0KXMgvDiputKphQ324dP0nzkKUfXlRIzScJJCSgRw9ZifKWN0D9qTdkNkjk83ToPgwnldg5lzU62woXo4AKbcuabAYOVoC7owM5bfNuWJe566UzD6i5PFY15jYMzi1+ICriDItCv3S+JdqyrBrX3RloZhdyXqs2Htxfw4b1OcYboPCu4+9qM3OV02wyGKlGQMhfrXNwYyj8huxS1pHghEROM2Zs0paZUOy+6ajM+Xh0LX2w==", :complemento=>nil, :cancelada=>nil, :impuestos=>[{:impuesto=>"IVA"}]}
Expand All @@ -62,4 +158,4 @@
expect(comprobante.timbre_valido? cert).to be false
end

end
end