From c68ba9506edd026f98bb956ffac9cdb503a92263 Mon Sep 17 00:00:00 2001 From: Azarel Doroteo Pacheco Date: Sat, 3 Dec 2016 13:20:36 -0600 Subject: [PATCH 01/56] Remove importe_gravado and importe_excento in deduccion. Remove descuento in incapacidad. Add importe_monetario to deduccion. Add importe. --- lib/fm_layout/encabezado.rb | 32 +++--- lib/fm_layout/nomina/deduccion.rb | 14 ++- lib/fm_layout/nomina/incapacidad.rb | 11 +- spec/fm_layout_nomina_spec.rb | 151 +++++++++++++++------------- 4 files changed, 109 insertions(+), 99 deletions(-) diff --git a/lib/fm_layout/encabezado.rb b/lib/fm_layout/encabezado.rb index a3f68e3..6078a8d 100644 --- a/lib/fm_layout/encabezado.rb +++ b/lib/fm_layout/encabezado.rb @@ -11,22 +11,22 @@ def initialize def self.campos_vs_metodos { - 'serie' => 'serie', - 'fecha' => 'fecha', - 'folio' => 'folio', - 'tipoDeComprobante' => 'tipo_de_comprobante', - 'formaDePago' => 'forma_de_pago', - 'metodoDePago' => 'metodo_de_pago', - 'condicionesDePago' => 'condiciones_de_pago', - 'NumCtaPago' => 'numero_de_cuenta_de_pago', - 'subTotal' => 'subtotal', - 'descuento' => 'descuento', - 'motivoDescuento' => 'motivo_de_descuento', - 'total' => 'total', - 'Moneda' => 'moneda', - 'TipoCambio' => 'tipo_de_cambio', - 'noCertificado' => 'numero_de_certificado', - 'LugarExpedicion' => 'lugar_de_expedicion' + 'serie' => 'serie', + 'fecha' => 'fecha', + 'folio' => 'folio', + 'tipoDeComprobante' => 'tipo_de_comprobante', + 'formaDePago' => 'forma_de_pago', + 'metodoDePago' => 'metodo_de_pago', + 'condicionesDePago' => 'condiciones_de_pago', + 'NumCtaPago' => 'numero_de_cuenta_de_pago', + 'subTotal' => 'subtotal', + 'descuento' => 'descuento', + 'motivoDescuento' => 'motivo_de_descuento', + 'total' => 'total', + 'Moneda' => 'moneda', + 'TipoCambio' => 'tipo_de_cambio', + 'noCertificado' => 'numero_de_certificado', + 'LugarExpedicion' => 'lugar_de_expedicion' } end diff --git a/lib/fm_layout/nomina/deduccion.rb b/lib/fm_layout/nomina/deduccion.rb index cdc60ad..300c382 100644 --- a/lib/fm_layout/nomina/deduccion.rb +++ b/lib/fm_layout/nomina/deduccion.rb @@ -5,18 +5,16 @@ class Deduccion include ::FmLayout::FmSeccion def initialize - @titulo= 'Deduccion' - @datos= {} - #valores_iniciales + @titulo = 'Deduccion' + @datos = {} end def self.campos_vs_metodos { - 'TipoDeduccion' => 'tipo', - 'Clave' => 'clave', - 'Concepto' => 'concepto', - 'ImporteGravado' => 'importe_gravado', - 'ImporteExento' => 'importe_exento', + 'TipoDeduccion' => 'tipo', + 'Clave' => 'clave', + 'Concepto' => 'concepto', + 'Importe' => 'importe', } end diff --git a/lib/fm_layout/nomina/incapacidad.rb b/lib/fm_layout/nomina/incapacidad.rb index 0030204..7a4cc9b 100644 --- a/lib/fm_layout/nomina/incapacidad.rb +++ b/lib/fm_layout/nomina/incapacidad.rb @@ -5,16 +5,15 @@ class Incapacidad include ::FmLayout::FmSeccion def initialize - @titulo= 'Incapacidad' - @datos= {} - #valores_iniciales + @titulo = 'Incapacidad' + @datos = {} end def self.campos_vs_metodos { - 'DiasIncapacidad' => 'dias', - 'TipoIncapacidad' => 'tipo', - 'Descuento' => 'descuento', + 'DiasIncapacidad' => 'dias', + 'TipoIncapacidad' => 'tipo', + 'ImporteMonetario' => 'importe_monetario', } end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 3afae33..3fb3e45 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -7,7 +7,7 @@ let(:hoy){ Date.today } let(:inicio_quincena){ Date.today - 15 } let(:fin_quincena){ Date.today } - let(:inicio_relacion_laboral){ Date.today - 48*7 } + let(:inicio_relacion_laboral){ Date.today - 48 * 7 } let(:prueba) do # DSL FmLayout.define_layout do |f| @@ -19,21 +19,25 @@ e.motivo_de_descuento 'Deducciones de nómina' e.lugar_de_expedicion 'Nuevo León, México' end + f.datos_adicionales do |d| d.tipo_de_documento 'RECIBO DE NOMINA' d.id_de_nomina 'N-1' d.id_de_trabajador '' d.leyenda 'Leyenda al pie del recibo' end + f.emisor do |e| e.rfc 'ESI920427886' e.nombre 'FACTURACION MODERNA S.A de C.V.' e.regimen_fiscal 'REGIMEN GENERAL DE LEY PERSONAS MORALES' end + f.receptor do |r| r.rfc 'XAXX010101000' r.nombre 'RAMIREZ MARTINEZ JUAN JOSE' end + f.concepto do |c| c.unidad 'Servicio' c.descripcion 'Pago de Nómina' @@ -86,30 +90,27 @@ d.tipo '002' d.clave '001' d.concepto 'ISR' - d.importe_gravado 0.0 - d.importe_exento 76.97 + d.importe 0.0 end n.deduccion do |d| d.tipo '001' d.clave '002' d.concepto 'IMSS' - d.importe_gravado 0.0 - d.importe_exento 75.36 + d.importe 0.0 end n.deduccion do |d| d.tipo '006' d.clave '006' d.concepto 'Descuento por incapacidad' - d.importe_gravado 0.0 - d.importe_exento 200.00 + d.importe 0.0 end n.incapacidad do |i| i.dias 1 i.tipo 2 - i.descuento 200.00 + i.importe_monetario 200.00 end n.horas_extra do |h| @@ -124,6 +125,7 @@ context 'encabezado' do let(:encabezado){ prueba.to_h['Encabezado'] } + it{ expect(encabezado['fecha']).to eq('asignarFecha') } it{ expect(encabezado['tipoDeComprobante']).to eq('egreso') } it{ expect(encabezado['formaDePago']).to eq('PAGO EN UNA SOLA EXHIBICIÓN') } @@ -134,6 +136,7 @@ context 'datos adicionales' do let(:datos_adicionales){ prueba.to_h['Datos Adicionales'] } + it{ expect(datos_adicionales['tipoDocumento']).to eq('RECIBO DE NOMINA') } it{ expect(datos_adicionales['idNomina']).to eq('N-1') } it{ expect(datos_adicionales['idTrabajador']).to eq('') } @@ -142,6 +145,7 @@ context 'emisor' do let(:emisor){ prueba.to_h['Emisor'] } + it{ expect(emisor['rfc']).to eq('ESI920427886') } it{ expect(emisor['nombre']).to eq('FACTURACION MODERNA S.A de C.V.') } it{ expect(emisor['RegimenFiscal']).to eq('REGIMEN GENERAL DE LEY PERSONAS MORALES') } @@ -149,12 +153,14 @@ context 'receptor' do let(:receptor){ prueba.to_h['Receptor'] } + it{ expect(receptor['rfc']).to eq('XAXX010101000') } it{ expect(receptor['nombre']).to eq('RAMIREZ MARTINEZ JUAN JOSE') } end context 'concepto' do let(:concepto){ prueba.to_h['Conceptos'].first['Concepto'] } + it{ expect(concepto['cantidad']).to eq(1) } it{ expect(concepto['unidad']).to eq('Servicio') } it{ expect(concepto['descripcion']).to eq('Pago de Nómina') } @@ -164,95 +170,101 @@ context 'nomina' do let(:nomina){ prueba.to_h['Nomina'] } + context 'complemento nomina' do let(:complemento){ nomina['ComplementoNomina'] } - it{ expect(complemento['RegistroPatronal']).to eq('P123456789') } - it{ expect(complemento['NumEmpleado']).to eq('2013001') } - it{ expect(complemento['CURP']).to eq('XEXX010101MOCNRR02') } - it{ expect(complemento['TipoRegimen']).to eq(1)} - it{ expect(complemento['NumSeguridadSocial']).to eq('12345678912')} - it{ expect(complemento['FechaPago']).to eq(hoy.strftime("%F"))} - it{ expect(complemento['FechaInicialPago']).to eq(inicio_quincena.strftime("%F"))} - it{ expect(complemento['FechaFinalPago']).to eq(fin_quincena.strftime("%F"))} - it{ expect(complemento['NumDiasPagados']).to eq(15)} - it{ expect(complemento['Departamento']).to eq('Desarrollo')} - it{ expect(complemento['CLABE']).to eq('123456789012345678')} - it{ expect(complemento['Banco']).to eq('012')} - it{ expect(complemento['FechaInicioRelLaboral']).to eq(inicio_relacion_laboral.strftime("%F"))} - it{ expect(complemento['Antiguedad']).to eq(48)} - it{ expect(complemento['Puesto']).to eq('Programador')} - it{ expect(complemento['TipoContrato']).to eq('Base')} - it{ expect(complemento['PeriodicidadPago']).to eq('Quincenal')} - it{ expect(complemento['SalarioBaseCotApor']).to eq(200.0)} - it{ expect(complemento['RiesgoPuesto']).to eq(5)} - it{ expect(complemento['SalarioDiarioIntegrado']).to eq(209.04)} + + it { expect(complemento['RegistroPatronal']).to eq('P123456789') } + it { expect(complemento['NumEmpleado']).to eq('2013001') } + it { expect(complemento['CURP']).to eq('XEXX010101MOCNRR02') } + it { expect(complemento['TipoRegimen']).to eq(1)} + it { expect(complemento['NumSeguridadSocial']).to eq('12345678912')} + it { expect(complemento['FechaPago']).to eq(hoy.strftime("%F"))} + it { expect(complemento['FechaInicialPago']).to eq(inicio_quincena.strftime("%F"))} + it { expect(complemento['FechaFinalPago']).to eq(fin_quincena.strftime("%F"))} + it { expect(complemento['NumDiasPagados']).to eq(15)} + it { expect(complemento['Departamento']).to eq('Desarrollo')} + it { expect(complemento['CLABE']).to eq('123456789012345678')} + it { expect(complemento['Banco']).to eq('012')} + it { expect(complemento['FechaInicioRelLaboral']).to eq(inicio_relacion_laboral.strftime("%F"))} + it { expect(complemento['Antiguedad']).to eq(48)} + it { expect(complemento['Puesto']).to eq('Programador')} + it { expect(complemento['TipoContrato']).to eq('Base')} + it { expect(complemento['PeriodicidadPago']).to eq('Quincenal')} + it { expect(complemento['SalarioBaseCotApor']).to eq(200.0)} + it { expect(complemento['RiesgoPuesto']).to eq(5)} + it { expect(complemento['SalarioDiarioIntegrado']).to eq(209.04)} end context 'percepciones' do context 'primera percepcion' do let(:percepcion) { nomina['Percepciones'].first['Percepcion'] } - it{ expect(percepcion['TipoPercepcion']).to eq('001')} - it{ expect(percepcion['Clave']).to eq('001')} + + it { expect(percepcion['TipoPercepcion']).to eq('001')} + it { expect(percepcion['Clave']).to eq('001')} it{ expect(percepcion['Concepto']).to eq('Sueldos')} - it{ expect(percepcion['ImporteGravado']).to eq(3000.00)} - it{ expect(percepcion['ImporteExento']).to eq(0.00)} + it { expect(percepcion['ImporteGravado']).to eq(3000.00)} + it { expect(percepcion['ImporteExento']).to eq(0.00)} end context 'segunda percepcion' do let(:percepcion) { nomina['Percepciones'].last['Percepcion'] } - it{ expect(percepcion['TipoPercepcion']).to eq('019')} - it{ expect(percepcion['Clave']).to eq('019')} - it{ expect(percepcion['Concepto']).to eq('Horas extra')} - it{ expect(percepcion['ImporteGravado']).to eq(0.00)} - it{ expect(percepcion['ImporteExento']).to eq(100.00)} + + it { expect(percepcion['TipoPercepcion']).to eq('019')} + it { expect(percepcion['Clave']).to eq('019')} + it { expect(percepcion['Concepto']).to eq('Horas extra')} + it { expect(percepcion['ImporteGravado']).to eq(0.00)} + it { expect(percepcion['ImporteExento']).to eq(100.00)} end end context 'deducciones' do context 'primera deduccion' do let(:deduccion) { nomina['Deducciones'][0]['Deduccion'] } - it{ expect(deduccion['TipoDeduccion']).to eq('002')} - it{ expect(deduccion['Clave']).to eq('001')} - it{ expect(deduccion['Concepto']).to eq('ISR')} - it{ expect(deduccion['ImporteGravado']).to eq(0.00)} - it{ expect(deduccion['ImporteExento']).to eq(76.97)} + + it { expect(deduccion['TipoDeduccion']).to eq('002')} + it { expect(deduccion['Clave']).to eq('001')} + it { expect(deduccion['Concepto']).to eq('ISR')} + it { expect(deduccion['Importe']).to eq(0.00)} end context 'segunda deduccion' do let(:deduccion) { nomina['Deducciones'][1]['Deduccion'] } - it{ expect(deduccion['TipoDeduccion']).to eq('001')} - it{ expect(deduccion['Clave']).to eq('002')} - it{ expect(deduccion['Concepto']).to eq('IMSS')} - it{ expect(deduccion['ImporteGravado']).to eq(0.00)} - it{ expect(deduccion['ImporteExento']).to eq(75.36)} + + it { expect(deduccion['TipoDeduccion']).to eq('001')} + it { expect(deduccion['Clave']).to eq('002')} + it { expect(deduccion['Concepto']).to eq('IMSS')} + it { expect(deduccion['Importe']).to eq(0.00)} end context 'tercera deduccion' do let(:deduccion) { nomina['Deducciones'][2]['Deduccion'] } - it{ expect(deduccion['TipoDeduccion']).to eq('006')} - it{ expect(deduccion['Clave']).to eq('006')} - it{ expect(deduccion['Concepto']).to eq('Descuento por incapacidad')} - it{ expect(deduccion['ImporteGravado']).to eq(0.00)} - it{ expect(deduccion['ImporteExento']).to eq(200.0)} + + it { expect(deduccion['TipoDeduccion']).to eq('006')} + it { expect(deduccion['Clave']).to eq('006')} + it { expect(deduccion['Concepto']).to eq('Descuento por incapacidad')} + it { expect(deduccion['Importe']).to eq(0.00)} end end context 'incapacidades' do context 'primera incapacidad' do let(:incapacidad) { nomina['Incapacidades'].first['Incapacidad'] } - it{ expect(incapacidad['DiasIncapacidad']).to eq(1)} - it{ expect(incapacidad['TipoIncapacidad']).to eq(2)} - it{ expect(incapacidad['Descuento']).to eq(200.00)} + + it { expect(incapacidad['DiasIncapacidad']).to eq(1)} + it { expect(incapacidad['TipoIncapacidad']).to eq(2)} + it { expect(incapacidad['ImporteMonetario']).to eq(200.00)} end end context 'horas extra' do context 'primera hora extra' do let(:hora_extra) { nomina['InformacionHorasExtra'].first['HorasExtra'] } - it{ expect(hora_extra['Dias']).to eq(1)} - it{ expect(hora_extra['TipoHoras']).to eq('Dobles')} - it{ expect(hora_extra['HorasExtra']).to eq(1)} - it{ expect(hora_extra['ImportePagado']).to eq(100.00)} + + it { expect(hora_extra['Dias']).to eq(1)} + it { expect(hora_extra['TipoHoras']).to eq('Dobles')} + it { expect(hora_extra['HorasExtra']).to eq(1)} + it { expect(hora_extra['ImportePagado']).to eq(100.00)} end end @@ -260,16 +272,17 @@ context 'salida en texto' do let(:salida){ prueba.to_s } - it{ expect(salida).to match(/\[Encabezado\]/) } - it{ expect(salida).to match(/\[Datos Adicionales\]/) } - it{ expect(salida).to match(/\[Emisor\]/) } - it{ expect(salida).to match(/\[Receptor\]/) } - it{ expect(salida).to match(/\[Concepto\]/) } - it{ expect(salida).to match(/\[ComplementoNomina\]/) } - it{ expect(salida).to match(/\[Percepcion\]/) } - it{ expect(salida).to match(/\[Deduccion\]/) } - it{ expect(salida).to match(/\[Incapacidad\]/) } - it{ expect(salida).to match(/\[HorasExtra\]/) } + + it { expect(salida).to match(/\[Encabezado\]/) } + it { expect(salida).to match(/\[Datos Adicionales\]/) } + it { expect(salida).to match(/\[Emisor\]/) } + it { expect(salida).to match(/\[Receptor\]/) } + it { expect(salida).to match(/\[Concepto\]/) } + it { expect(salida).to match(/\[ComplementoNomina\]/) } + it { expect(salida).to match(/\[Percepcion\]/) } + it { expect(salida).to match(/\[Deduccion\]/) } + it { expect(salida).to match(/\[Incapacidad\]/) } + it { expect(salida).to match(/\[HorasExtra\]/) } end end end From 27ae3b0233a9dccbd0261ec59c1e4b28984556f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Thu, 8 Dec 2016 14:41:57 -0600 Subject: [PATCH 02/56] Add field to complemento_nomina --- lib/fm_layout/nomina/complemento_nomina.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/fm_layout/nomina/complemento_nomina.rb b/lib/fm_layout/nomina/complemento_nomina.rb index 222b17a..139b3a1 100644 --- a/lib/fm_layout/nomina/complemento_nomina.rb +++ b/lib/fm_layout/nomina/complemento_nomina.rb @@ -21,6 +21,7 @@ def self.campos_vs_metodos 'FechaInicialPago' => 'fecha_inicial_de_pago', 'FechaFinalPago' => 'fecha_final_de_pago', 'NumDiasPagados' => 'dias_pagados', + 'TotalPercepciones' => 'total_percepciones', 'Departamento' => 'departamento', 'CLABE' => 'clabe', 'Banco' => 'banco', From 70443967c9d41ff7b4ad235b9939cb65dfb3132c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Thu, 15 Dec 2016 14:03:55 -0600 Subject: [PATCH 03/56] Changes for percepciones --- Gemfile | 1 + lib/fm_layout.rb | 7 + lib/fm_layout/concepto.rb | 3 +- lib/fm_layout/datos_adicionales.rb | 3 +- lib/fm_layout/domicilio.rb | 3 +- lib/fm_layout/emisor.rb | 3 +- lib/fm_layout/encabezado.rb | 5 +- lib/fm_layout/fm_layout.rb | 1 - lib/fm_layout/fm_layout_nomina.rb | 194 +++++++++++++++++++++ lib/fm_layout/fm_seccion.rb | 29 ++- lib/fm_layout/nomina/complemento_nomina.rb | 2 +- lib/fm_layout/nomina/deduccion.rb | 2 +- lib/fm_layout/nomina/horas_extra.rb | 3 +- lib/fm_layout/nomina/incapacidad.rb | 2 +- lib/fm_layout/nomina/nomina.rb | 16 +- lib/fm_layout/nomina/percepcion.rb | 27 ++- lib/fm_layout/receptor.rb | 3 +- lib/fm_layout/recibo_nomina.rb | 47 +++++ spec/fm_layout_nomina_spec.rb | 57 +++--- 19 files changed, 345 insertions(+), 63 deletions(-) create mode 100644 lib/fm_layout/fm_layout_nomina.rb create mode 100644 lib/fm_layout/recibo_nomina.rb diff --git a/Gemfile b/Gemfile index 893a299..07fa574 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,7 @@ source 'https://rubygems.org' gem 'coveralls', require: false +gem 'pry' # Specify your gem's dependencies in fm_layout.gemspec gemspec diff --git a/lib/fm_layout.rb b/lib/fm_layout.rb index ee2b878..8821a4c 100644 --- a/lib/fm_layout.rb +++ b/lib/fm_layout.rb @@ -1,5 +1,6 @@ require "fm_layout/version" require "fm_layout/fm_layout" +require "fm_layout/fm_layout_nomina" module FmLayout def self.define_layout @@ -7,6 +8,12 @@ def self.define_layout yield(layout) if block_given? layout end + + def self.define_layout_nomina + layout = FmLayoutNomina.new + yield(layout) if block_given? + layout + end end # Monkeypatch diff --git a/lib/fm_layout/concepto.rb b/lib/fm_layout/concepto.rb index 62e57c3..ef0c152 100644 --- a/lib/fm_layout/concepto.rb +++ b/lib/fm_layout/concepto.rb @@ -4,7 +4,8 @@ module FmLayout class Concepto include FmSeccion - def initialize + def initialize separador = '|' + @separador = separador @titulo = 'Concepto' @datos = {} valores_iniciales diff --git a/lib/fm_layout/datos_adicionales.rb b/lib/fm_layout/datos_adicionales.rb index de5f8a7..03fce32 100644 --- a/lib/fm_layout/datos_adicionales.rb +++ b/lib/fm_layout/datos_adicionales.rb @@ -4,7 +4,8 @@ module FmLayout class DatosAdicionales include FmSeccion - def initialize + def initialize separador = '|' + @separador = separador @titulo = "Datos Adicionales" @datos= {} valores_iniciales diff --git a/lib/fm_layout/domicilio.rb b/lib/fm_layout/domicilio.rb index 3384327..d1aa528 100644 --- a/lib/fm_layout/domicilio.rb +++ b/lib/fm_layout/domicilio.rb @@ -5,7 +5,8 @@ module FmLayout class Domicilio include FmSeccion - def initialize(titulo = 'Domicilio') + def initialize(titulo = 'Domicilio',separador = '|') + @separador = separador @titulo = titulo @datos = {} valores_iniciales diff --git a/lib/fm_layout/emisor.rb b/lib/fm_layout/emisor.rb index b6fc580..a3cb762 100644 --- a/lib/fm_layout/emisor.rb +++ b/lib/fm_layout/emisor.rb @@ -4,7 +4,8 @@ module FmLayout class Emisor include FmSeccion - def initialize + def initialize separador = '|' + @separador = separador @titulo = 'Emisor' @datos = {} valores_iniciales diff --git a/lib/fm_layout/encabezado.rb b/lib/fm_layout/encabezado.rb index a3f68e3..6dc78b9 100644 --- a/lib/fm_layout/encabezado.rb +++ b/lib/fm_layout/encabezado.rb @@ -3,8 +3,9 @@ module FmLayout class Encabezado include FmSeccion - def initialize - @titulo= 'Encabezado' + def initialize separador = '|', titulo = 'Encabezado' + @separador = separador + @titulo= titulo @datos= {} valores_iniciales end diff --git a/lib/fm_layout/fm_layout.rb b/lib/fm_layout/fm_layout.rb index d5164ef..26bb673 100644 --- a/lib/fm_layout/fm_layout.rb +++ b/lib/fm_layout/fm_layout.rb @@ -8,7 +8,6 @@ require 'fm_layout/impuesto_trasladado_local' require 'fm_layout/impuesto_retenido' require 'fm_layout/impuesto_retenido_local' -require 'fm_layout/nomina/nomina' module FmLayout class FmLayout diff --git a/lib/fm_layout/fm_layout_nomina.rb b/lib/fm_layout/fm_layout_nomina.rb new file mode 100644 index 0000000..c3de7cf --- /dev/null +++ b/lib/fm_layout/fm_layout_nomina.rb @@ -0,0 +1,194 @@ +require 'fm_layout/datos_adicionales' +require 'fm_layout/emisor' +require 'fm_layout/receptor' +require 'fm_layout/domicilio' +require 'fm_layout/concepto' +require 'fm_layout/impuesto_trasladado' +require 'fm_layout/impuesto_trasladado_local' +require 'fm_layout/impuesto_retenido' +require 'fm_layout/impuesto_retenido_local' +require 'fm_layout/recibo_nomina' +require 'fm_layout/nomina/nomina' + +module FmLayout + class FmLayoutNomina + def initialize + @recibo_nomina = ReciboNomina.new + @datos_adicionales = DatosAdicionales.new('=') + @emisor = Emisor.new('=') + @receptor= Receptor.new('=') + @conceptos = [] + @impuestos_trasladados = [] + @impuestos_trasladados_locales = [] + @impuestos_retenidos = [] + @impuestos_retenidos_locales = [] + end + + def recibo_nomina + if block_given? + yield(@recibo_nomina) + else + @recibo_nomina + end + end + + def datos_adicionales + if block_given? + yield(@datos_adicionales) + else + @datos_adicionales + end + end + + def emisor + if block_given? + yield(@emisor) + else + @emisor + end + end + + def receptor + if block_given? + yield(@receptor) + else + @receptor + end + end + + def domicilio_fiscal + @domicilio_fiscal ||= Domicilio.new('DomicilioFiscal','=') + if block_given? + yield(@domicilio_fiscal) + else + @domicilio_fiscal + end + end + + def domicilio + @domicilio ||= Domicilio.new('Domicilio','=') + if block_given? + yield(@domicilio) + else + @domicilio + end + end + + def expedido_en + @expedido_en ||= Domicilio.new('ExpedidoEn','=') + if block_given? + yield(@expedido_en) + else + @expedido_en + end + end + + def concepto + concepto = Concepto.new('=') + if block_given? + yield(concepto) + @conceptos << concepto + else + concepto + end + end + + def impuesto_trasladado + impuesto = ImpuestoTrasladado.new + if block_given? + yield(impuesto) + @impuestos_trasladados << impuesto + else + impuesto + end + end + + def impuesto_trasladado_local + impuesto = ImpuestoTrasladadoLocal.new + if block_given? + yield(impuesto) + @impuestos_trasladados_locales << impuesto + else + impuesto + end + end + + def impuesto_retenido + impuesto = ImpuestoRetenido.new + if block_given? + yield(impuesto) + @impuestos_retenidos << impuesto + else + impuesto + end + end + + def impuesto_retenido_local + impuesto = ImpuestoRetenidoLocal.new + if block_given? + yield(impuesto) + @impuestos_retenidos_locales << impuesto + else + impuesto + end + end + + def nomina + @nomina = Nomina::Nomina.new + if block_given? + yield(@nomina) + else + @nomina + end + end + + def to_s + salida = @recibo_nomina.to_s + @datos_adicionales.to_s + @emisor.to_s + @domicilio_fiscal.to_s + @expedido_en.to_s + @receptor.to_s + @domicilio.to_s + salida += @conceptos.map(&:to_s).reduce(:+).to_s + salida += @impuestos_trasladados.map(&:to_s).reduce(:+).to_s + salida += @impuestos_retenidos.map(&:to_s).reduce(:+).to_s + salida += @impuestos_trasladados_locales.map(&:to_s).reduce(:+).to_s + salida += @impuestos_retenidos_locales.map(&:to_s).reduce(:+).to_s + salida += @nomina.to_s + salida + end + + def to_h + recibo_nomina.to_h + .merge(@datos_adicionales.to_h) + .merge(@emisor.to_h) + .merge(@domicilio_fiscal.to_h) + .merge(@expedido_en.to_h) + .merge(@receptor.to_h) + .merge(@domicilio.to_h) + .merge(obtener_hash_conceptos) + .merge(obtener_hash_traslados) + .merge(obtener_hash_retenciones) + .merge(@nomina.to_h) + .merge(obtener_hash_traslados_locales) + .merge(obtener_hash_retenciones_locales) + end + + private + + def obtener_hash_conceptos + { 'Conceptos' => @conceptos.map(&:to_h) } + end + + def obtener_hash_retenciones + {'ImpuestosRetenidos' => @impuestos_retenidos.map(&:to_h) } + end + + def obtener_hash_traslados + { 'ImpuestosTrasladados' => @impuestos_trasladados.map(&:to_h) } + end + + def obtener_hash_traslados_locales + { 'ImpuestosTrasladadosLocales' => @impuestos_trasladados_locales.map(&:to_h) } + end + + def obtener_hash_retenciones_locales + { 'ImpuestosRetenidosLocales' => @impuestos_retenidos_locales.map(&:to_h) } + end + end +end diff --git a/lib/fm_layout/fm_seccion.rb b/lib/fm_layout/fm_seccion.rb index 973f55e..93fed74 100644 --- a/lib/fm_layout/fm_seccion.rb +++ b/lib/fm_layout/fm_seccion.rb @@ -1,21 +1,36 @@ module FmLayout module FmSeccion - def titulo - @titulo - end + def titulo + @titulo + end - def to_h - { @titulo => @datos } - end + def to_h + { @titulo => @datos } + end def to_s + separador = @separador ? @separador : '|' + salida = "[#{@titulo}]\r\n\r\n" @datos.each do |k,v| - salida += "#{k}|#{v}\r\n" + salida += "#{k}#{separador}#{v}\r\n" end salida += "\r\n" salida end + end + module FmSeccionNomina + include FmSeccion + + def to_s + salida = "[#{@titulo}]\r\n\r\n" + @datos.each do |k,v| + salida += "#{k}=#{v}\r\n" + end + salida += "\r\n" + salida + end end + end diff --git a/lib/fm_layout/nomina/complemento_nomina.rb b/lib/fm_layout/nomina/complemento_nomina.rb index 139b3a1..feb247d 100644 --- a/lib/fm_layout/nomina/complemento_nomina.rb +++ b/lib/fm_layout/nomina/complemento_nomina.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class ComplementoNomina - include ::FmLayout::FmSeccion + include ::FmLayout::FmSeccionNomina def initialize @titulo= 'ComplementoNomina' diff --git a/lib/fm_layout/nomina/deduccion.rb b/lib/fm_layout/nomina/deduccion.rb index cdc60ad..5ccaaea 100644 --- a/lib/fm_layout/nomina/deduccion.rb +++ b/lib/fm_layout/nomina/deduccion.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class Deduccion - include ::FmLayout::FmSeccion + include ::FmLayout::FmSeccionNomina def initialize @titulo= 'Deduccion' diff --git a/lib/fm_layout/nomina/horas_extra.rb b/lib/fm_layout/nomina/horas_extra.rb index 45751db..c05f332 100644 --- a/lib/fm_layout/nomina/horas_extra.rb +++ b/lib/fm_layout/nomina/horas_extra.rb @@ -2,7 +2,8 @@ module FmLayout module Nomina class HorasExtra - include ::FmLayout::FmSeccion + include ::FmLayout::FmSeccionNomina + attr_reader :datos def initialize @titulo= 'HorasExtra' diff --git a/lib/fm_layout/nomina/incapacidad.rb b/lib/fm_layout/nomina/incapacidad.rb index 0030204..07ac2f8 100644 --- a/lib/fm_layout/nomina/incapacidad.rb +++ b/lib/fm_layout/nomina/incapacidad.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class Incapacidad - include ::FmLayout::FmSeccion + include ::FmLayout::FmSeccionNomina def initialize @titulo= 'Incapacidad' diff --git a/lib/fm_layout/nomina/nomina.rb b/lib/fm_layout/nomina/nomina.rb index f37d225..6c080c3 100644 --- a/lib/fm_layout/nomina/nomina.rb +++ b/lib/fm_layout/nomina/nomina.rb @@ -13,7 +13,6 @@ def initialize @percepciones = [] @deducciones = [] @incapacidades = [] - @horas_extras = [] end def complemento_nomina @@ -54,23 +53,12 @@ def incapacidad end end - def horas_extra - horas_extra = HorasExtra.new - if block_given? - yield(horas_extra) - @horas_extras << horas_extra - else - horas_extra - end - end - - def to_h - { 'Nomina' => {}.merge( @complemento_nomina.to_h).merge(obtener_hash_percepciones).merge(obtener_hash_deducciones).merge(obtener_hash_incapacidades).merge(obtener_hash_horas_extra) } + { 'Nomina' => {}.merge( @complemento_nomina.to_h).merge(obtener_hash_percepciones).merge(obtener_hash_deducciones).merge(obtener_hash_incapacidades) } end def to_s - @complemento_nomina.to_s + @percepciones.map(&:to_s).inject(:+).to_s + @deducciones.map(&:to_s).inject(:+).to_s + @incapacidades.map(&:to_s).inject(:+).to_s + @horas_extras.map(&:to_s).inject(:+).to_s + @complemento_nomina.to_s + @percepciones.map(&:to_s).inject(:+).to_s + @deducciones.map(&:to_s).inject(:+).to_s + @incapacidades.map(&:to_s).inject(:+).to_s end private diff --git a/lib/fm_layout/nomina/percepcion.rb b/lib/fm_layout/nomina/percepcion.rb index 4eec36a..8f18a29 100644 --- a/lib/fm_layout/nomina/percepcion.rb +++ b/lib/fm_layout/nomina/percepcion.rb @@ -2,11 +2,15 @@ module FmLayout module Nomina class Percepcion - include ::FmLayout::FmSeccion + include ::FmLayout::FmSeccionNomina def initialize @titulo= 'Percepcion' @datos= {} + @horas_extras_dias = [] + @horas_extras_tipo_horas = [] + @horas_extras_horas_extras = [] + @horas_extras_importe_pagado = [] #valores_iniciales end @@ -20,6 +24,20 @@ def self.campos_vs_metodos } end + def horas_extra + horas_extra = HorasExtra.new + if block_given? + yield(horas_extra) + @horas_extras_dias << horas_extra.datos["Dias"] + @horas_extras_tipo_horas << horas_extra.datos["TipoHoras"] + @horas_extras_horas_extras << horas_extra.datos["HorasExtra"] + @horas_extras_importe_pagado << horas_extra.datos["ImportePagado"] + formato_horas_extras + else + horas_extra + end + end + # Creación de los métodos de acceso dinámicamente campos_vs_metodos.each do |campo, metodo| define_method(metodo) do |dato| @@ -27,6 +45,13 @@ def self.campos_vs_metodos end end + def formato_horas_extras + @datos[:"HorasExtra.Dias"] = "[#{@horas_extras_dias.join(',')}]" + @datos[:"HorasExtra.TipoHoras"] = "[#{@horas_extras_tipo_horas.join(',')}]" + @datos[:"HorasExtra.HorasExtra"] = "[#{@horas_extras_horas_extras.join(',')}]" + @datos[:"HorasExtra.ImportePagado"] = "[#{@horas_extras_importe_pagado.join(',')}]" + end + end end end diff --git a/lib/fm_layout/receptor.rb b/lib/fm_layout/receptor.rb index 0ccb5ae..a69d8e4 100644 --- a/lib/fm_layout/receptor.rb +++ b/lib/fm_layout/receptor.rb @@ -4,7 +4,8 @@ module FmLayout class Receptor include FmSeccion - def initialize + def initialize separador = '|' + @separador = separador @titulo = 'Receptor' @datos = {} end diff --git a/lib/fm_layout/recibo_nomina.rb b/lib/fm_layout/recibo_nomina.rb new file mode 100644 index 0000000..b25845b --- /dev/null +++ b/lib/fm_layout/recibo_nomina.rb @@ -0,0 +1,47 @@ +require 'fm_layout/fm_seccion' +module FmLayout + class ReciboNomina + include FmSeccion + + def initialize + @separador = '=' + @titulo= 'ReciboNomina' + @datos= {} + valores_iniciales + end + + def self.campos_vs_metodos + { + 'serie' => 'serie', + 'folio' => 'folio', + 'fecha' => 'fecha', + 'subTotal' => 'subtotal', + 'descuento' => 'descuento', + 'total' => 'total', + 'Moneda' => 'moneda', + 'noCertificado' => 'numero_de_certificado', + 'LugarExpedicion' => 'lugar_de_expedicion', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + private + + def valores_iniciales + @datos['serie'] = nil + @datos['folio'] = 'asignarFolio' + @datos['fecha'] = nil + @datos['subTotal'] = nil + @datos['descuento'] = nil + @datos['total'] = nil + @datos['noCertificado'] = nil + end + end + +end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 3afae33..728507e 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -10,14 +10,14 @@ let(:inicio_relacion_laboral){ Date.today - 48*7 } let(:prueba) do # DSL - FmLayout.define_layout do |f| - f.encabezado do |e| - e.tipo_de_comprobante 'egreso' - e.forma_de_pago 'PAGO EN UNA SOLA EXHIBICIÓN' - e.metodo_de_pago 'Transferencia Electrónica' - e.condiciones_de_pago 'Contado' - e.motivo_de_descuento 'Deducciones de nómina' - e.lugar_de_expedicion 'Nuevo León, México' + FmLayout.define_layout_nomina do |f| + f.recibo_nomina do |e| + e.serie 'RN' + e.folio '105' + e.fecha '2016-11-29T16:07:43' + e.subtotal '4420.00' + e.descuento '193.43' + e.total '4226.57' end f.datos_adicionales do |d| d.tipo_de_documento 'RECIBO DE NOMINA' @@ -80,6 +80,12 @@ p.concepto 'Horas extra' p.importe_gravado 0.0 p.importe_exento 100.0 + p.horas_extra do |h| + h.dias 1 + h.tipo 'Dobles' + h.horas_extra 1 + h.importe 100.0 + end end n.deduccion do |d| @@ -112,24 +118,18 @@ i.descuento 200.00 end - n.horas_extra do |h| - h.dias 1 - h.tipo 'Dobles' - h.horas_extra 1 - h.importe 100.00 - end end end end - context 'encabezado' do - let(:encabezado){ prueba.to_h['Encabezado'] } - it{ expect(encabezado['fecha']).to eq('asignarFecha') } - it{ expect(encabezado['tipoDeComprobante']).to eq('egreso') } - it{ expect(encabezado['formaDePago']).to eq('PAGO EN UNA SOLA EXHIBICIÓN') } - it{ expect(encabezado['condicionesDePago']).to eq('Contado') } - it{ expect(encabezado['motivoDescuento']).to eq('Deducciones de nómina') } - it{ expect(encabezado['LugarExpedicion']).to eq('Nuevo León, México') } + context 'recibo_nomina' do + let(:recibo_nomina){ prueba.to_h['ReciboNomina'] } + it{ expect(recibo_nomina['serie']).to eq('RN') } + it{ expect(recibo_nomina['folio']).to eq('105') } + it{ expect(recibo_nomina['fecha']).to eq('2016-11-29T16:07:43') } + it{ expect(recibo_nomina['subTotal']).to eq('4420.00') } + it{ expect(recibo_nomina['descuento']).to eq('193.43') } + it{ expect(recibo_nomina['total']).to eq('4226.57') } end context 'datos adicionales' do @@ -248,11 +248,11 @@ context 'horas extra' do context 'primera hora extra' do - let(:hora_extra) { nomina['InformacionHorasExtra'].first['HorasExtra'] } - it{ expect(hora_extra['Dias']).to eq(1)} - it{ expect(hora_extra['TipoHoras']).to eq('Dobles')} - it{ expect(hora_extra['HorasExtra']).to eq(1)} - it{ expect(hora_extra['ImportePagado']).to eq(100.00)} + let(:percepcion) { nomina['Percepciones'].last['Percepcion']} + it{ expect(percepcion[:"HorasExtra.Dias"]).to eq('[1]')} + it{ expect(percepcion[:"HorasExtra.TipoHoras"]).to eq('[Dobles]')} + it{ expect(percepcion[:"HorasExtra.HorasExtra"]).to eq('[1]')} + it{ expect(percepcion[:"HorasExtra.ImportePagado"]).to eq('[100.0]')} end end @@ -260,7 +260,7 @@ context 'salida en texto' do let(:salida){ prueba.to_s } - it{ expect(salida).to match(/\[Encabezado\]/) } + it{ expect(salida).to match(/\[ReciboNomina\]/) } it{ expect(salida).to match(/\[Datos Adicionales\]/) } it{ expect(salida).to match(/\[Emisor\]/) } it{ expect(salida).to match(/\[Receptor\]/) } @@ -269,7 +269,6 @@ it{ expect(salida).to match(/\[Percepcion\]/) } it{ expect(salida).to match(/\[Deduccion\]/) } it{ expect(salida).to match(/\[Incapacidad\]/) } - it{ expect(salida).to match(/\[HorasExtra\]/) } end end end From fadbca8893fafb70845cf3724fc73b201eda5ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Fri, 23 Dec 2016 10:36:20 -0600 Subject: [PATCH 04/56] Add test for accion_o_titulo --- lib/fm_layout/nomina/percepcion.rb | 18 +++++++++++++----- spec/fm_layout_nomina_spec.rb | 26 ++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/lib/fm_layout/nomina/percepcion.rb b/lib/fm_layout/nomina/percepcion.rb index 8f18a29..cc00fb8 100644 --- a/lib/fm_layout/nomina/percepcion.rb +++ b/lib/fm_layout/nomina/percepcion.rb @@ -16,11 +16,11 @@ def initialize def self.campos_vs_metodos { - 'TipoPercepcion' => 'tipo', - 'Clave' => 'clave', - 'Concepto' => 'concepto', - 'ImporteGravado' => 'importe_gravado', - 'ImporteExento' => 'importe_exento', + 'TipoPercepcion' => 'tipo', + 'Clave' => 'clave', + 'Concepto' => 'concepto', + 'ImporteGravado' => 'importe_gravado', + 'ImporteExento' => 'importe_exento', } end @@ -52,6 +52,14 @@ def formato_horas_extras @datos[:"HorasExtra.ImportePagado"] = "[#{@horas_extras_importe_pagado.join(',')}]" end + def valor_mercado dato + @datos["AccionesOTitulos.ValorMercado"] = dato + end + + def precio_al_otorgarse dato + @datos["AccionesOTitulos.PrecioAlOtorgarse"] = dato + end + end end end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 387378d..1815777 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -92,6 +92,16 @@ end end + n.percepcion do |p| + p.tipo '045' + p.clave '045' + p.concepto 'Acción o Título' + p.importe_gravado 3000 + p.importe_exento 0 + p.valor_mercado 200 + p.precio_al_otorgarse 20 + end + n.deduccion do |d| d.tipo '002' d.clave '001' @@ -207,7 +217,7 @@ end context 'segunda percepcion' do - let(:percepcion) { nomina['Percepciones'].last['Percepcion'] } + let(:percepcion) { nomina['Percepciones'][1]['Percepcion'] } it { expect(percepcion['TipoPercepcion']).to eq('019')} it { expect(percepcion['Clave']).to eq('019')} @@ -215,6 +225,18 @@ it { expect(percepcion['ImporteGravado']).to eq(0.00)} it { expect(percepcion['ImporteExento']).to eq(100.00)} end + + context 'tercera percepcion' do + let(:percepcion) { nomina['Percepciones'].last['Percepcion'] } + + it { expect(percepcion['TipoPercepcion']).to eq('045')} + it { expect(percepcion['Clave']).to eq('045')} + it { expect(percepcion['Concepto']).to eq('Acción o Título')} + it { expect(percepcion['ImporteGravado']).to eq(3000.00)} + it { expect(percepcion['ImporteExento']).to eq(0.00)} + it { expect(percepcion['AccionesOTitulos.ValorMercado']).to eq 200 } + it { expect(percepcion['AccionesOTitulos.PrecioAlOtorgarse']).to eq 20 } + end end context 'deducciones' do @@ -258,7 +280,7 @@ context 'horas extra' do context 'primera hora extra' do - let(:percepcion) { nomina['Percepciones'].last['Percepcion']} + let(:percepcion) { nomina['Percepciones'][1]['Percepcion']} it{ expect(percepcion[:"HorasExtra.Dias"]).to eq('[1]')} it{ expect(percepcion[:"HorasExtra.TipoHoras"]).to eq('[Dobles]')} it{ expect(percepcion[:"HorasExtra.HorasExtra"]).to eq('[1]')} From 5f41f1e05694ad2b0aa34fa5683a4b36c2dfb7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Fri, 23 Dec 2016 10:42:34 -0600 Subject: [PATCH 05/56] Small refactor in HoraExtras --- lib/fm_layout/nomina/percepcion.rb | 8 ++++---- spec/fm_layout_nomina_spec.rb | 14 ++++---------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/lib/fm_layout/nomina/percepcion.rb b/lib/fm_layout/nomina/percepcion.rb index cc00fb8..9cef186 100644 --- a/lib/fm_layout/nomina/percepcion.rb +++ b/lib/fm_layout/nomina/percepcion.rb @@ -46,10 +46,10 @@ def horas_extra end def formato_horas_extras - @datos[:"HorasExtra.Dias"] = "[#{@horas_extras_dias.join(',')}]" - @datos[:"HorasExtra.TipoHoras"] = "[#{@horas_extras_tipo_horas.join(',')}]" - @datos[:"HorasExtra.HorasExtra"] = "[#{@horas_extras_horas_extras.join(',')}]" - @datos[:"HorasExtra.ImportePagado"] = "[#{@horas_extras_importe_pagado.join(',')}]" + @datos["HorasExtra.Dias"] = "[#{@horas_extras_dias.join(',')}]" + @datos["HorasExtra.TipoHoras"] = "[#{@horas_extras_tipo_horas.join(',')}]" + @datos["HorasExtra.HorasExtra"] = "[#{@horas_extras_horas_extras.join(',')}]" + @datos["HorasExtra.ImportePagado"] = "[#{@horas_extras_importe_pagado.join(',')}]" end def valor_mercado dato diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 1815777..df1a323 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -224,6 +224,10 @@ it { expect(percepcion['Concepto']).to eq('Horas extra')} it { expect(percepcion['ImporteGravado']).to eq(0.00)} it { expect(percepcion['ImporteExento']).to eq(100.00)} + it { expect(percepcion["HorasExtra.Dias"]).to eq('[1]')} + it { expect(percepcion["HorasExtra.TipoHoras"]).to eq('[Dobles]')} + it { expect(percepcion["HorasExtra.HorasExtra"]).to eq('[1]')} + it { expect(percepcion["HorasExtra.ImportePagado"]).to eq('[100.0]')} end context 'tercera percepcion' do @@ -278,16 +282,6 @@ end end - context 'horas extra' do - context 'primera hora extra' do - let(:percepcion) { nomina['Percepciones'][1]['Percepcion']} - it{ expect(percepcion[:"HorasExtra.Dias"]).to eq('[1]')} - it{ expect(percepcion[:"HorasExtra.TipoHoras"]).to eq('[Dobles]')} - it{ expect(percepcion[:"HorasExtra.HorasExtra"]).to eq('[1]')} - it{ expect(percepcion[:"HorasExtra.ImportePagado"]).to eq('[100.0]')} - end - end - end context 'salida en texto' do From 507335c478407ad71108a471b0d43b06d39a5577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Fri, 23 Dec 2016 11:31:21 -0600 Subject: [PATCH 06/56] Add support and test for JubilacionPensionRetiro --- .../nomina/jubilacion_pension_retiro.rb | 31 +++++++++++++++++++ lib/fm_layout/nomina/nomina.rb | 20 ++++++++++-- spec/fm_layout_nomina_spec.rb | 28 +++++++++++++---- 3 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 lib/fm_layout/nomina/jubilacion_pension_retiro.rb diff --git a/lib/fm_layout/nomina/jubilacion_pension_retiro.rb b/lib/fm_layout/nomina/jubilacion_pension_retiro.rb new file mode 100644 index 0000000..82e3bb6 --- /dev/null +++ b/lib/fm_layout/nomina/jubilacion_pension_retiro.rb @@ -0,0 +1,31 @@ +module FmLayout + module Nomina + class JubilacionPensionRetiro + + include ::FmLayout::FmSeccionNomina + + def initialize + @titulo = 'JubilacionPensionRetiro' + @datos = {} + end + + def self.campos_vs_metodos + { + 'TotalUnaExhibicion' => 'total_una_exhibicion', + 'TotalParcialidad' => 'total_parcialidad', + 'MontoDiario' => 'monto_diario', + 'IngresoAcumulable' => 'ingreso_acumulable', + 'IngresoNoAcumulable' => 'ingreso_no_acumulable', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + end + end +end diff --git a/lib/fm_layout/nomina/nomina.rb b/lib/fm_layout/nomina/nomina.rb index 6c080c3..65040e4 100644 --- a/lib/fm_layout/nomina/nomina.rb +++ b/lib/fm_layout/nomina/nomina.rb @@ -3,6 +3,7 @@ require 'fm_layout/nomina/deduccion' require 'fm_layout/nomina/incapacidad' require 'fm_layout/nomina/horas_extra' +require 'fm_layout/nomina/jubilacion_pension_retiro' module FmLayout module Nomina @@ -11,6 +12,7 @@ class Nomina def initialize @complemento_nomina = ComplementoNomina.new @percepciones = [] + @jubilacion_pension_retiro = [] @deducciones = [] @incapacidades = [] end @@ -33,6 +35,16 @@ def percepcion end end + def jubilacion_pension_retiro + jubilacion_pension_retiro = JubilacionPensionRetiro.new + if block_given? + yield(jubilacion_pension_retiro) + @jubilacion_pension_retiro << jubilacion_pension_retiro + else + jubilacion_pension_retiro + end + end + def deduccion deduccion = Deduccion.new if block_given? @@ -54,11 +66,11 @@ def incapacidad end def to_h - { 'Nomina' => {}.merge( @complemento_nomina.to_h).merge(obtener_hash_percepciones).merge(obtener_hash_deducciones).merge(obtener_hash_incapacidades) } + { 'Nomina' => {}.merge( @complemento_nomina.to_h).merge(obtener_hash_percepciones).merge(obtener_hash_jubilacion_pension_retiro).merge(obtener_hash_deducciones).merge(obtener_hash_incapacidades) } end def to_s - @complemento_nomina.to_s + @percepciones.map(&:to_s).inject(:+).to_s + @deducciones.map(&:to_s).inject(:+).to_s + @incapacidades.map(&:to_s).inject(:+).to_s + @complemento_nomina.to_s + @percepciones.map(&:to_s).inject(:+).to_s + @jubilacion_pension_retiro.map(&:to_s).inject(:+).to_s + @deducciones.map(&:to_s).inject(:+).to_s + @incapacidades.map(&:to_s).inject(:+).to_s end private @@ -67,6 +79,10 @@ def obtener_hash_percepciones { 'Percepciones' => @percepciones.map(&:to_h) } end + def obtener_hash_jubilacion_pension_retiro + @jubilacion_pension_retiro.map(&:to_h).first + end + def obtener_hash_deducciones { 'Deducciones' => @deducciones.map(&:to_h) } end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index df1a323..36a5aa0 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -71,9 +71,9 @@ end n.percepcion do |p| - p.tipo '001' - p.clave '001' - p.concepto 'Sueldos' + p.tipo '039' + p.clave '039' + p.concepto 'Jubilaciones, pensiones o haberes de retiro' p.importe_gravado 3000 p.importe_exento 0 end @@ -102,6 +102,12 @@ p.precio_al_otorgarse 20 end + n.jubilacion_pension_retiro do |j| + j.total_una_exhibicion 500 + j.ingreso_acumulable 200 + j.ingreso_no_acumulable 20 + end + n.deduccion do |d| d.tipo '002' d.clave '001' @@ -209,9 +215,9 @@ context 'primera percepcion' do let(:percepcion) { nomina['Percepciones'].first['Percepcion'] } - it { expect(percepcion['TipoPercepcion']).to eq('001')} - it { expect(percepcion['Clave']).to eq('001')} - it{ expect(percepcion['Concepto']).to eq('Sueldos')} + it { expect(percepcion['TipoPercepcion']).to eq('039')} + it { expect(percepcion['Clave']).to eq('039')} + it{ expect(percepcion['Concepto']).to eq('Jubilaciones, pensiones o haberes de retiro')} it { expect(percepcion['ImporteGravado']).to eq(3000.00)} it { expect(percepcion['ImporteExento']).to eq(0.00)} end @@ -243,6 +249,15 @@ end end + context 'jubilación pensión retiro' do + + let(:jubilacion) { nomina['JubilacionPensionRetiro']} + + it { expect(jubilacion['TotalUnaExhibicion']).to eq 500 } + it { expect(jubilacion['IngresoAcumulable']).to eq 200 } + it { expect(jubilacion['IngresoNoAcumulable']).to eq 20 } + end + context 'deducciones' do context 'primera deduccion' do let(:deduccion) { nomina['Deducciones'][0]['Deduccion'] } @@ -293,6 +308,7 @@ it{ expect(salida).to match(/\[Concepto\]/) } it{ expect(salida).to match(/\[ComplementoNomina\]/) } it{ expect(salida).to match(/\[Percepcion\]/) } + it{ expect(salida).to match(/\[JubilacionPensionRetiro\]/) } it{ expect(salida).to match(/\[Deduccion\]/) } it{ expect(salida).to match(/\[Incapacidad\]/) } end From 2f71d31f24fc82057ef2f4250992d08d16688cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 28 Dec 2016 16:25:20 -0600 Subject: [PATCH 07/56] Add support for OtroPago --- lib/fm_layout/nomina/nomina.rb | 28 ++++++++++++--- lib/fm_layout/nomina/otro_pago.rb | 48 +++++++++++++++++++++++++ spec/fm_layout_nomina_spec.rb | 59 +++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 lib/fm_layout/nomina/otro_pago.rb diff --git a/lib/fm_layout/nomina/nomina.rb b/lib/fm_layout/nomina/nomina.rb index 65040e4..c9fe7fb 100644 --- a/lib/fm_layout/nomina/nomina.rb +++ b/lib/fm_layout/nomina/nomina.rb @@ -4,6 +4,7 @@ require 'fm_layout/nomina/incapacidad' require 'fm_layout/nomina/horas_extra' require 'fm_layout/nomina/jubilacion_pension_retiro' +require 'fm_layout/nomina/otro_pago' module FmLayout module Nomina @@ -11,10 +12,12 @@ class Nomina def initialize @complemento_nomina = ComplementoNomina.new - @percepciones = [] + @percepciones = [] @jubilacion_pension_retiro = [] - @deducciones = [] - @incapacidades = [] + @deducciones = [] + @incapacidades = [] + @otro_pagos = [] + @num_otro_pago = 0 end def complemento_nomina @@ -55,6 +58,17 @@ def deduccion end end + def otro_pago + @num_otro_pago += 1 + otro_pago = OtroPago.new @num_otro_pago + if block_given? + yield(otro_pago) + @otro_pagos << otro_pago + else + otro_pago + end + end + def incapacidad incapacidad = Incapacidad.new if block_given? @@ -66,11 +80,11 @@ def incapacidad end def to_h - { 'Nomina' => {}.merge( @complemento_nomina.to_h).merge(obtener_hash_percepciones).merge(obtener_hash_jubilacion_pension_retiro).merge(obtener_hash_deducciones).merge(obtener_hash_incapacidades) } + { 'Nomina' => {}.merge( @complemento_nomina.to_h).merge(obtener_hash_percepciones).merge(obtener_hash_jubilacion_pension_retiro).merge(obtener_hash_deducciones).merge(obtener_hash_otro_pagos).merge(obtener_hash_incapacidades) } end def to_s - @complemento_nomina.to_s + @percepciones.map(&:to_s).inject(:+).to_s + @jubilacion_pension_retiro.map(&:to_s).inject(:+).to_s + @deducciones.map(&:to_s).inject(:+).to_s + @incapacidades.map(&:to_s).inject(:+).to_s + @complemento_nomina.to_s + @percepciones.map(&:to_s).inject(:+).to_s + @jubilacion_pension_retiro.map(&:to_s).inject(:+).to_s + @deducciones.map(&:to_s).inject(:+).to_s + @otro_pagos.map(&:to_s).inject(:+).to_s + @incapacidades.map(&:to_s).inject(:+).to_s end private @@ -87,6 +101,10 @@ def obtener_hash_deducciones { 'Deducciones' => @deducciones.map(&:to_h) } end + def obtener_hash_otro_pagos + { 'OtroPagos' => @otro_pagos.map(&:to_h) } + end + def obtener_hash_incapacidades { 'Incapacidades' => @incapacidades.map(&:to_h) } end diff --git a/lib/fm_layout/nomina/otro_pago.rb b/lib/fm_layout/nomina/otro_pago.rb new file mode 100644 index 0000000..5e83d68 --- /dev/null +++ b/lib/fm_layout/nomina/otro_pago.rb @@ -0,0 +1,48 @@ +module FmLayout + module Nomina + class OtroPago + + include ::FmLayout::FmSeccionNomina + attr_reader :datos + + def initialize num_pago + @titulo= "OtroPago##{num_pago}" + @datos= {} + #valores_iniciales + end + + def self.campos_vs_metodos + { + 'TipoOtroPago' => 'tipo', + 'Clave' => 'clave', + 'Concepto' => 'concepto', + 'Importe' => 'importe', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + def subsidio_causado dato + @datos["SubsidioAlEmpleo.SubsidioCausado"] = dato + end + + def saldo dato + @datos["CompensacionSaldosAFavor.SaldoAFavor"] = "[#{dato}]" + end + + def anio dato + @datos["CompensacionSaldosAFavor.Año"] = "[#{dato}]" + end + + def remanente_saldo dato + @datos["CompensacionSaldosAFavor.RemanenteSalFav"] = "[#{dato}]" + end + + end + end +end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 36a5aa0..45c85f0 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -129,6 +129,31 @@ d.importe 0.0 end + n.otro_pago do |op| + op.tipo '002' + op.clave '002' + op.concepto 'Un concepto' + op.importe 250.5 + op.subsidio_causado 20.3 + end + + n.otro_pago do |op| + op.tipo '004' + op.clave '004' + op.concepto 'Un concepto' + op.importe 350.5 + op.saldo 200.0 + op.anio 2016 + op.remanente_saldo 100.0 + end + + n.otro_pago do |op| + op.tipo '001' + op.clave '001' + op.concepto 'Un concepto' + op.importe 150.5 + end + n.incapacidad do |i| i.dias 1 i.tipo 2 @@ -287,6 +312,40 @@ end end + context "otro pago" do + context "primer otro pago" do + let(:otro_pago) { nomina['OtroPagos'][0]['OtroPago#1'] } + + it { expect(otro_pago['TipoOtroPago']).to eq '002' } + it { expect(otro_pago['Clave']).to eq '002' } + it { expect(otro_pago['Concepto']).to eq 'Un concepto' } + it { expect(otro_pago['Importe']).to eq 250.5 } + it { expect(otro_pago['SubsidioAlEmpleo.SubsidioCausado']).to eq 20.3 } + end # context primer otro pago + + context "segundo otro pago" do + let(:otro_pago) { nomina['OtroPagos'][1]['OtroPago#2'] } + + it { expect(otro_pago['TipoOtroPago']).to eq '004' } + it { expect(otro_pago['Clave']).to eq '004' } + it { expect(otro_pago['Concepto']).to eq 'Un concepto' } + it { expect(otro_pago['Importe']).to eq 350.5 } + it { expect(otro_pago['CompensacionSaldosAFavor.SaldoAFavor']).to eq "[200.0]" } + it { expect(otro_pago['CompensacionSaldosAFavor.Año']).to eq "[2016]" } + it { expect(otro_pago['CompensacionSaldosAFavor.RemanenteSalFav']).to eq "[100.0]" } + end # context segundo otro pago + + context "tercer otro pago" do + let(:otro_pago) { nomina['OtroPagos'][2]['OtroPago#3'] } + + it { expect(otro_pago['TipoOtroPago']).to eq '001' } + it { expect(otro_pago['Clave']).to eq '001' } + it { expect(otro_pago['Concepto']).to eq 'Un concepto' } + it { expect(otro_pago['Importe']).to eq 150.5 } + end # context tercer otro pago + + end # context otro pago + context 'incapacidades' do context 'primera incapacidad' do let(:incapacidad) { nomina['Incapacidades'].first['Incapacidad'] } From 2605f8710fb6db617f3beb858a486ef9fb20df31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 28 Dec 2016 16:45:48 -0600 Subject: [PATCH 08/56] Add method tipo_nomina in ComplementoNomina --- lib/fm_layout/nomina/complemento_nomina.rb | 1 + spec/fm_layout_nomina_spec.rb | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/fm_layout/nomina/complemento_nomina.rb b/lib/fm_layout/nomina/complemento_nomina.rb index feb247d..8983f26 100644 --- a/lib/fm_layout/nomina/complemento_nomina.rb +++ b/lib/fm_layout/nomina/complemento_nomina.rb @@ -12,6 +12,7 @@ def initialize def self.campos_vs_metodos { + 'TipoNomina' => 'tipo_nomina', 'RegistroPatronal' => 'registro_patronal', 'NumEmpleado' => 'numero_de_empleado', 'CURP' => 'curp', diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 45c85f0..01a88c9 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -47,6 +47,7 @@ f.nomina do |n| n.complemento_nomina do |c| + c.tipo_nomina 'O' c.registro_patronal 'P123456789' c.numero_de_empleado '2013001' c.curp 'XEXX010101MOCNRR02' @@ -214,6 +215,7 @@ context 'complemento nomina' do let(:complemento){ nomina['ComplementoNomina'] } + it { expect(complemento['TipoNomina']).to eq('O') } it { expect(complemento['RegistroPatronal']).to eq('P123456789') } it { expect(complemento['NumEmpleado']).to eq('2013001') } it { expect(complemento['CURP']).to eq('XEXX010101MOCNRR02') } From ceb63bcca2a1e46d2a98b01750e4ea373c3f4e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 28 Dec 2016 17:31:10 -0600 Subject: [PATCH 09/56] Add initial value in complemento_nomina to get version of complemento_nomina --- lib/fm_layout/nomina/complemento_nomina.rb | 6 +++++- spec/fm_layout_nomina_spec.rb | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/fm_layout/nomina/complemento_nomina.rb b/lib/fm_layout/nomina/complemento_nomina.rb index 8983f26..074f97a 100644 --- a/lib/fm_layout/nomina/complemento_nomina.rb +++ b/lib/fm_layout/nomina/complemento_nomina.rb @@ -7,7 +7,7 @@ class ComplementoNomina def initialize @titulo= 'ComplementoNomina' @datos= {} - #valores_iniciales + valores_iniciales end def self.campos_vs_metodos @@ -45,6 +45,10 @@ def self.campos_vs_metodos end end + def valores_iniciales + @datos['Version'] = '1.2' + end + end end end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 01a88c9..663111a 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -215,6 +215,7 @@ context 'complemento nomina' do let(:complemento){ nomina['ComplementoNomina'] } + it { expect(complemento['Version']).to eq('1.2') } it { expect(complemento['TipoNomina']).to eq('O') } it { expect(complemento['RegistroPatronal']).to eq('P123456789') } it { expect(complemento['NumEmpleado']).to eq('2013001') } From 6acb4724e69bf776cdc7a231a3e5e420ba0c6818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Thu, 29 Dec 2016 18:31:41 -0600 Subject: [PATCH 10/56] Updating field and method of Emisor for regimen --- lib/fm_layout/emisor.rb | 2 +- spec/fm_layout_nomina_spec.rb | 4 ++-- spec/fm_layout_spec.rb | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/fm_layout/emisor.rb b/lib/fm_layout/emisor.rb index a3cb762..a4c2ac7 100644 --- a/lib/fm_layout/emisor.rb +++ b/lib/fm_layout/emisor.rb @@ -15,6 +15,7 @@ def self.campos_vs_metodos { 'rfc' => 'rfc', 'nombre' => 'nombre', + 'Regimen' => 'regimen', 'RegimenFiscal' => 'regimen_fiscal', } end @@ -31,7 +32,6 @@ def self.campos_vs_metodos def valores_iniciales @datos['rfc'] = nil @datos['nombre'] = nil - @datos['RegimenFiscal'] = nil end end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 663111a..063a852 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -30,7 +30,7 @@ f.emisor do |e| e.rfc 'ESI920427886' e.nombre 'FACTURACION MODERNA S.A de C.V.' - e.regimen_fiscal 'REGIMEN GENERAL DE LEY PERSONAS MORALES' + e.regimen '612' end f.receptor do |r| @@ -189,7 +189,7 @@ it{ expect(emisor['rfc']).to eq('ESI920427886') } it{ expect(emisor['nombre']).to eq('FACTURACION MODERNA S.A de C.V.') } - it{ expect(emisor['RegimenFiscal']).to eq('REGIMEN GENERAL DE LEY PERSONAS MORALES') } + it{ expect(emisor['Regimen']).to eq('612') } end context 'receptor' do diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index 2896a1d..dcd5119 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -34,7 +34,7 @@ f.emisor do |e| e.rfc 'TUMG620310R95' e.nombre 'FACTURACION MODERNA S.A de C.V.' - e.regimen_fiscal 'REGIMEN GENERAL DE LEY PERSONAS MORALES' + e.regimen '612' end f.domicilio_fiscal do |d| d.calle 'Calle 1' @@ -157,7 +157,7 @@ let(:emisor){ prueba.to_h['Emisor'] } it{ expect(emisor['rfc']).to eq('TUMG620310R95') } it{ expect(emisor['nombre']).to eq('FACTURACION MODERNA S.A de C.V.') } - it{ expect(emisor['RegimenFiscal']).to eq('REGIMEN GENERAL DE LEY PERSONAS MORALES') } + it{ expect(emisor['Regimen']).to eq('612') } end context 'domicilio fiscal' do From e61274d94f7fdd33088c09c5dd375a60d08197d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Fri, 30 Dec 2016 14:24:22 -0600 Subject: [PATCH 11/56] Add field curp for method in Emisor --- lib/fm_layout/emisor.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/fm_layout/emisor.rb b/lib/fm_layout/emisor.rb index a4c2ac7..7b9414b 100644 --- a/lib/fm_layout/emisor.rb +++ b/lib/fm_layout/emisor.rb @@ -17,6 +17,7 @@ def self.campos_vs_metodos 'nombre' => 'nombre', 'Regimen' => 'regimen', 'RegimenFiscal' => 'regimen_fiscal', + 'Curp' => 'curp', } end From 83b95452ca1facde68239eaf5a4fedcb0cb08b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 2 Jan 2017 13:03:26 -0600 Subject: [PATCH 12/56] Add fields to emisor for ComprobanteNomina 1.2 --- lib/fm_layout/receptor.rb | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/fm_layout/receptor.rb b/lib/fm_layout/receptor.rb index a69d8e4..a1e0fae 100644 --- a/lib/fm_layout/receptor.rb +++ b/lib/fm_layout/receptor.rb @@ -12,10 +12,25 @@ def initialize separador = '|' def self.campos_vs_metodos { - 'rfc' => 'rfc', - 'nombre' => 'nombre', - 'NumCliente' => 'numero_de_cliente', - 'emailCliente' => 'email', + 'rfc' => 'rfc', + 'nombre' => 'nombre', + 'Curp' => 'curp', + 'NumSeguridadSocial' => 'numero_seguridad_social', + 'FechaInicioRelLaboral' => 'fecha_inicio_relacion_laboral', + 'Antigüedad' => 'antiguedad', + 'TipoContrato' => 'tipo_contrato', + 'TipoJornada' => 'tipo_jornada', + 'TipoRegimen' => 'tipo_regimen', + 'NumEmpleado' => 'numero_empleado', + 'Departamento' => 'departamento', + 'Puesto' => 'puesto', + 'RiesgoPuesto' => 'riesgo_puesto', + 'PeriodicidadPago' => 'periodicidad_pago', + 'Banco' => 'banco', + 'CuentaBancaria' => 'cuenta_bancaria', + 'SalarioBaseCotApor' => 'salario_base', + 'SalarioDiarioIntegrado' => 'salario_diario_integrado', + 'ClaveEntFed' => 'clave_entidad_federativa', } end From 2b2626aae9496c915fa06fd188479b5ca570723a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 2 Jan 2017 13:03:36 -0600 Subject: [PATCH 13/56] Remove domicilio_fical and expedido of fm_layout_nomina --- lib/fm_layout/fm_layout_nomina.rb | 32 +------------------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/lib/fm_layout/fm_layout_nomina.rb b/lib/fm_layout/fm_layout_nomina.rb index c3de7cf..f69f41e 100644 --- a/lib/fm_layout/fm_layout_nomina.rb +++ b/lib/fm_layout/fm_layout_nomina.rb @@ -1,7 +1,6 @@ require 'fm_layout/datos_adicionales' require 'fm_layout/emisor' require 'fm_layout/receptor' -require 'fm_layout/domicilio' require 'fm_layout/concepto' require 'fm_layout/impuesto_trasladado' require 'fm_layout/impuesto_trasladado_local' @@ -56,33 +55,6 @@ def receptor end end - def domicilio_fiscal - @domicilio_fiscal ||= Domicilio.new('DomicilioFiscal','=') - if block_given? - yield(@domicilio_fiscal) - else - @domicilio_fiscal - end - end - - def domicilio - @domicilio ||= Domicilio.new('Domicilio','=') - if block_given? - yield(@domicilio) - else - @domicilio - end - end - - def expedido_en - @expedido_en ||= Domicilio.new('ExpedidoEn','=') - if block_given? - yield(@expedido_en) - else - @expedido_en - end - end - def concepto concepto = Concepto.new('=') if block_given? @@ -143,7 +115,7 @@ def nomina end def to_s - salida = @recibo_nomina.to_s + @datos_adicionales.to_s + @emisor.to_s + @domicilio_fiscal.to_s + @expedido_en.to_s + @receptor.to_s + @domicilio.to_s + salida = @recibo_nomina.to_s + @datos_adicionales.to_s + @emisor.to_s + @receptor.to_s salida += @conceptos.map(&:to_s).reduce(:+).to_s salida += @impuestos_trasladados.map(&:to_s).reduce(:+).to_s salida += @impuestos_retenidos.map(&:to_s).reduce(:+).to_s @@ -157,10 +129,8 @@ def to_h recibo_nomina.to_h .merge(@datos_adicionales.to_h) .merge(@emisor.to_h) - .merge(@domicilio_fiscal.to_h) .merge(@expedido_en.to_h) .merge(@receptor.to_h) - .merge(@domicilio.to_h) .merge(obtener_hash_conceptos) .merge(obtener_hash_traslados) .merge(obtener_hash_retenciones) From caac749352f697172c73f07dbdf2c2e4ef4e4765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 2 Jan 2017 13:44:46 -0600 Subject: [PATCH 14/56] Updating structure of concepto to comprobante_nomina --- lib/fm_layout/concepto.rb | 4 ++-- lib/fm_layout/fm_layout.rb | 2 +- lib/fm_layout/fm_layout_nomina.rb | 4 +++- spec/fm_layout_nomina_spec.rb | 4 ++-- spec/fm_layout_spec.rb | 4 ---- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/fm_layout/concepto.rb b/lib/fm_layout/concepto.rb index ef0c152..7316a09 100644 --- a/lib/fm_layout/concepto.rb +++ b/lib/fm_layout/concepto.rb @@ -4,9 +4,9 @@ module FmLayout class Concepto include FmSeccion - def initialize separador = '|' + def initialize separador, num_concepto @separador = separador - @titulo = 'Concepto' + @titulo = num_concepto ? "Concepto##{num_concepto}" : 'Concepto' @datos = {} valores_iniciales end diff --git a/lib/fm_layout/fm_layout.rb b/lib/fm_layout/fm_layout.rb index 26bb673..7143b56 100644 --- a/lib/fm_layout/fm_layout.rb +++ b/lib/fm_layout/fm_layout.rb @@ -83,7 +83,7 @@ def expedido_en end def concepto - concepto = Concepto.new + concepto = Concepto.new '|', nil if block_given? yield(concepto) @conceptos << concepto diff --git a/lib/fm_layout/fm_layout_nomina.rb b/lib/fm_layout/fm_layout_nomina.rb index f69f41e..f3ddaa1 100644 --- a/lib/fm_layout/fm_layout_nomina.rb +++ b/lib/fm_layout/fm_layout_nomina.rb @@ -21,6 +21,7 @@ def initialize @impuestos_trasladados_locales = [] @impuestos_retenidos = [] @impuestos_retenidos_locales = [] + @num_concepto = 0 end def recibo_nomina @@ -56,7 +57,8 @@ def receptor end def concepto - concepto = Concepto.new('=') + @num_concepto += 1 + concepto = Concepto.new('=', @num_concepto) if block_given? yield(concepto) @conceptos << concepto diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 063a852..2d54691 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -200,7 +200,7 @@ end context 'concepto' do - let(:concepto){ prueba.to_h['Conceptos'].first['Concepto'] } + let(:concepto){ prueba.to_h['Conceptos'].first['Concepto#1'] } it{ expect(concepto['cantidad']).to eq(1) } it{ expect(concepto['unidad']).to eq('Servicio') } @@ -367,7 +367,7 @@ it{ expect(salida).to match(/\[Datos Adicionales\]/) } it{ expect(salida).to match(/\[Emisor\]/) } it{ expect(salida).to match(/\[Receptor\]/) } - it{ expect(salida).to match(/\[Concepto\]/) } + it{ expect(salida).to match(/\[Concepto#1\]/) } it{ expect(salida).to match(/\[ComplementoNomina\]/) } it{ expect(salida).to match(/\[Percepcion\]/) } it{ expect(salida).to match(/\[JubilacionPensionRetiro\]/) } diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index dcd5119..090cd9e 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -61,8 +61,6 @@ f.receptor do |r| r.rfc 'XAXX010101000' r.nombre 'PUBLICO EN GENERAL' - r.numero_de_cliente '987654' - r.email 'soporte@facturacionmoderna.com' end f.domicilio do |d| d.calle 'Calle 3' @@ -190,8 +188,6 @@ let(:receptor){ prueba.to_h['Receptor'] } it{ expect(receptor['rfc']).to eq('XAXX010101000') } it{ expect(receptor['nombre']).to eq('PUBLICO EN GENERAL') } - it{ expect(receptor['NumCliente']).to eq('987654') } - it{ expect(receptor['emailCliente']).to eq('soporte@facturacionmoderna.com') } end context 'domilicio' do From 4a7697c9d46784b0733fddca6b328517a049f3ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 2 Jan 2017 14:10:35 -0600 Subject: [PATCH 15/56] Updating structure of percepcion to comprobante_nomina --- lib/fm_layout/nomina/nomina.rb | 4 +++- lib/fm_layout/nomina/percepcion.rb | 4 ++-- lib/fm_layout/receptor.rb | 1 + spec/fm_layout_nomina_spec.rb | 8 ++++---- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/fm_layout/nomina/nomina.rb b/lib/fm_layout/nomina/nomina.rb index c9fe7fb..556ee5f 100644 --- a/lib/fm_layout/nomina/nomina.rb +++ b/lib/fm_layout/nomina/nomina.rb @@ -18,6 +18,7 @@ def initialize @incapacidades = [] @otro_pagos = [] @num_otro_pago = 0 + @num_percepcion = 0 end def complemento_nomina @@ -29,7 +30,8 @@ def complemento_nomina end def percepcion - percepcion = Percepcion.new + @num_percepcion += 1 + percepcion = Percepcion.new @num_percepcion if block_given? yield(percepcion) @percepciones << percepcion diff --git a/lib/fm_layout/nomina/percepcion.rb b/lib/fm_layout/nomina/percepcion.rb index 9cef186..1a730de 100644 --- a/lib/fm_layout/nomina/percepcion.rb +++ b/lib/fm_layout/nomina/percepcion.rb @@ -4,8 +4,8 @@ class Percepcion include ::FmLayout::FmSeccionNomina - def initialize - @titulo= 'Percepcion' + def initialize num_percepcion + @titulo= "Percepcion##{num_percepcion}" @datos= {} @horas_extras_dias = [] @horas_extras_tipo_horas = [] diff --git a/lib/fm_layout/receptor.rb b/lib/fm_layout/receptor.rb index a1e0fae..4cd3b7d 100644 --- a/lib/fm_layout/receptor.rb +++ b/lib/fm_layout/receptor.rb @@ -31,6 +31,7 @@ def self.campos_vs_metodos 'SalarioBaseCotApor' => 'salario_base', 'SalarioDiarioIntegrado' => 'salario_diario_integrado', 'ClaveEntFed' => 'clave_entidad_federativa', + 'emailCliente' => 'email', } end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 2d54691..0d28725 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -241,7 +241,7 @@ context 'percepciones' do context 'primera percepcion' do - let(:percepcion) { nomina['Percepciones'].first['Percepcion'] } + let(:percepcion) { nomina['Percepciones'].first['Percepcion#1'] } it { expect(percepcion['TipoPercepcion']).to eq('039')} it { expect(percepcion['Clave']).to eq('039')} @@ -251,7 +251,7 @@ end context 'segunda percepcion' do - let(:percepcion) { nomina['Percepciones'][1]['Percepcion'] } + let(:percepcion) { nomina['Percepciones'][1]['Percepcion#2'] } it { expect(percepcion['TipoPercepcion']).to eq('019')} it { expect(percepcion['Clave']).to eq('019')} @@ -265,7 +265,7 @@ end context 'tercera percepcion' do - let(:percepcion) { nomina['Percepciones'].last['Percepcion'] } + let(:percepcion) { nomina['Percepciones'].last['Percepcion#3'] } it { expect(percepcion['TipoPercepcion']).to eq('045')} it { expect(percepcion['Clave']).to eq('045')} @@ -369,7 +369,7 @@ it{ expect(salida).to match(/\[Receptor\]/) } it{ expect(salida).to match(/\[Concepto#1\]/) } it{ expect(salida).to match(/\[ComplementoNomina\]/) } - it{ expect(salida).to match(/\[Percepcion\]/) } + it{ expect(salida).to match(/\[Percepcion#1\]/) } it{ expect(salida).to match(/\[JubilacionPensionRetiro\]/) } it{ expect(salida).to match(/\[Deduccion\]/) } it{ expect(salida).to match(/\[Incapacidad\]/) } From b874385e63c565987c6c4e0cd578ead0ff76da47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 2 Jan 2017 14:20:41 -0600 Subject: [PATCH 16/56] Updating structure of deduccion to comprobante_nomina --- lib/fm_layout/nomina/deduccion.rb | 4 ++-- lib/fm_layout/nomina/nomina.rb | 4 +++- spec/fm_layout_nomina_spec.rb | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/fm_layout/nomina/deduccion.rb b/lib/fm_layout/nomina/deduccion.rb index a99d90e..09c9f87 100644 --- a/lib/fm_layout/nomina/deduccion.rb +++ b/lib/fm_layout/nomina/deduccion.rb @@ -4,8 +4,8 @@ class Deduccion include ::FmLayout::FmSeccionNomina - def initialize - @titulo = 'Deduccion' + def initialize num_deduccion + @titulo = "Deduccion##{num_deduccion}" @datos = {} end diff --git a/lib/fm_layout/nomina/nomina.rb b/lib/fm_layout/nomina/nomina.rb index 556ee5f..ced879e 100644 --- a/lib/fm_layout/nomina/nomina.rb +++ b/lib/fm_layout/nomina/nomina.rb @@ -19,6 +19,7 @@ def initialize @otro_pagos = [] @num_otro_pago = 0 @num_percepcion = 0 + @num_deduccion = 0 end def complemento_nomina @@ -51,7 +52,8 @@ def jubilacion_pension_retiro end def deduccion - deduccion = Deduccion.new + @num_deduccion += 1 + deduccion = Deduccion.new @num_deduccion if block_given? yield(deduccion) @deducciones << deduccion diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 0d28725..f89c117 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -288,7 +288,7 @@ context 'deducciones' do context 'primera deduccion' do - let(:deduccion) { nomina['Deducciones'][0]['Deduccion'] } + let(:deduccion) { nomina['Deducciones'][0]['Deduccion#1'] } it { expect(deduccion['TipoDeduccion']).to eq('002')} it { expect(deduccion['Clave']).to eq('001')} @@ -297,7 +297,7 @@ end context 'segunda deduccion' do - let(:deduccion) { nomina['Deducciones'][1]['Deduccion'] } + let(:deduccion) { nomina['Deducciones'][1]['Deduccion#2'] } it { expect(deduccion['TipoDeduccion']).to eq('001')} it { expect(deduccion['Clave']).to eq('002')} @@ -306,7 +306,7 @@ end context 'tercera deduccion' do - let(:deduccion) { nomina['Deducciones'][2]['Deduccion'] } + let(:deduccion) { nomina['Deducciones'][2]['Deduccion#3'] } it { expect(deduccion['TipoDeduccion']).to eq('006')} it { expect(deduccion['Clave']).to eq('006')} @@ -371,7 +371,7 @@ it{ expect(salida).to match(/\[ComplementoNomina\]/) } it{ expect(salida).to match(/\[Percepcion#1\]/) } it{ expect(salida).to match(/\[JubilacionPensionRetiro\]/) } - it{ expect(salida).to match(/\[Deduccion\]/) } + it{ expect(salida).to match(/\[Deduccion#1\]/) } it{ expect(salida).to match(/\[Incapacidad\]/) } end end From 573b63c9927daa7f9dbc7747caf91a2c03a60466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 2 Jan 2017 14:28:05 -0600 Subject: [PATCH 17/56] Updating structure of Incapacidad to comprobante_nomina --- lib/fm_layout/nomina/incapacidad.rb | 4 ++-- lib/fm_layout/nomina/nomina.rb | 16 +++++++++------- spec/fm_layout_nomina_spec.rb | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/fm_layout/nomina/incapacidad.rb b/lib/fm_layout/nomina/incapacidad.rb index febcc7e..938f30b 100644 --- a/lib/fm_layout/nomina/incapacidad.rb +++ b/lib/fm_layout/nomina/incapacidad.rb @@ -4,8 +4,8 @@ class Incapacidad include ::FmLayout::FmSeccionNomina - def initialize - @titulo = 'Incapacidad' + def initialize num_incapacidad + @titulo = "Incapacidad##{num_incapacidad}" @datos = {} end diff --git a/lib/fm_layout/nomina/nomina.rb b/lib/fm_layout/nomina/nomina.rb index ced879e..d3fbf24 100644 --- a/lib/fm_layout/nomina/nomina.rb +++ b/lib/fm_layout/nomina/nomina.rb @@ -14,12 +14,13 @@ def initialize @complemento_nomina = ComplementoNomina.new @percepciones = [] @jubilacion_pension_retiro = [] - @deducciones = [] - @incapacidades = [] - @otro_pagos = [] - @num_otro_pago = 0 - @num_percepcion = 0 - @num_deduccion = 0 + @deducciones = [] + @incapacidades = [] + @otro_pagos = [] + @num_otro_pago = 0 + @num_percepcion = 0 + @num_deduccion = 0 + @num_incapacidad = 0 end def complemento_nomina @@ -74,7 +75,8 @@ def otro_pago end def incapacidad - incapacidad = Incapacidad.new + @num_incapacidad += 1 + incapacidad = Incapacidad.new @num_incapacidad if block_given? yield(incapacidad) @incapacidades << incapacidad diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index f89c117..8c6ea67 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -351,7 +351,7 @@ context 'incapacidades' do context 'primera incapacidad' do - let(:incapacidad) { nomina['Incapacidades'].first['Incapacidad'] } + let(:incapacidad) { nomina['Incapacidades'].first['Incapacidad#1'] } it { expect(incapacidad['DiasIncapacidad']).to eq(1)} it { expect(incapacidad['TipoIncapacidad']).to eq(2)} @@ -372,7 +372,7 @@ it{ expect(salida).to match(/\[Percepcion#1\]/) } it{ expect(salida).to match(/\[JubilacionPensionRetiro\]/) } it{ expect(salida).to match(/\[Deduccion#1\]/) } - it{ expect(salida).to match(/\[Incapacidad\]/) } + it{ expect(salida).to match(/\[Incapacidad#1\]/) } end end end From ac9ecd28f9c1abcb83fcef957ad9db1cc700200e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Tue, 3 Jan 2017 18:05:06 -0600 Subject: [PATCH 18/56] Remove gem 'pry' --- Gemfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Gemfile b/Gemfile index 07fa574..893a299 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,6 @@ source 'https://rubygems.org' gem 'coveralls', require: false -gem 'pry' # Specify your gem's dependencies in fm_layout.gemspec gemspec From 2755b0c3e621b88b36028b1575271dabc585bde6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Tue, 3 Jan 2017 18:45:28 -0600 Subject: [PATCH 19/56] Updating fields of complemento_nomina and receptor for complemento_nomina 1.2 --- lib/fm_layout/nomina/complemento_nomina.rb | 31 +++-------- spec/fm_layout_nomina_spec.rb | 65 +++++++++++----------- 2 files changed, 40 insertions(+), 56 deletions(-) diff --git a/lib/fm_layout/nomina/complemento_nomina.rb b/lib/fm_layout/nomina/complemento_nomina.rb index 074f97a..4299ea6 100644 --- a/lib/fm_layout/nomina/complemento_nomina.rb +++ b/lib/fm_layout/nomina/complemento_nomina.rb @@ -12,29 +12,14 @@ def initialize def self.campos_vs_metodos { - 'TipoNomina' => 'tipo_nomina', - 'RegistroPatronal' => 'registro_patronal', - 'NumEmpleado' => 'numero_de_empleado', - 'CURP' => 'curp', - 'TipoRegimen' => 'tipo_de_regimen', - 'NumSeguridadSocial' => 'numero_de_seguridad_social', - 'FechaPago' => 'fecha_de_pago', - 'FechaInicialPago' => 'fecha_inicial_de_pago', - 'FechaFinalPago' => 'fecha_final_de_pago', - 'NumDiasPagados' => 'dias_pagados', - 'TotalPercepciones' => 'total_percepciones', - 'Departamento' => 'departamento', - 'CLABE' => 'clabe', - 'Banco' => 'banco', - 'FechaInicioRelLaboral' => 'inicio_de_relacion_laboral', - 'Antiguedad' => 'antiguedad', - 'Puesto' => 'puesto', - 'TipoContrato' => 'tipo_de_contrato', - 'TipoJornada' => 'tipo_de_jornada', - 'PeriodicidadPago' => 'periodicidad_de_pago', - 'SalarioBaseCotApor' => 'salario_base', - 'RiesgoPuesto' => 'riesgo_del_puesto', - 'SalarioDiarioIntegrado' => 'salario_diario_integrado', + 'TipoNomina' => 'tipo_nomina', + 'FechaPago' => 'fecha_de_pago', + 'FechaInicialPago' => 'fecha_inicial_de_pago', + 'FechaFinalPago' => 'fecha_final_de_pago', + 'NumDiasPagados' => 'dias_pagados', + 'TotalPercepciones' => 'total_percepciones', + 'TotalDeducciones' => 'total_deducciones', + 'TotalOtrosPagos' => 'total_otros_pagos', } end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 8c6ea67..cd71d77 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -36,6 +36,22 @@ f.receptor do |r| r.rfc 'XAXX010101000' r.nombre 'RAMIREZ MARTINEZ JUAN JOSE' + r.curp 'XEXX010101MOCNRR02' + r.numero_seguridad_social '12345678912' + r.fecha_inicio_relacion_laboral inicio_relacion_laboral.strftime("%F") + r.antiguedad "P52W" + r.tipo_contrato '01' + r.tipo_jornada '04' + r.tipo_regimen '02' + r.numero_empleado '2013001' + r.departamento 'Desarrollo' + r.puesto 'Programador' + r.riesgo_puesto 5 + r.periodicidad_pago '04' + r.banco '002' + r.salario_base 200 + r.salario_diario_integrado 209.04 + r.clave_entidad_federativa 'OAX' end f.concepto do |c| @@ -48,27 +64,10 @@ f.nomina do |n| n.complemento_nomina do |c| c.tipo_nomina 'O' - c.registro_patronal 'P123456789' - c.numero_de_empleado '2013001' - c.curp 'XEXX010101MOCNRR02' - c.tipo_de_regimen 1 - c.numero_de_seguridad_social '12345678912' c.fecha_de_pago hoy.strftime("%F") c.fecha_inicial_de_pago inicio_quincena.strftime("%F") c.fecha_final_de_pago fin_quincena.strftime("%F") c.dias_pagados 15 - c.departamento 'Desarrollo' - c.clabe '123456789012345678' - c.banco '012' - c.inicio_de_relacion_laboral inicio_relacion_laboral.strftime("%F") - c.antiguedad 48 - c.puesto 'Programador' - c.tipo_de_contrato 'Base' - c.tipo_de_jornada 'Mixta' - c.periodicidad_de_pago 'Quincenal' - c.salario_base 200 - c.riesgo_del_puesto 5 - c.salario_diario_integrado 209.04 end n.percepcion do |p| @@ -197,6 +196,22 @@ it{ expect(receptor['rfc']).to eq('XAXX010101000') } it{ expect(receptor['nombre']).to eq('RAMIREZ MARTINEZ JUAN JOSE') } + it{ expect(receptor['Curp']).to eq('XEXX010101MOCNRR02') } + it { expect(receptor['NumSeguridadSocial']).to eq('12345678912')} + it { expect(receptor['FechaInicioRelLaboral']).to eq(inicio_relacion_laboral.strftime("%F"))} + it { expect(receptor['Antigüedad']).to eq("P52W")} + it { expect(receptor['TipoContrato']).to eq('01')} + it { expect(receptor['TipoJornada']).to eq('04')} + it { expect(receptor['TipoRegimen']).to eq('02')} + it { expect(receptor['NumEmpleado']).to eq('2013001') } + it { expect(receptor['Departamento']).to eq('Desarrollo')} + it { expect(receptor['Puesto']).to eq('Programador')} + it { expect(receptor['RiesgoPuesto']).to eq(5)} + it { expect(receptor['PeriodicidadPago']).to eq('04')} + it { expect(receptor['Banco']).to eq('002')} + it { expect(receptor['SalarioBaseCotApor']).to eq(200.0)} + it { expect(receptor['SalarioDiarioIntegrado']).to eq(209.04)} + it { expect(receptor['ClaveEntFed']).to eq('OAX')} end context 'concepto' do @@ -217,26 +232,10 @@ it { expect(complemento['Version']).to eq('1.2') } it { expect(complemento['TipoNomina']).to eq('O') } - it { expect(complemento['RegistroPatronal']).to eq('P123456789') } - it { expect(complemento['NumEmpleado']).to eq('2013001') } - it { expect(complemento['CURP']).to eq('XEXX010101MOCNRR02') } - it { expect(complemento['TipoRegimen']).to eq(1)} - it { expect(complemento['NumSeguridadSocial']).to eq('12345678912')} it { expect(complemento['FechaPago']).to eq(hoy.strftime("%F"))} it { expect(complemento['FechaInicialPago']).to eq(inicio_quincena.strftime("%F"))} it { expect(complemento['FechaFinalPago']).to eq(fin_quincena.strftime("%F"))} it { expect(complemento['NumDiasPagados']).to eq(15)} - it { expect(complemento['Departamento']).to eq('Desarrollo')} - it { expect(complemento['CLABE']).to eq('123456789012345678')} - it { expect(complemento['Banco']).to eq('012')} - it { expect(complemento['FechaInicioRelLaboral']).to eq(inicio_relacion_laboral.strftime("%F"))} - it { expect(complemento['Antiguedad']).to eq(48)} - it { expect(complemento['Puesto']).to eq('Programador')} - it { expect(complemento['TipoContrato']).to eq('Base')} - it { expect(complemento['PeriodicidadPago']).to eq('Quincenal')} - it { expect(complemento['SalarioBaseCotApor']).to eq(200.0)} - it { expect(complemento['RiesgoPuesto']).to eq(5)} - it { expect(complemento['SalarioDiarioIntegrado']).to eq(209.04)} end context 'percepciones' do From 5faa1bf64a4560c73a9b4d4daf85500504e7d895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 4 Jan 2017 18:38:02 -0600 Subject: [PATCH 20/56] Add initial values for concepto, these values are used for complemento_nomina --- lib/fm_layout/concepto.rb | 4 +++- spec/fm_layout_nomina_spec.rb | 6 ++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/fm_layout/concepto.rb b/lib/fm_layout/concepto.rb index 7316a09..5094898 100644 --- a/lib/fm_layout/concepto.rb +++ b/lib/fm_layout/concepto.rb @@ -33,7 +33,9 @@ def self.campos_vs_metodos private def valores_iniciales - @datos['cantidad'] = 1 + @datos['cantidad'] = 1 + @datos['unidad'] = 'ACT' + @datos['descripcion'] = 'Pago de nómina' end end end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index cd71d77..b111ed3 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -55,8 +55,6 @@ end f.concepto do |c| - c.unidad 'Servicio' - c.descripcion 'Pago de Nómina' c.valor_unitario 3100.00 c.importe 3100.00 end @@ -218,8 +216,8 @@ let(:concepto){ prueba.to_h['Conceptos'].first['Concepto#1'] } it{ expect(concepto['cantidad']).to eq(1) } - it{ expect(concepto['unidad']).to eq('Servicio') } - it{ expect(concepto['descripcion']).to eq('Pago de Nómina') } + it{ expect(concepto['unidad']).to eq('ACT') } + it{ expect(concepto['descripcion']).to eq('Pago de nómina') } it{ expect(concepto['valorUnitario']).to eq(3100.00) } it{ expect(concepto['importe']).to eq(3100.00) } end From ccd9b23f7dd4ff18aca04c320968a58ad3419dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 4 Jan 2017 19:24:22 -0600 Subject: [PATCH 21/56] Add method registro_patronal to emisor --- lib/fm_layout/emisor.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/fm_layout/emisor.rb b/lib/fm_layout/emisor.rb index 7b9414b..6835c7f 100644 --- a/lib/fm_layout/emisor.rb +++ b/lib/fm_layout/emisor.rb @@ -13,11 +13,12 @@ def initialize separador = '|' def self.campos_vs_metodos { - 'rfc' => 'rfc', - 'nombre' => 'nombre', - 'Regimen' => 'regimen', - 'RegimenFiscal' => 'regimen_fiscal', - 'Curp' => 'curp', + 'rfc' => 'rfc', + 'nombre' => 'nombre', + 'Regimen' => 'regimen', + 'RegimenFiscal' => 'regimen_fiscal', + 'Curp' => 'curp', + 'RegistroPatronal' => 'registro_patronal', } end From 722291154f7ae9b7fa017f98cc1de348e8094df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 9 Jan 2017 13:42:29 -0600 Subject: [PATCH 22/56] Small refactor Remove unnecessary methods from fm_layout_nomina --- lib/fm_layout/fm_layout_nomina.rb | 71 ------------------------------- 1 file changed, 71 deletions(-) diff --git a/lib/fm_layout/fm_layout_nomina.rb b/lib/fm_layout/fm_layout_nomina.rb index f3ddaa1..8eac2e5 100644 --- a/lib/fm_layout/fm_layout_nomina.rb +++ b/lib/fm_layout/fm_layout_nomina.rb @@ -2,10 +2,6 @@ require 'fm_layout/emisor' require 'fm_layout/receptor' require 'fm_layout/concepto' -require 'fm_layout/impuesto_trasladado' -require 'fm_layout/impuesto_trasladado_local' -require 'fm_layout/impuesto_retenido' -require 'fm_layout/impuesto_retenido_local' require 'fm_layout/recibo_nomina' require 'fm_layout/nomina/nomina' @@ -17,10 +13,6 @@ def initialize @emisor = Emisor.new('=') @receptor= Receptor.new('=') @conceptos = [] - @impuestos_trasladados = [] - @impuestos_trasladados_locales = [] - @impuestos_retenidos = [] - @impuestos_retenidos_locales = [] @num_concepto = 0 end @@ -67,46 +59,6 @@ def concepto end end - def impuesto_trasladado - impuesto = ImpuestoTrasladado.new - if block_given? - yield(impuesto) - @impuestos_trasladados << impuesto - else - impuesto - end - end - - def impuesto_trasladado_local - impuesto = ImpuestoTrasladadoLocal.new - if block_given? - yield(impuesto) - @impuestos_trasladados_locales << impuesto - else - impuesto - end - end - - def impuesto_retenido - impuesto = ImpuestoRetenido.new - if block_given? - yield(impuesto) - @impuestos_retenidos << impuesto - else - impuesto - end - end - - def impuesto_retenido_local - impuesto = ImpuestoRetenidoLocal.new - if block_given? - yield(impuesto) - @impuestos_retenidos_locales << impuesto - else - impuesto - end - end - def nomina @nomina = Nomina::Nomina.new if block_given? @@ -119,10 +71,6 @@ def nomina def to_s salida = @recibo_nomina.to_s + @datos_adicionales.to_s + @emisor.to_s + @receptor.to_s salida += @conceptos.map(&:to_s).reduce(:+).to_s - salida += @impuestos_trasladados.map(&:to_s).reduce(:+).to_s - salida += @impuestos_retenidos.map(&:to_s).reduce(:+).to_s - salida += @impuestos_trasladados_locales.map(&:to_s).reduce(:+).to_s - salida += @impuestos_retenidos_locales.map(&:to_s).reduce(:+).to_s salida += @nomina.to_s salida end @@ -134,11 +82,7 @@ def to_h .merge(@expedido_en.to_h) .merge(@receptor.to_h) .merge(obtener_hash_conceptos) - .merge(obtener_hash_traslados) - .merge(obtener_hash_retenciones) .merge(@nomina.to_h) - .merge(obtener_hash_traslados_locales) - .merge(obtener_hash_retenciones_locales) end private @@ -147,20 +91,5 @@ def obtener_hash_conceptos { 'Conceptos' => @conceptos.map(&:to_h) } end - def obtener_hash_retenciones - {'ImpuestosRetenidos' => @impuestos_retenidos.map(&:to_h) } - end - - def obtener_hash_traslados - { 'ImpuestosTrasladados' => @impuestos_trasladados.map(&:to_h) } - end - - def obtener_hash_traslados_locales - { 'ImpuestosTrasladadosLocales' => @impuestos_trasladados_locales.map(&:to_h) } - end - - def obtener_hash_retenciones_locales - { 'ImpuestosRetenidosLocales' => @impuestos_retenidos_locales.map(&:to_h) } - end end end From fa5f2df510bf6158199daee9154c6fa691b76765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 9 Jan 2017 13:55:16 -0600 Subject: [PATCH 23/56] Small refactor --- lib/fm_layout/domicilio.rb | 2 +- lib/fm_layout/encabezado.rb | 5 ++--- lib/fm_layout/fm_seccion.rb | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/fm_layout/domicilio.rb b/lib/fm_layout/domicilio.rb index d1aa528..557a2cd 100644 --- a/lib/fm_layout/domicilio.rb +++ b/lib/fm_layout/domicilio.rb @@ -5,7 +5,7 @@ module FmLayout class Domicilio include FmSeccion - def initialize(titulo = 'Domicilio',separador = '|') + def initialize(titulo = 'Domicilio', separador = '|') @separador = separador @titulo = titulo @datos = {} diff --git a/lib/fm_layout/encabezado.rb b/lib/fm_layout/encabezado.rb index 7f8299c..6078a8d 100644 --- a/lib/fm_layout/encabezado.rb +++ b/lib/fm_layout/encabezado.rb @@ -3,9 +3,8 @@ module FmLayout class Encabezado include FmSeccion - def initialize separador = '|', titulo = 'Encabezado' - @separador = separador - @titulo= titulo + def initialize + @titulo= 'Encabezado' @datos= {} valores_iniciales end diff --git a/lib/fm_layout/fm_seccion.rb b/lib/fm_layout/fm_seccion.rb index 93fed74..5b2afe7 100644 --- a/lib/fm_layout/fm_seccion.rb +++ b/lib/fm_layout/fm_seccion.rb @@ -9,7 +9,7 @@ def to_h end def to_s - separador = @separador ? @separador : '|' + separador = @separador || '|' salida = "[#{@titulo}]\r\n\r\n" @datos.each do |k,v| From 3419c1b0f20ed02310a21b9a0ddba1ab685429cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 9 Jan 2017 14:05:52 -0600 Subject: [PATCH 24/56] Small refactor Remove unnecessary methods from fm_layout --- lib/fm_layout/fm_layout.rb | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/fm_layout/fm_layout.rb b/lib/fm_layout/fm_layout.rb index 7143b56..a495147 100644 --- a/lib/fm_layout/fm_layout.rb +++ b/lib/fm_layout/fm_layout.rb @@ -132,15 +132,6 @@ def impuesto_retenido_local end end - def nomina - @nomina = Nomina::Nomina.new - if block_given? - yield(@nomina) - else - @nomina - end - end - def to_s salida = @encabezado.to_s + @datos_adicionales.to_s + @emisor.to_s + @domicilio_fiscal.to_s + @expedido_en.to_s + @receptor.to_s + @domicilio.to_s salida += @conceptos.map(&:to_s).reduce(:+).to_s @@ -148,7 +139,6 @@ def to_s salida += @impuestos_retenidos.map(&:to_s).reduce(:+).to_s salida += @impuestos_trasladados_locales.map(&:to_s).reduce(:+).to_s salida += @impuestos_retenidos_locales.map(&:to_s).reduce(:+).to_s - salida += @nomina.to_s salida end @@ -163,7 +153,6 @@ def to_h .merge(obtener_hash_conceptos) .merge(obtener_hash_traslados) .merge(obtener_hash_retenciones) - .merge(@nomina.to_h) .merge(obtener_hash_traslados_locales) .merge(obtener_hash_retenciones_locales) end From d28212218eef51c49b6814542e2f0d4a80e545bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 11 Jan 2017 14:37:46 -0600 Subject: [PATCH 25/56] Add support to separacion_indemnizacion comprobante_nomina 1.2 --- lib/fm_layout/nomina/nomina.rb | 22 +++++++++-- .../nomina/separacion_indemnizacion.rb | 31 +++++++++++++++ spec/fm_layout_nomina_spec.rb | 39 ++++++++++++++++++- 3 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 lib/fm_layout/nomina/separacion_indemnizacion.rb diff --git a/lib/fm_layout/nomina/nomina.rb b/lib/fm_layout/nomina/nomina.rb index d3fbf24..6b4ed0f 100644 --- a/lib/fm_layout/nomina/nomina.rb +++ b/lib/fm_layout/nomina/nomina.rb @@ -4,6 +4,7 @@ require 'fm_layout/nomina/incapacidad' require 'fm_layout/nomina/horas_extra' require 'fm_layout/nomina/jubilacion_pension_retiro' +require 'fm_layout/nomina/separacion_indemnizacion' require 'fm_layout/nomina/otro_pago' module FmLayout @@ -14,6 +15,7 @@ def initialize @complemento_nomina = ComplementoNomina.new @percepciones = [] @jubilacion_pension_retiro = [] + @separacion_indemnizacion = [] @deducciones = [] @incapacidades = [] @otro_pagos = [] @@ -52,6 +54,16 @@ def jubilacion_pension_retiro end end + def separacion_indemnizacion + separacion_indemnizacion = SeparacionIndemnizacion.new + if block_given? + yield(separacion_indemnizacion) + @separacion_indemnizacion << separacion_indemnizacion + else + separacion_indemnizacion + end + end + def deduccion @num_deduccion += 1 deduccion = Deduccion.new @num_deduccion @@ -86,11 +98,11 @@ def incapacidad end def to_h - { 'Nomina' => {}.merge( @complemento_nomina.to_h).merge(obtener_hash_percepciones).merge(obtener_hash_jubilacion_pension_retiro).merge(obtener_hash_deducciones).merge(obtener_hash_otro_pagos).merge(obtener_hash_incapacidades) } + { 'Nomina' => {}.merge( @complemento_nomina.to_h).merge(obtener_hash_percepciones).merge(obtener_hash_jubilacion_pension_retiro).merge(obtener_hash_separacion_indemnizacion).merge(obtener_hash_deducciones).merge(obtener_hash_otro_pagos).merge(obtener_hash_incapacidades) } end def to_s - @complemento_nomina.to_s + @percepciones.map(&:to_s).inject(:+).to_s + @jubilacion_pension_retiro.map(&:to_s).inject(:+).to_s + @deducciones.map(&:to_s).inject(:+).to_s + @otro_pagos.map(&:to_s).inject(:+).to_s + @incapacidades.map(&:to_s).inject(:+).to_s + @complemento_nomina.to_s + @percepciones.map(&:to_s).inject(:+).to_s + @jubilacion_pension_retiro.map(&:to_s).inject(:+).to_s + @separacion_indemnizacion.map(&:to_s).inject(:+).to_s + @deducciones.map(&:to_s).inject(:+).to_s + @otro_pagos.map(&:to_s).inject(:+).to_s + @incapacidades.map(&:to_s).inject(:+).to_s end private @@ -100,7 +112,11 @@ def obtener_hash_percepciones end def obtener_hash_jubilacion_pension_retiro - @jubilacion_pension_retiro.map(&:to_h).first + @jubilacion_pension_retiro.map(&:to_h).first || {} + end + + def obtener_hash_separacion_indemnizacion + @separacion_indemnizacion.map(&:to_h).first || {} end def obtener_hash_deducciones diff --git a/lib/fm_layout/nomina/separacion_indemnizacion.rb b/lib/fm_layout/nomina/separacion_indemnizacion.rb new file mode 100644 index 0000000..caef032 --- /dev/null +++ b/lib/fm_layout/nomina/separacion_indemnizacion.rb @@ -0,0 +1,31 @@ +module FmLayout + module Nomina + class SeparacionIndemnizacion + + include ::FmLayout::FmSeccionNomina + + def initialize + @titulo = 'SeparacionIndemnizacion' + @datos = {} + end + + def self.campos_vs_metodos + { + 'TotalPagado' => 'total_pagado', + 'NumAñosServicio' => 'numero_anios_servicio', + 'UltimoSueldoMensOrd' => 'ultimo_sueldo_mensual', + 'IngresoAcumulable' => 'ingreso_acumulable', + 'IngresoNoAcumulable' => 'ingreso_no_acumulable', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + end + end +end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index b111ed3..c3c2e88 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -100,12 +100,28 @@ p.precio_al_otorgarse 20 end + n.percepcion do |p| + p.tipo '022' + p.clave '022' + p.concepto 'Separacion Indemnizacion' + p.importe_gravado 3000 + p.importe_exento 0 + end + n.jubilacion_pension_retiro do |j| j.total_una_exhibicion 500 j.ingreso_acumulable 200 j.ingreso_no_acumulable 20 end + n.separacion_indemnizacion do |s| + s.total_pagado 10000 + s.numero_anios_servicio 2 + s.ultimo_sueldo_mensual 20000 + s.ingreso_acumulable 20000 + s.ingreso_no_acumulable 500 + end + n.deduccion do |d| d.tipo '002' d.clave '001' @@ -262,7 +278,7 @@ end context 'tercera percepcion' do - let(:percepcion) { nomina['Percepciones'].last['Percepcion#3'] } + let(:percepcion) { nomina['Percepciones'][2]['Percepcion#3'] } it { expect(percepcion['TipoPercepcion']).to eq('045')} it { expect(percepcion['Clave']).to eq('045')} @@ -272,8 +288,28 @@ it { expect(percepcion['AccionesOTitulos.ValorMercado']).to eq 200 } it { expect(percepcion['AccionesOTitulos.PrecioAlOtorgarse']).to eq 20 } end + + context 'cuarta percepcion' do + let(:percepcion) { nomina['Percepciones'][3]['Percepcion#4'] } + + it { expect(percepcion['TipoPercepcion']).to eq('022')} + it { expect(percepcion['Clave']).to eq('022')} + it { expect(percepcion['Concepto']).to eq('Separacion Indemnizacion')} + it { expect(percepcion['ImporteGravado']).to eq(3000.00)} + it { expect(percepcion['ImporteExento']).to eq(0.00)} + end end + context "Separación indemnizacion" do + let(:separacion) { nomina['SeparacionIndemnizacion'] } + + it { expect(separacion['TotalPagado']).to eq(10000) } + it { expect(separacion['NumAñosServicio']).to eq(2) } + it { expect(separacion['UltimoSueldoMensOrd']).to eq(20000) } + it { expect(separacion['IngresoAcumulable']).to eq(20000) } + it { expect(separacion['IngresoNoAcumulable']).to eq(500) } + end # context Separación indemnizacion + context 'jubilación pensión retiro' do let(:jubilacion) { nomina['JubilacionPensionRetiro']} @@ -368,6 +404,7 @@ it{ expect(salida).to match(/\[ComplementoNomina\]/) } it{ expect(salida).to match(/\[Percepcion#1\]/) } it{ expect(salida).to match(/\[JubilacionPensionRetiro\]/) } + it{ expect(salida).to match(/\[SeparacionIndemnizacion\]/) } it{ expect(salida).to match(/\[Deduccion#1\]/) } it{ expect(salida).to match(/\[Incapacidad#1\]/) } end From 1023147c30884ecbdc84f4b7cc011c4755f66bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 22 Feb 2017 19:30:00 -0600 Subject: [PATCH 26/56] Added support for ComplementoINE --- lib/fm_layout/complemento_ine.rb | 31 +++++++++++++++++++++++++++++++ lib/fm_layout/entidad_ine.rb | 28 ++++++++++++++++++++++++++++ lib/fm_layout/fm_layout.rb | 30 ++++++++++++++++++++++++++++++ spec/fm_layout_spec.rb | 11 +++++++++++ 4 files changed, 100 insertions(+) create mode 100644 lib/fm_layout/complemento_ine.rb create mode 100644 lib/fm_layout/entidad_ine.rb diff --git a/lib/fm_layout/complemento_ine.rb b/lib/fm_layout/complemento_ine.rb new file mode 100644 index 0000000..4d8523e --- /dev/null +++ b/lib/fm_layout/complemento_ine.rb @@ -0,0 +1,31 @@ +require 'fm_layout/fm_seccion' + +module FmLayout + class ComplementoIne + include FmSeccion + + def initialize separador = '|' + @separador = separador + @titulo = 'ComplementoINE' + @datos = {} + end + + def self.campos_vs_metodos + { + 'TipoProceso' => 'tipo_proceso', + 'TipoComite' => 'tipo_comite', + 'IdContabilidad' => 'id_contabilidad', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + private + + end +end diff --git a/lib/fm_layout/entidad_ine.rb b/lib/fm_layout/entidad_ine.rb new file mode 100644 index 0000000..809eda6 --- /dev/null +++ b/lib/fm_layout/entidad_ine.rb @@ -0,0 +1,28 @@ +require 'fm_layout/fm_seccion' + +module FmLayout + class EntidadINE + include FmSeccion + + def initialize + @titulo = 'Entidad' + @datos = {} + end + + def self.campos_vs_metodos + { + 'ClaveEntidad' => 'clave_entidad', + 'Ambito' => 'ambito', + 'IdContabilidad' => 'id_contabilidad', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + end +end diff --git a/lib/fm_layout/fm_layout.rb b/lib/fm_layout/fm_layout.rb index a495147..34b374b 100644 --- a/lib/fm_layout/fm_layout.rb +++ b/lib/fm_layout/fm_layout.rb @@ -8,6 +8,8 @@ require 'fm_layout/impuesto_trasladado_local' require 'fm_layout/impuesto_retenido' require 'fm_layout/impuesto_retenido_local' +require 'fm_layout/complemento_ine' +require 'fm_layout/entidad_ine' module FmLayout class FmLayout @@ -21,6 +23,7 @@ def initialize @impuestos_trasladados_locales = [] @impuestos_retenidos = [] @impuestos_retenidos_locales = [] + @entidades_ine = [] end def encabezado @@ -132,6 +135,25 @@ def impuesto_retenido_local end end + def complemento_ine + @complemento_ine = ComplementoIne.new + if block_given? + yield(@complemento_ine) + else + @complemento_ine + end + end + + def entidad_ine + entidad = EntidadINE.new + if block_given? + yield(entidad) + @entidades_ine << entidad + else + entidad + end + end + def to_s salida = @encabezado.to_s + @datos_adicionales.to_s + @emisor.to_s + @domicilio_fiscal.to_s + @expedido_en.to_s + @receptor.to_s + @domicilio.to_s salida += @conceptos.map(&:to_s).reduce(:+).to_s @@ -139,6 +161,8 @@ def to_s salida += @impuestos_retenidos.map(&:to_s).reduce(:+).to_s salida += @impuestos_trasladados_locales.map(&:to_s).reduce(:+).to_s salida += @impuestos_retenidos_locales.map(&:to_s).reduce(:+).to_s + salida += @complemento_ine.to_s + salida += @entidades_ine.map(&:to_s).reduce(:+).to_s salida end @@ -155,6 +179,8 @@ def to_h .merge(obtener_hash_retenciones) .merge(obtener_hash_traslados_locales) .merge(obtener_hash_retenciones_locales) + .merge(@complemento_ine.to_h) + .merge(obtener_hash_entidades_ine) end private @@ -178,5 +204,9 @@ def obtener_hash_traslados_locales def obtener_hash_retenciones_locales { 'ImpuestosRetenidosLocales' => @impuestos_retenidos_locales.map(&:to_h) } end + + def obtener_hash_entidades_ine + { 'EntidadesINE' => @entidades_ine.map(&:to_h) } + end end end diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index 090cd9e..cfeb58c 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -123,6 +123,15 @@ i.tasa 16.00 end + f.complemento_ine do |i| + i.tipo_proceso 'Ordinario' + i.tipo_comite 'Ejecutivo Estatal' + end + + f.entidad_ine do |e| + e.clave_entidad 'OAX' + e.id_contabilidad '000516' + end end end @@ -279,6 +288,8 @@ it{ expect(salida).to match(/\[ImpuestoRetenido\]/) } it{ expect(salida).to match(/\[TrasladoLocal\]/) } it{ expect(salida).to match(/\[RetencionLocal\]/) } + it{ expect(salida).to match(/\[ComplementoINE\]/) } + it{ expect(salida).to match(/\[Entidad\]/) } end end From 350abddfca3f4c386b2a4149907d70adb9a2772e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Thu, 23 Feb 2017 13:48:24 -0600 Subject: [PATCH 27/56] Completed test for complementoINE --- spec/fm_layout_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index cfeb58c..31d089d 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -274,6 +274,18 @@ it{ expect(retencion_local['TasadeRetencion']).to eq(16.00) } end + context 'ComplementoINE' do + let(:complementoINE){ prueba.to_h['ComplementoINE'] } + it{ expect(complementoINE['TipoProceso']).to eq('Ordinario') } + it{ expect(complementoINE['TipoComite']).to eq('Ejecutivo Estatal') } + end + + context 'ComplementoINE' do + let(:entidadesINE){ prueba.to_h['EntidadesINE'].first['Entidad'] } + it{ expect(entidadesINE['ClaveEntidad']).to eq('OAX') } + it{ expect(entidadesINE['IdContabilidad']).to eq('000516') } + end + context 'salida en texto' do let(:salida){ prueba.to_s } it{ expect(salida).to match(/\[Encabezado\]/) } From 016c98124cde31b1c21bd4d7ff14ca27a95129a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 6 Mar 2017 13:44:38 -0600 Subject: [PATCH 28/56] Add support for EntidadSNCF --- lib/fm_layout/entidad_sncf.rb | 26 ++++++++++++++++++++++++++ lib/fm_layout/fm_layout_nomina.rb | 13 ++++++++++++- spec/fm_layout_nomina_spec.rb | 13 +++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 lib/fm_layout/entidad_sncf.rb diff --git a/lib/fm_layout/entidad_sncf.rb b/lib/fm_layout/entidad_sncf.rb new file mode 100644 index 0000000..61807df --- /dev/null +++ b/lib/fm_layout/entidad_sncf.rb @@ -0,0 +1,26 @@ +module FmLayout + class EntidadSNCF + + include ::FmLayout::FmSeccionNomina + + def initialize + @titulo = "EntidadSNCF" + @datos = {} + end + + def self.campos_vs_metodos + { + 'OrigenRecurso' => 'origen_recurso', + 'MontoRecursoPropio' => 'monto_recurso_propio', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + end +end diff --git a/lib/fm_layout/fm_layout_nomina.rb b/lib/fm_layout/fm_layout_nomina.rb index 8eac2e5..7ae8691 100644 --- a/lib/fm_layout/fm_layout_nomina.rb +++ b/lib/fm_layout/fm_layout_nomina.rb @@ -1,5 +1,6 @@ require 'fm_layout/datos_adicionales' require 'fm_layout/emisor' +require 'fm_layout/entidad_sncf' require 'fm_layout/receptor' require 'fm_layout/concepto' require 'fm_layout/recibo_nomina' @@ -40,6 +41,15 @@ def emisor end end + def entidad_sncf + @entidad_sncf = EntidadSNCF.new + if block_given? + yield(@entidad_sncf) + else + @entidad_sncf + end + end + def receptor if block_given? yield(@receptor) @@ -69,7 +79,7 @@ def nomina end def to_s - salida = @recibo_nomina.to_s + @datos_adicionales.to_s + @emisor.to_s + @receptor.to_s + salida = @recibo_nomina.to_s + @datos_adicionales.to_s + @emisor.to_s + @entidad_sncf.to_s + @receptor.to_s salida += @conceptos.map(&:to_s).reduce(:+).to_s salida += @nomina.to_s salida @@ -79,6 +89,7 @@ def to_h recibo_nomina.to_h .merge(@datos_adicionales.to_h) .merge(@emisor.to_h) + .merge(@entidad_sncf.to_h) .merge(@expedido_en.to_h) .merge(@receptor.to_h) .merge(obtener_hash_conceptos) diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index c3c2e88..43766b7 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -33,6 +33,11 @@ e.regimen '612' end + f.entidad_sncf do |e| + e.origen_recurso 'IM' + e.monto_recurso_propio 750 + end + f.receptor do |r| r.rfc 'XAXX010101000' r.nombre 'RAMIREZ MARTINEZ JUAN JOSE' @@ -205,6 +210,13 @@ it{ expect(emisor['Regimen']).to eq('612') } end + context 'entidad_sncf' do + let(:entidad){ prueba.to_h['EntidadSNCF'] } + + it{ expect(entidad['OrigenRecurso']).to eq('IM') } + it{ expect(entidad['MontoRecursoPropio']).to eq(750) } + end + context 'receptor' do let(:receptor){ prueba.to_h['Receptor'] } @@ -399,6 +411,7 @@ it{ expect(salida).to match(/\[ReciboNomina\]/) } it{ expect(salida).to match(/\[Datos Adicionales\]/) } it{ expect(salida).to match(/\[Emisor\]/) } + it{ expect(salida).to match(/\[EntidadSNCF\]/) } it{ expect(salida).to match(/\[Receptor\]/) } it{ expect(salida).to match(/\[Concepto#1\]/) } it{ expect(salida).to match(/\[ComplementoNomina\]/) } From d24652a2c36139b97ffdc84948ac92056e93cd0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Mon, 15 May 2017 14:57:04 -0500 Subject: [PATCH 29/56] Fixing compensacion_saldo_a_favor The brackets are unnecessary --- lib/fm_layout/nomina/otro_pago.rb | 6 +++--- spec/fm_layout_nomina_spec.rb | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/fm_layout/nomina/otro_pago.rb b/lib/fm_layout/nomina/otro_pago.rb index 5e83d68..290888b 100644 --- a/lib/fm_layout/nomina/otro_pago.rb +++ b/lib/fm_layout/nomina/otro_pago.rb @@ -32,15 +32,15 @@ def subsidio_causado dato end def saldo dato - @datos["CompensacionSaldosAFavor.SaldoAFavor"] = "[#{dato}]" + @datos["CompensacionSaldosAFavor.SaldoAFavor"] = dato end def anio dato - @datos["CompensacionSaldosAFavor.Año"] = "[#{dato}]" + @datos["CompensacionSaldosAFavor.Año"] = dato end def remanente_saldo dato - @datos["CompensacionSaldosAFavor.RemanenteSalFav"] = "[#{dato}]" + @datos["CompensacionSaldosAFavor.RemanenteSalFav"] = dato end end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 43766b7..98a4452 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -378,9 +378,9 @@ it { expect(otro_pago['Clave']).to eq '004' } it { expect(otro_pago['Concepto']).to eq 'Un concepto' } it { expect(otro_pago['Importe']).to eq 350.5 } - it { expect(otro_pago['CompensacionSaldosAFavor.SaldoAFavor']).to eq "[200.0]" } - it { expect(otro_pago['CompensacionSaldosAFavor.Año']).to eq "[2016]" } - it { expect(otro_pago['CompensacionSaldosAFavor.RemanenteSalFav']).to eq "[100.0]" } + it { expect(otro_pago['CompensacionSaldosAFavor.SaldoAFavor']).to eq 200.0 } + it { expect(otro_pago['CompensacionSaldosAFavor.Año']).to eq 2016 } + it { expect(otro_pago['CompensacionSaldosAFavor.RemanenteSalFav']).to eq 100.0 } end # context segundo otro pago context "tercer otro pago" do From 189abfeea42facbfa4eb4ea024cf3f233b386cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Tue, 27 Jun 2017 16:27:16 -0500 Subject: [PATCH 30/56] Enable support for cfdi 3.3 --- Gemfile | 1 + lib/fm_layout/complemento_ine.rb | 3 +- lib/fm_layout/comprobante_fiscal_digital.rb | 53 +++ lib/fm_layout/concepto.rb | 68 ++- lib/fm_layout/datos_adicionales.rb | 5 +- lib/fm_layout/emisor.rb | 14 +- lib/fm_layout/entidad_sncf.rb | 2 +- lib/fm_layout/fm_layout.rb | 61 ++- lib/fm_layout/fm_layout_nomina.rb | 11 +- lib/fm_layout/fm_seccion.rb | 16 - lib/fm_layout/impuesto_retenido.rb | 40 +- lib/fm_layout/impuesto_retenido_local.rb | 31 +- lib/fm_layout/impuesto_trasladado.rb | 41 +- lib/fm_layout/impuesto_trasladado_local.rb | 31 +- lib/fm_layout/nomina/complemento_nomina.rb | 2 +- lib/fm_layout/nomina/concepto.rb | 40 ++ lib/fm_layout/nomina/deduccion.rb | 2 +- lib/fm_layout/nomina/emisor.rb | 39 ++ lib/fm_layout/nomina/horas_extra.rb | 2 +- lib/fm_layout/nomina/incapacidad.rb | 2 +- .../nomina/jubilacion_pension_retiro.rb | 2 +- lib/fm_layout/nomina/nomina.rb | 3 + lib/fm_layout/nomina/otro_pago.rb | 2 +- lib/fm_layout/nomina/percepcion.rb | 2 +- lib/fm_layout/nomina/receptor.rb | 45 ++ .../nomina/separacion_indemnizacion.rb | 2 +- lib/fm_layout/parte.rb | 53 +++ lib/fm_layout/receptor.rb | 26 +- spec/fm_layout_nomina_spec.rb | 4 +- spec/fm_layout_spec.rb | 398 +++++++++--------- 30 files changed, 647 insertions(+), 354 deletions(-) create mode 100644 lib/fm_layout/comprobante_fiscal_digital.rb create mode 100644 lib/fm_layout/nomina/concepto.rb create mode 100644 lib/fm_layout/nomina/emisor.rb create mode 100644 lib/fm_layout/nomina/receptor.rb create mode 100644 lib/fm_layout/parte.rb diff --git a/Gemfile b/Gemfile index 893a299..07fa574 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,7 @@ source 'https://rubygems.org' gem 'coveralls', require: false +gem 'pry' # Specify your gem's dependencies in fm_layout.gemspec gemspec diff --git a/lib/fm_layout/complemento_ine.rb b/lib/fm_layout/complemento_ine.rb index 4d8523e..fa476ae 100644 --- a/lib/fm_layout/complemento_ine.rb +++ b/lib/fm_layout/complemento_ine.rb @@ -4,8 +4,7 @@ module FmLayout class ComplementoIne include FmSeccion - def initialize separador = '|' - @separador = separador + def initialize @titulo = 'ComplementoINE' @datos = {} end diff --git a/lib/fm_layout/comprobante_fiscal_digital.rb b/lib/fm_layout/comprobante_fiscal_digital.rb new file mode 100644 index 0000000..af9010c --- /dev/null +++ b/lib/fm_layout/comprobante_fiscal_digital.rb @@ -0,0 +1,53 @@ +require 'fm_layout/fm_seccion' +module FmLayout + class ComprobanteFiscalDigital + include FmSeccion + + def initialize + @titulo= 'ComprobanteFiscalDigital' + @datos= {} + valores_iniciales + end + + def self.campos_vs_metodos + { + 'Serie' => 'serie', + 'Folio' => 'folio', + 'Fecha' => 'fecha', + 'FormaPago' => 'forma_de_pago', + 'NoCertificado' => 'numero_de_certificado', + 'CondicionesDePago' => 'condiciones_de_pago', + 'SubTotal' => 'subtotal', + 'Descuento' => 'descuento', + 'Moneda' => 'moneda', + 'Total' => 'total', + 'TipoDeComprobante' => 'tipo_de_comprobante', + 'MetodoPago' => 'metodo_de_pago', + 'LugarExpedicion' => 'lugar_de_expedicion', + 'TipoCambio' => 'tipo_de_cambio' + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + + private + + def valores_iniciales + @datos['Version'] = '3.3' + @datos['Fecha'] = 'asignarFecha' + @datos['Folio'] = 'asignarFolio' + #@datos['NumCtaPago'] = 'No identificado' + @datos['NoCertificado'] = nil + @datos['SubTotal'] = nil + @datos['Descuento'] = nil + @datos['Total'] = nil + end + end + +end diff --git a/lib/fm_layout/concepto.rb b/lib/fm_layout/concepto.rb index 5094898..a4e4b6c 100644 --- a/lib/fm_layout/concepto.rb +++ b/lib/fm_layout/concepto.rb @@ -1,28 +1,73 @@ require 'fm_layout/fm_seccion' +require 'fm_layout/parte' module FmLayout class Concepto include FmSeccion - def initialize separador, num_concepto - @separador = separador - @titulo = num_concepto ? "Concepto##{num_concepto}" : 'Concepto' + def initialize num_concepto + @titulo = "Concepto##{num_concepto}" @datos = {} valores_iniciales + @impuesto_t = ImpuestoTrasladado.new + @impuesto_r = ImpuestoRetenido.new + @parte = Parte.new end def self.campos_vs_metodos { - 'cantidad' => 'cantidad', - 'unidad' => 'unidad', - 'noIdentificacion' => 'numero_de_identificacion', - 'descripcion' => 'descripcion', - 'valorUnitario' => 'valor_unitario', - 'importe' => 'importe', + 'ClaveProdServ' => 'clave_producto_servicio', + 'NoIdentificacion' => 'numero_de_identificacion', + 'Cantidad' => 'cantidad', + 'ClaveUnidad' => 'clave_unidad', + 'Unidad' => 'unidad', + 'Descripcion' => 'descripcion', + 'ValorUnitario' => 'valor_unitario', + 'Importe' => 'importe', + 'Descuento' => 'descuento', 'CuentaPredial' => 'cuenta_predial', } end + def partes + if block_given? + yield @parte + @datos["Parte.ClaveProdServ"] = @parte.datos["ClaveProdServ"] + @datos["Parte.NoIdentificacion"] = @parte.datos["NoIdentificacion"] + @datos["Parte.Cantidad"] = @parte.datos["Cantidad"] + @datos["Parte.Unidad"] = @parte.datos["Unidad"] + @datos["Parte.Descripcion"] = @parte.datos["Descripcion"] + else + @parte + end + end + + def impuesto_trasladado + if block_given? + yield @impuesto_t + @datos["Impuestos.Traslados.Base"] = @impuesto_t.datos["Base"] + @datos["Impuestos.Traslados.Impuesto"] = @impuesto_t.datos["Impuesto"] + @datos["Impuestos.Traslados.TipoFactor"] = @impuesto_t.datos["TipoFactor"] + @datos["Impuestos.Traslados.TasaOCuota"] = @impuesto_t.datos["TasaOCuota"] + @datos["Impuestos.Traslados.Importe"] = @impuesto_t.datos["Importe"] + else + @impuesto_t + end + end + + def impuesto_retenido + if block_given? + yield @impuesto_r + @datos["Impuestos.Retenciones.Base"] = @impuesto_r.datos["Base"] + @datos["Impuestos.Retenciones.Impuesto"] = @impuesto_r.datos["Impuesto"] + @datos["Impuestos.Retenciones.TipoFactor"] = @impuesto_r.datos["TipoFactor"] + @datos["Impuestos.Retenciones.TasaOCuota"] = @impuesto_r.datos["TasaOCuota"] + @datos["Impuestos.Retenciones.Importe"] = @impuesto_r.datos["Importe"] + else + @impuesto_r + end + end + # Creación de los métodos de acceso dinámicamente campos_vs_metodos.each do |campo, metodo| define_method(metodo) do |dato| @@ -33,9 +78,8 @@ def self.campos_vs_metodos private def valores_iniciales - @datos['cantidad'] = 1 - @datos['unidad'] = 'ACT' - @datos['descripcion'] = 'Pago de nómina' + @datos['Cantidad'] = 1 + @datos['Unidad'] = 'ACT' end end end diff --git a/lib/fm_layout/datos_adicionales.rb b/lib/fm_layout/datos_adicionales.rb index 03fce32..d38a3b7 100644 --- a/lib/fm_layout/datos_adicionales.rb +++ b/lib/fm_layout/datos_adicionales.rb @@ -4,9 +4,8 @@ module FmLayout class DatosAdicionales include FmSeccion - def initialize separador = '|' - @separador = separador - @titulo = "Datos Adicionales" + def initialize + @titulo = "DatosAdicionales" @datos= {} valores_iniciales end diff --git a/lib/fm_layout/emisor.rb b/lib/fm_layout/emisor.rb index 6835c7f..4111bda 100644 --- a/lib/fm_layout/emisor.rb +++ b/lib/fm_layout/emisor.rb @@ -4,8 +4,7 @@ module FmLayout class Emisor include FmSeccion - def initialize separador = '|' - @separador = separador + def initialize @titulo = 'Emisor' @datos = {} valores_iniciales @@ -13,12 +12,9 @@ def initialize separador = '|' def self.campos_vs_metodos { - 'rfc' => 'rfc', - 'nombre' => 'nombre', - 'Regimen' => 'regimen', + 'Rfc' => 'rfc', + 'Nombre' => 'nombre', 'RegimenFiscal' => 'regimen_fiscal', - 'Curp' => 'curp', - 'RegistroPatronal' => 'registro_patronal', } end @@ -32,8 +28,8 @@ def self.campos_vs_metodos private def valores_iniciales - @datos['rfc'] = nil - @datos['nombre'] = nil + @datos['Rfc'] = nil + @datos['Nombre'] = nil end end diff --git a/lib/fm_layout/entidad_sncf.rb b/lib/fm_layout/entidad_sncf.rb index 61807df..5a38120 100644 --- a/lib/fm_layout/entidad_sncf.rb +++ b/lib/fm_layout/entidad_sncf.rb @@ -1,7 +1,7 @@ module FmLayout class EntidadSNCF - include ::FmLayout::FmSeccionNomina + include ::FmLayout::FmSeccion def initialize @titulo = "EntidadSNCF" diff --git a/lib/fm_layout/fm_layout.rb b/lib/fm_layout/fm_layout.rb index 34b374b..02d6197 100644 --- a/lib/fm_layout/fm_layout.rb +++ b/lib/fm_layout/fm_layout.rb @@ -1,4 +1,4 @@ -require 'fm_layout/encabezado' +require 'fm_layout/comprobante_fiscal_digital' require 'fm_layout/datos_adicionales' require 'fm_layout/emisor' require 'fm_layout/receptor' @@ -14,16 +14,18 @@ module FmLayout class FmLayout def initialize - @encabezado = Encabezado.new + @encabezado = ComprobanteFiscalDigital.new @datos_adicionales = DatosAdicionales.new @emisor = Emisor.new @receptor= Receptor.new @conceptos = [] - @impuestos_trasladados = [] - @impuestos_trasladados_locales = [] - @impuestos_retenidos = [] - @impuestos_retenidos_locales = [] - @entidades_ine = [] + @entidades_ine = [] + @num_concepto = 0 + + @impuesto_trasladado = ImpuestoTrasladado.new + @impuesto_retenido = ImpuestoRetenido.new + @impuesto_trasladado_local = ImpuestoTrasladadoLocal.new + @impuesto_retenido_local = ImpuestoRetenidoLocal.new end def encabezado @@ -86,7 +88,8 @@ def expedido_en end def concepto - concepto = Concepto.new '|', nil + @num_concepto += 1 + concepto = Concepto.new @num_concepto if block_given? yield(concepto) @conceptos << concepto @@ -96,42 +99,34 @@ def concepto end def impuesto_trasladado - impuesto = ImpuestoTrasladado.new if block_given? - yield(impuesto) - @impuestos_trasladados << impuesto + yield(@impuesto_trasladado) else - impuesto + @impuesto_trasladado end end def impuesto_trasladado_local - impuesto = ImpuestoTrasladadoLocal.new if block_given? - yield(impuesto) - @impuestos_trasladados_locales << impuesto + yield(@impuesto_trasladado_local) else - impuesto + @impuesto_trasladado_local end end def impuesto_retenido - impuesto = ImpuestoRetenido.new if block_given? - yield(impuesto) - @impuestos_retenidos << impuesto + yield(@impuesto_retenido) else - impuesto + @impuesto_retenido end end - def impuesto_retenido_local - impuesto = ImpuestoRetenidoLocal.new + def impuesto_retenido_local if block_given? - yield(impuesto) - @impuestos_retenidos_locales << impuesto + yield(@impuesto_retenido_local) else - impuesto + @impuesto_retenido_local end end @@ -157,10 +152,10 @@ def entidad_ine def to_s salida = @encabezado.to_s + @datos_adicionales.to_s + @emisor.to_s + @domicilio_fiscal.to_s + @expedido_en.to_s + @receptor.to_s + @domicilio.to_s salida += @conceptos.map(&:to_s).reduce(:+).to_s - salida += @impuestos_trasladados.map(&:to_s).reduce(:+).to_s - salida += @impuestos_retenidos.map(&:to_s).reduce(:+).to_s - salida += @impuestos_trasladados_locales.map(&:to_s).reduce(:+).to_s - salida += @impuestos_retenidos_locales.map(&:to_s).reduce(:+).to_s + salida += @impuesto_trasladado.to_s if @impuesto_trasladado.con_impuestos? + salida += @impuesto_retenido.to_s if @impuesto_retenido.con_impuestos? + salida += @impuesto_trasladado_local.to_s if @impuesto_trasladado_local.con_impuestos? + salida += @impuesto_retenido_local.to_s if @impuesto_retenido_local.con_impuestos? salida += @complemento_ine.to_s salida += @entidades_ine.map(&:to_s).reduce(:+).to_s salida @@ -190,19 +185,19 @@ def obtener_hash_conceptos end def obtener_hash_retenciones - {'ImpuestosRetenidos' => @impuestos_retenidos.map(&:to_h) } + {'ImpuestosRetenidos' => @impuesto_retenido.to_h } end def obtener_hash_traslados - { 'ImpuestosTrasladados' => @impuestos_trasladados.map(&:to_h) } + { 'ImpuestosTrasladados' => @impuesto_trasladado.to_h } end def obtener_hash_traslados_locales - { 'ImpuestosTrasladadosLocales' => @impuestos_trasladados_locales.map(&:to_h) } + { 'ImpuestosTrasladadosLocales' => @impuesto_trasladado_local.to_h } end def obtener_hash_retenciones_locales - { 'ImpuestosRetenidosLocales' => @impuestos_retenidos_locales.map(&:to_h) } + { 'ImpuestosRetenidosLocales' => @impuesto_retenido_local.to_h } end def obtener_hash_entidades_ine diff --git a/lib/fm_layout/fm_layout_nomina.rb b/lib/fm_layout/fm_layout_nomina.rb index 7ae8691..ac7e830 100644 --- a/lib/fm_layout/fm_layout_nomina.rb +++ b/lib/fm_layout/fm_layout_nomina.rb @@ -1,8 +1,5 @@ require 'fm_layout/datos_adicionales' -require 'fm_layout/emisor' require 'fm_layout/entidad_sncf' -require 'fm_layout/receptor' -require 'fm_layout/concepto' require 'fm_layout/recibo_nomina' require 'fm_layout/nomina/nomina' @@ -10,9 +7,9 @@ module FmLayout class FmLayoutNomina def initialize @recibo_nomina = ReciboNomina.new - @datos_adicionales = DatosAdicionales.new('=') - @emisor = Emisor.new('=') - @receptor= Receptor.new('=') + @datos_adicionales = DatosAdicionales.new + @emisor = Nomina::Emisor.new + @receptor= Nomina::Receptor.new @conceptos = [] @num_concepto = 0 end @@ -60,7 +57,7 @@ def receptor def concepto @num_concepto += 1 - concepto = Concepto.new('=', @num_concepto) + concepto = Nomina::Concepto.new(@num_concepto) if block_given? yield(concepto) @conceptos << concepto diff --git a/lib/fm_layout/fm_seccion.rb b/lib/fm_layout/fm_seccion.rb index 5b2afe7..ac11f34 100644 --- a/lib/fm_layout/fm_seccion.rb +++ b/lib/fm_layout/fm_seccion.rb @@ -8,21 +8,6 @@ def to_h { @titulo => @datos } end - def to_s - separador = @separador || '|' - - salida = "[#{@titulo}]\r\n\r\n" - @datos.each do |k,v| - salida += "#{k}#{separador}#{v}\r\n" - end - salida += "\r\n" - salida - end - end - - module FmSeccionNomina - include FmSeccion - def to_s salida = "[#{@titulo}]\r\n\r\n" @datos.each do |k,v| @@ -32,5 +17,4 @@ def to_s salida end end - end diff --git a/lib/fm_layout/impuesto_retenido.rb b/lib/fm_layout/impuesto_retenido.rb index 74dccf2..eeabe3b 100644 --- a/lib/fm_layout/impuesto_retenido.rb +++ b/lib/fm_layout/impuesto_retenido.rb @@ -3,16 +3,22 @@ module FmLayout class ImpuestoRetenido include FmSeccion + attr_reader :datos + attr_accessor :arr_base, :arr_impuesto, :arr_tipo_factor, :arr_tasa_o_cuota, :arr_importe def initialize - @titulo = 'ImpuestoRetenido' + @titulo = 'Retenciones' + @arr_base = [] + @arr_impuesto = [] + @arr_tipo_factor = [] + @arr_tasa_o_cuota = [] + @arr_importe = [] @datos = {} end def self.campos_vs_metodos { - 'impuesto' => 'impuesto', - 'importe' => 'importe', + 'TotalImpuestosRetenidos' => 'total_impuestos', } end @@ -23,5 +29,33 @@ def self.campos_vs_metodos end end + def base value + arr_base.push value + @datos["Base"] = "[#{arr_base.join(',')}]" + end + + def impuesto value + arr_impuesto.push value + @datos["Impuesto"] = "[#{arr_impuesto.join(',')}]" + end + + def tipo_factor value + arr_tipo_factor.push value + @datos["TipoFactor"] = "[#{arr_tipo_factor.join(',')}]" + end + + def tasa_o_cuota value + arr_tasa_o_cuota.push value + @datos["TasaOCuota"] = "[#{arr_tasa_o_cuota.join(',')}]" + end + + def importe value + arr_importe.push value + @datos["Importe"] = "[#{arr_importe.join(',')}]" + end + + def con_impuestos? + @datos.any? + end end end diff --git a/lib/fm_layout/impuesto_retenido_local.rb b/lib/fm_layout/impuesto_retenido_local.rb index a354607..27fb32c 100644 --- a/lib/fm_layout/impuesto_retenido_local.rb +++ b/lib/fm_layout/impuesto_retenido_local.rb @@ -3,26 +3,33 @@ module FmLayout class ImpuestoRetenidoLocal include FmSeccion + attr_accessor :arr_impuesto, :arr_tasa, :arr_importe def initialize - @titulo = 'RetencionLocal' + @titulo = 'RetencionesLocales' + @arr_impuesto = [] + @arr_tasa = [] + @arr_importe = [] @datos = {} end - def self.campos_vs_metodos - { - 'ImpLocRetenido' => 'impuesto', - 'Importe' => 'importe', - 'TasadeRetencion' => 'tasa', - } + def impuesto value + arr_impuesto.push value + @datos["ImpLocRetenido"] = "[#{arr_impuesto.join(',')}]" end - # Creación de los métodos de acceso dinámicamente - campos_vs_metodos.each do |campo, metodo| - define_method(metodo) do |dato| - @datos[campo] = dato - end + def tasa value + arr_tasa.push value + @datos["TasadeRetencion"] = "[#{arr_tasa.join(',')}]" end + def importe value + arr_importe.push value + @datos["Importe"] = "[#{arr_importe.join(',')}]" + end + + def con_impuestos? + @datos.any? + end end end diff --git a/lib/fm_layout/impuesto_trasladado.rb b/lib/fm_layout/impuesto_trasladado.rb index d802d6c..b9c0bc8 100644 --- a/lib/fm_layout/impuesto_trasladado.rb +++ b/lib/fm_layout/impuesto_trasladado.rb @@ -3,17 +3,22 @@ module FmLayout class ImpuestoTrasladado include FmSeccion + attr_reader :datos + attr_accessor :arr_base, :arr_impuesto, :arr_tipo_factor, :arr_tasa_o_cuota, :arr_importe def initialize - @titulo = 'ImpuestoTrasladado' + @titulo = 'Traslados' + @arr_base = [] + @arr_impuesto = [] + @arr_tipo_factor = [] + @arr_tasa_o_cuota = [] + @arr_importe = [] @datos = {} end def self.campos_vs_metodos { - 'impuesto' => 'impuesto', - 'importe' => 'importe', - 'tasa' => 'tasa', + 'TotalImpuestosTrasladados' => 'total_impuestos', } end @@ -24,5 +29,33 @@ def self.campos_vs_metodos end end + def base value + arr_base.push value + @datos["Base"] = "[#{arr_base.join(',')}]" + end + + def impuesto value + arr_impuesto.push value + @datos["Impuesto"] = "[#{arr_impuesto.join(',')}]" + end + + def tipo_factor value + arr_tipo_factor.push value + @datos["TipoFactor"] = "[#{arr_tipo_factor.join(',')}]" + end + + def tasa_o_cuota value + arr_tasa_o_cuota.push value + @datos["TasaOCuota"] = "[#{arr_tasa_o_cuota.join(',')}]" + end + + def importe value + arr_importe.push value + @datos["Importe"] = "[#{arr_importe.join(',')}]" + end + + def con_impuestos? + @datos.any? + end end end diff --git a/lib/fm_layout/impuesto_trasladado_local.rb b/lib/fm_layout/impuesto_trasladado_local.rb index 7c2499c..29c0b34 100644 --- a/lib/fm_layout/impuesto_trasladado_local.rb +++ b/lib/fm_layout/impuesto_trasladado_local.rb @@ -3,26 +3,33 @@ module FmLayout class ImpuestoTrasladadoLocal include FmSeccion + attr_accessor :arr_impuesto, :arr_tasa, :arr_importe def initialize - @titulo = 'TrasladoLocal' + @titulo = 'TrasladosLocales' + @arr_impuesto = [] + @arr_tasa = [] + @arr_importe = [] @datos = {} end - def self.campos_vs_metodos - { - 'ImpLocTrasladado' => 'impuesto', - 'Importe' => 'importe', - 'TasadeTraslado' => 'tasa', - } + def impuesto value + arr_impuesto.push value + @datos["ImpLocTrasladado"] = "[#{arr_impuesto.join(',')}]" end - # Creación de los métodos de acceso dinámicamente - campos_vs_metodos.each do |campo, metodo| - define_method(metodo) do |dato| - @datos[campo] = dato - end + def tasa value + arr_tasa.push value + @datos["TasadeTraslado"] = "[#{arr_tasa.join(',')}]" end + def importe value + arr_importe.push value + @datos["Importe"] = "[#{arr_importe.join(',')}]" + end + + def con_impuestos? + @datos.any? + end end end diff --git a/lib/fm_layout/nomina/complemento_nomina.rb b/lib/fm_layout/nomina/complemento_nomina.rb index 4299ea6..6af9212 100644 --- a/lib/fm_layout/nomina/complemento_nomina.rb +++ b/lib/fm_layout/nomina/complemento_nomina.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class ComplementoNomina - include ::FmLayout::FmSeccionNomina + include ::FmLayout::FmSeccion def initialize @titulo= 'ComplementoNomina' diff --git a/lib/fm_layout/nomina/concepto.rb b/lib/fm_layout/nomina/concepto.rb new file mode 100644 index 0000000..cdbe27b --- /dev/null +++ b/lib/fm_layout/nomina/concepto.rb @@ -0,0 +1,40 @@ +module FmLayout + module Nomina + class Concepto + include ::FmLayout::FmSeccion + + def initialize num_concepto + @titulo = "Concepto##{num_concepto}" + @datos = {} + valores_iniciales + end + + def self.campos_vs_metodos + { + 'cantidad' => 'cantidad', + 'unidad' => 'unidad', + 'noIdentificacion' => 'numero_de_identificacion', + 'descripcion' => 'descripcion', + 'valorUnitario' => 'valor_unitario', + 'importe' => 'importe', + 'CuentaPredial' => 'cuenta_predial', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + private + + def valores_iniciales + @datos['cantidad'] = 1 + @datos['unidad'] = 'ACT' + @datos['descripcion'] = 'Pago de nómina' + end + end + end +end diff --git a/lib/fm_layout/nomina/deduccion.rb b/lib/fm_layout/nomina/deduccion.rb index 09c9f87..fc5f497 100644 --- a/lib/fm_layout/nomina/deduccion.rb +++ b/lib/fm_layout/nomina/deduccion.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class Deduccion - include ::FmLayout::FmSeccionNomina + include ::FmLayout::FmSeccion def initialize num_deduccion @titulo = "Deduccion##{num_deduccion}" diff --git a/lib/fm_layout/nomina/emisor.rb b/lib/fm_layout/nomina/emisor.rb new file mode 100644 index 0000000..b203af0 --- /dev/null +++ b/lib/fm_layout/nomina/emisor.rb @@ -0,0 +1,39 @@ +module FmLayout + module Nomina + class Emisor + include ::FmLayout::FmSeccion + + def initialize + @titulo = 'Emisor' + @datos = {} + valores_iniciales + end + + def self.campos_vs_metodos + { + 'rfc' => 'rfc', + 'nombre' => 'nombre', + 'Regimen' => 'regimen', + 'RegimenFiscal' => 'regimen_fiscal', + 'Curp' => 'curp', + 'RegistroPatronal' => 'registro_patronal', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + private + + def valores_iniciales + @datos['rfc'] = nil + @datos['nombre'] = nil + end + + end + end +end diff --git a/lib/fm_layout/nomina/horas_extra.rb b/lib/fm_layout/nomina/horas_extra.rb index c05f332..a7ea2e1 100644 --- a/lib/fm_layout/nomina/horas_extra.rb +++ b/lib/fm_layout/nomina/horas_extra.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class HorasExtra - include ::FmLayout::FmSeccionNomina + include ::FmLayout::FmSeccion attr_reader :datos def initialize diff --git a/lib/fm_layout/nomina/incapacidad.rb b/lib/fm_layout/nomina/incapacidad.rb index 938f30b..bda167b 100644 --- a/lib/fm_layout/nomina/incapacidad.rb +++ b/lib/fm_layout/nomina/incapacidad.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class Incapacidad - include ::FmLayout::FmSeccionNomina + include ::FmLayout::FmSeccion def initialize num_incapacidad @titulo = "Incapacidad##{num_incapacidad}" diff --git a/lib/fm_layout/nomina/jubilacion_pension_retiro.rb b/lib/fm_layout/nomina/jubilacion_pension_retiro.rb index 82e3bb6..cbcddf4 100644 --- a/lib/fm_layout/nomina/jubilacion_pension_retiro.rb +++ b/lib/fm_layout/nomina/jubilacion_pension_retiro.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class JubilacionPensionRetiro - include ::FmLayout::FmSeccionNomina + include ::FmLayout::FmSeccion def initialize @titulo = 'JubilacionPensionRetiro' diff --git a/lib/fm_layout/nomina/nomina.rb b/lib/fm_layout/nomina/nomina.rb index 6b4ed0f..5488ad1 100644 --- a/lib/fm_layout/nomina/nomina.rb +++ b/lib/fm_layout/nomina/nomina.rb @@ -1,3 +1,6 @@ +require 'fm_layout/nomina/emisor' +require 'fm_layout/nomina/receptor' +require 'fm_layout/nomina/concepto' require 'fm_layout/nomina/complemento_nomina' require 'fm_layout/nomina/percepcion' require 'fm_layout/nomina/deduccion' diff --git a/lib/fm_layout/nomina/otro_pago.rb b/lib/fm_layout/nomina/otro_pago.rb index 290888b..a684bdb 100644 --- a/lib/fm_layout/nomina/otro_pago.rb +++ b/lib/fm_layout/nomina/otro_pago.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class OtroPago - include ::FmLayout::FmSeccionNomina + include ::FmLayout::FmSeccion attr_reader :datos def initialize num_pago diff --git a/lib/fm_layout/nomina/percepcion.rb b/lib/fm_layout/nomina/percepcion.rb index 1a730de..d5701d2 100644 --- a/lib/fm_layout/nomina/percepcion.rb +++ b/lib/fm_layout/nomina/percepcion.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class Percepcion - include ::FmLayout::FmSeccionNomina + include ::FmLayout::FmSeccion def initialize num_percepcion @titulo= "Percepcion##{num_percepcion}" diff --git a/lib/fm_layout/nomina/receptor.rb b/lib/fm_layout/nomina/receptor.rb new file mode 100644 index 0000000..3b63fd3 --- /dev/null +++ b/lib/fm_layout/nomina/receptor.rb @@ -0,0 +1,45 @@ +module FmLayout + module Nomina + class Receptor + include ::FmLayout::FmSeccion + + def initialize + @titulo = 'Receptor' + @datos = {} + end + + def self.campos_vs_metodos + { + 'rfc' => 'rfc', + 'nombre' => 'nombre', + 'Curp' => 'curp', + 'NumSeguridadSocial' => 'numero_seguridad_social', + 'FechaInicioRelLaboral' => 'fecha_inicio_relacion_laboral', + 'Antigüedad' => 'antiguedad', + 'TipoContrato' => 'tipo_contrato', + 'TipoJornada' => 'tipo_jornada', + 'TipoRegimen' => 'tipo_regimen', + 'NumEmpleado' => 'numero_empleado', + 'Departamento' => 'departamento', + 'Puesto' => 'puesto', + 'RiesgoPuesto' => 'riesgo_puesto', + 'PeriodicidadPago' => 'periodicidad_pago', + 'Banco' => 'banco', + 'CuentaBancaria' => 'cuenta_bancaria', + 'SalarioBaseCotApor' => 'salario_base', + 'SalarioDiarioIntegrado' => 'salario_diario_integrado', + 'ClaveEntFed' => 'clave_entidad_federativa', + 'emailCliente' => 'email', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + end + end +end diff --git a/lib/fm_layout/nomina/separacion_indemnizacion.rb b/lib/fm_layout/nomina/separacion_indemnizacion.rb index caef032..65ed673 100644 --- a/lib/fm_layout/nomina/separacion_indemnizacion.rb +++ b/lib/fm_layout/nomina/separacion_indemnizacion.rb @@ -2,7 +2,7 @@ module FmLayout module Nomina class SeparacionIndemnizacion - include ::FmLayout::FmSeccionNomina + include ::FmLayout::FmSeccion def initialize @titulo = 'SeparacionIndemnizacion' diff --git a/lib/fm_layout/parte.rb b/lib/fm_layout/parte.rb new file mode 100644 index 0000000..f38f3ee --- /dev/null +++ b/lib/fm_layout/parte.rb @@ -0,0 +1,53 @@ +require 'fm_layout/fm_seccion' + +module FmLayout + class Parte + include FmSeccion + attr_reader :datos + attr_accessor :arr_clave, :arr_no_identificacion, :arr_cantidad, :arr_unidad, :arr_descripcion + + def initialize + @arr_clave = [] + @arr_no_identificacion = [] + @arr_cantidad = [] + @arr_unidad = [] + @arr_descripcion = [] + @datos = {} + end + + def self.campos_vs_metodos + { + 'ClaveProdServ' => 'clave_producto_servicio', + 'NoIdentificacion' => 'numero_de_identificacion', + 'Cantidad' => 'cantidad', + 'Unidad' => 'unidad', + 'Descripcion' => 'descripcion', + } + end + + def clave_producto_servicio value + arr_clave.push value + @datos["ClaveProdServ"] = "[#{arr_clave.join(',')}]" + end + + def numero_de_identificacion value + arr_no_identificacion.push value + @datos["NoIdentificacion"] = "[#{arr_no_identificacion.join(',')}]" + end + + def cantidad value + arr_cantidad.push value + @datos["Cantidad"] = "[#{arr_cantidad.join(',')}]" + end + + def unidad value + arr_unidad.push value + @datos["Unidad"] = "[#{arr_unidad.join(',')}]" + end + + def descripcion value + arr_descripcion.push value + @datos["Descripcion"] = "[#{arr_descripcion.join(',')}]" + end + end +end diff --git a/lib/fm_layout/receptor.rb b/lib/fm_layout/receptor.rb index 4cd3b7d..0e7f17e 100644 --- a/lib/fm_layout/receptor.rb +++ b/lib/fm_layout/receptor.rb @@ -4,34 +4,16 @@ module FmLayout class Receptor include FmSeccion - def initialize separador = '|' - @separador = separador + def initialize @titulo = 'Receptor' @datos = {} end def self.campos_vs_metodos { - 'rfc' => 'rfc', - 'nombre' => 'nombre', - 'Curp' => 'curp', - 'NumSeguridadSocial' => 'numero_seguridad_social', - 'FechaInicioRelLaboral' => 'fecha_inicio_relacion_laboral', - 'Antigüedad' => 'antiguedad', - 'TipoContrato' => 'tipo_contrato', - 'TipoJornada' => 'tipo_jornada', - 'TipoRegimen' => 'tipo_regimen', - 'NumEmpleado' => 'numero_empleado', - 'Departamento' => 'departamento', - 'Puesto' => 'puesto', - 'RiesgoPuesto' => 'riesgo_puesto', - 'PeriodicidadPago' => 'periodicidad_pago', - 'Banco' => 'banco', - 'CuentaBancaria' => 'cuenta_bancaria', - 'SalarioBaseCotApor' => 'salario_base', - 'SalarioDiarioIntegrado' => 'salario_diario_integrado', - 'ClaveEntFed' => 'clave_entidad_federativa', - 'emailCliente' => 'email', + 'Rfc' => 'rfc', + 'Nombre' => 'nombre', + 'UsoCFDI' => 'uso_cfdi', } end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 98a4452..8597bfc 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -194,7 +194,7 @@ end context 'datos adicionales' do - let(:datos_adicionales){ prueba.to_h['Datos Adicionales'] } + let(:datos_adicionales){ prueba.to_h['DatosAdicionales'] } it{ expect(datos_adicionales['tipoDocumento']).to eq('RECIBO DE NOMINA') } it{ expect(datos_adicionales['idNomina']).to eq('N-1') } @@ -409,7 +409,7 @@ context 'salida en texto' do let(:salida){ prueba.to_s } it{ expect(salida).to match(/\[ReciboNomina\]/) } - it{ expect(salida).to match(/\[Datos Adicionales\]/) } + it{ expect(salida).to match(/\[DatosAdicionales\]/) } it{ expect(salida).to match(/\[Emisor\]/) } it{ expect(salida).to match(/\[EntidadSNCF\]/) } it{ expect(salida).to match(/\[Receptor\]/) } diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index 31d089d..cc7ad94 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -12,122 +12,132 @@ e.serie 'A' e.folio 10 e.fecha hora - e.tipo_de_comprobante 'ingreso' - e.forma_de_pago 'PAGO EN UNA SOLA EXHIBICIÓN' - e.metodo_de_pago 'Transferencia Electrónica' + e.forma_de_pago '01' + e.numero_de_certificado '111222111' e.condiciones_de_pago 'Contado' - e.numero_de_cuenta_de_pago '0098-HSBC' e.subtotal 100.00 e.descuento 0.00 - e.total 116.00 e.moneda 'MXN' - e.tipo_de_cambio 1.0 - e.numero_de_certificado '111222111' - e.lugar_de_expedicion 'Nuevo León, México' + e.total 116.00 + e.tipo_de_comprobante 'I' + e.metodo_de_pago 'PUE' + e.lugar_de_expedicion '68000' end f.datos_adicionales do |d| d.tipo_de_documento 'Factura' - d.numero_de_pedido '123456' d.observaciones 'Efectos Fiscales al Pago' d.id_transaccion 5 end f.emisor do |e| e.rfc 'TUMG620310R95' e.nombre 'FACTURACION MODERNA S.A de C.V.' - e.regimen '612' - end - f.domicilio_fiscal do |d| - d.calle 'Calle 1' - d.numero_exterior 'Número Exterior' - d.numero_interior 'Número Interior' - d.colonia 'Colonia' - d.localidad 'Localidad' - d.municipio 'Municipio' - d.estado 'NUEVO LEON' - d.pais 'México' - d.codigo_postal '66260' - end - f.expedido_en do |d| - d.calle 'Calle 2' - d.numero_exterior 'Número Exterior 2' - d.numero_interior 'Número Interior 2' - d.colonia 'Colonia 2' - d.localidad 'Localidad 2' - d.municipio 'Municipio 2' - d.estado 'OAXACA' - d.pais 'México' - d.codigo_postal '68000' + e.regimen_fiscal '612' end f.receptor do |r| r.rfc 'XAXX010101000' r.nombre 'PUBLICO EN GENERAL' end - f.domicilio do |d| - d.calle 'Calle 3' - d.numero_exterior 'Número Exterior 3' - d.numero_interior 'Número Interior 3' - d.colonia 'Colonia 3' - d.localidad 'Localidad 3' - d.municipio 'Municipio 3' - d.estado 'PUEBLA' - d.pais 'México' - d.codigo_postal '72500' - end f.concepto do |c| + c.clave_producto_servicio '01010101' + c.numero_de_identificacion '111222333' c.cantidad 1 + c.clave_unidad 'H87' c.unidad 'No Aplica' - c.numero_de_identificacion '111222333' c.descripcion 'Caja Hojas Blancas Tamaño Carta' - c.valor_unitario 100.00 - c.importe 100.00 - c.cuenta_predial '123-132123' + c.valor_unitario 110.00 + c.importe 110.00 + c.descuento 10.00 + #c.cuenta_predial '123-132123' + + c.partes do |c| + c.clave_producto_servicio '01010101' + c.numero_de_identificacion '112233' + c.cantidad 1 + c.unidad 'No aplica' + c.descripcion 'Una descripcion' + end + + c.partes do |c| + c.clave_producto_servicio '01010101' + c.numero_de_identificacion '112234' + c.cantidad 1 + c.unidad 'No aplica' + c.descripcion 'Otra descripcion' + end + + c.impuesto_trasladado do |i| + i.base 100.00 + i.impuesto '002' + i.tipo_factor 'Tasa' + i.tasa_o_cuota 0.16 + i.importe 16 + end + + c.impuesto_retenido do |i| + i.base 100.00 + i.impuesto '001' + i.tipo_factor 'Tasa' + i.tasa_o_cuota 0.2 + i.importe 20 + end end f.concepto do |c| + c.clave_producto_servicio '10101502' + c.numero_de_identificacion '111222334' c.cantidad 2 - c.unidad 'mts' - c.numero_de_identificacion '1111' + c.clave_unidad 'H87' + c.unidad 'No Aplica' c.descripcion 'Plástico para forrar libros' - c.valor_unitario 10.00 - c.importe 20.00 + c.valor_unitario 10.0 + c.importe 20.0 + + c.impuesto_trasladado do |i| + i.base 20.0 + i.impuesto '002' + i.tipo_factor 'Tasa' + i.tasa_o_cuota 0.16 + i.importe 3.2 + end + + c.impuesto_retenido do |i| + i.base 20.0 + i.impuesto '001' + i.tipo_factor 'Tasa' + i.tasa_o_cuota 0.2 + i.importe 4 + end end f.impuesto_trasladado do |i| - i.impuesto 'IVA' - i.importe 150.00 - i.tasa 16.00 + i.total_impuestos 19.2 + i.impuesto "002" + i.tipo_factor "Tasa" + i.tasa_o_cuota 0.16 + i.importe 19.2 end f.impuesto_trasladado_local do |i| i.impuesto 'ISH' - i.importe 110.00 - i.tasa 11.00 - end - - f.impuesto_retenido do |i| - i.impuesto 'IVA' - i.importe 100.00 + i.importe 110.0 + i.tasa 0.11 end - f.impuesto_retenido do |i| - i.impuesto 'ISR' - i.importe 10.00 + i.total_impuestos 24 + i.impuesto "001" + i.importe 24 end - f.impuesto_retenido_local do |i| i.impuesto 'IVA LOCAL' i.importe 110.00 - i.tasa 16.00 + i.tasa 0.16 end - f.impuesto_retenido_local do |i| i.impuesto 'ISR LOCAL' i.importe 110.00 - i.tasa 16.00 + i.tasa 0.16 end - f.complemento_ine do |i| i.tipo_proceso 'Ordinario' i.tipo_comite 'Ejecutivo Estatal' end - f.entidad_ine do |e| e.clave_entidad 'OAX' e.id_contabilidad '000516' @@ -135,143 +145,127 @@ end end - context 'encabezado' do - let(:encabezado){ prueba.to_h['Encabezado'] } - it{ expect(encabezado['serie']).to eq('A') } - it{ expect(encabezado['folio']).to eq(10) } - it{ expect(encabezado['fecha']).to eq(hora) } - it{ expect(encabezado['tipoDeComprobante']).to eq('ingreso') } - it{ expect(encabezado['formaDePago']).to eq('PAGO EN UNA SOLA EXHIBICIÓN') } - it{ expect(encabezado['condicionesDePago']).to eq('Contado') } - it{ expect(encabezado['subTotal']).to eq(100.00) } - it{ expect(encabezado['descuento']).to eq(0.00) } - it{ expect(encabezado['total']).to eq(116.00) } - it{ expect(encabezado['Moneda']).to eq('MXN') } - it{ expect(encabezado['TipoCambio']).to eq(1.0) } - it{ expect(encabezado['noCertificado']).to eq('111222111') } - it{ expect(encabezado['LugarExpedicion']).to eq('Nuevo León, México') } + context 'comprobante fiscal digital' do + let(:comprobante_fiscal_digital){ prueba.to_h['ComprobanteFiscalDigital'] } + it{ expect(comprobante_fiscal_digital['Version']).to eq('3.3') } + it{ expect(comprobante_fiscal_digital['Serie']).to eq('A') } + it{ expect(comprobante_fiscal_digital['Folio']).to eq(10) } + it{ expect(comprobante_fiscal_digital['Fecha']).to eq(hora) } + it{ expect(comprobante_fiscal_digital['FormaPago']).to eq('01') } + it{ expect(comprobante_fiscal_digital['NoCertificado']).to eq('111222111') } + it{ expect(comprobante_fiscal_digital['CondicionesDePago']).to eq('Contado') } + it{ expect(comprobante_fiscal_digital['SubTotal']).to eq(100.00) } + it{ expect(comprobante_fiscal_digital['Descuento']).to eq(0.00) } + it{ expect(comprobante_fiscal_digital['Total']).to eq(116.00) } + it{ expect(comprobante_fiscal_digital['Moneda']).to eq('MXN') } + it{ expect(comprobante_fiscal_digital['TipoDeComprobante']).to eq('I') } + it{ expect(comprobante_fiscal_digital['MetodoPago']).to eq('PUE') } + it{ expect(comprobante_fiscal_digital['LugarExpedicion']).to eq('68000') } end context 'datos adicionales' do - let(:datos_adicionales){ prueba.to_h['Datos Adicionales'] } + let(:datos_adicionales){ prueba.to_h['DatosAdicionales'] } it{ expect(datos_adicionales['tipoDocumento']).to eq('Factura') } - it{ expect(datos_adicionales['numeropedido']).to eq('123456') } it{ expect(datos_adicionales['observaciones']).to eq('Efectos Fiscales al Pago') } it{ expect(datos_adicionales['TransID']).to eq(5) } end context 'emisor' do let(:emisor){ prueba.to_h['Emisor'] } - it{ expect(emisor['rfc']).to eq('TUMG620310R95') } - it{ expect(emisor['nombre']).to eq('FACTURACION MODERNA S.A de C.V.') } - it{ expect(emisor['Regimen']).to eq('612') } - end - - context 'domicilio fiscal' do - let(:domicilio_fiscal){ prueba.to_h['DomicilioFiscal'] } - it{ expect(domicilio_fiscal['calle']).to eq('Calle 1') } - it{ expect(domicilio_fiscal['noExterior']).to eq('Número Exterior') } - it{ expect(domicilio_fiscal['noInterior']).to eq('Número Interior') } - it{ expect(domicilio_fiscal['colonia']).to eq('Colonia') } - it{ expect(domicilio_fiscal['localidad']).to eq('Localidad') } - it{ expect(domicilio_fiscal['municipio']).to eq('Municipio') } - it{ expect(domicilio_fiscal['estado']).to eq('NUEVO LEON') } - it{ expect(domicilio_fiscal['pais']).to eq('México') } - it{ expect(domicilio_fiscal['codigoPostal']).to eq('66260') } - end - - context 'expedido en' do - let(:expedido_en){ prueba.to_h['ExpedidoEn'] } - it{ expect(expedido_en['calle']).to eq('Calle 2') } - it{ expect(expedido_en['noExterior']).to eq('Número Exterior 2') } - it{ expect(expedido_en['noInterior']).to eq('Número Interior 2') } - it{ expect(expedido_en['colonia']).to eq('Colonia 2') } - it{ expect(expedido_en['localidad']).to eq('Localidad 2') } - it{ expect(expedido_en['municipio']).to eq('Municipio 2') } - it{ expect(expedido_en['estado']).to eq('OAXACA') } - it{ expect(expedido_en['pais']).to eq('México') } - it{ expect(expedido_en['codigoPostal']).to eq('68000') } + it{ expect(emisor['Rfc']).to eq('TUMG620310R95') } + it{ expect(emisor['Nombre']).to eq('FACTURACION MODERNA S.A de C.V.') } + it{ expect(emisor['RegimenFiscal']).to eq('612') } end context 'receptor' do let(:receptor){ prueba.to_h['Receptor'] } - it{ expect(receptor['rfc']).to eq('XAXX010101000') } - it{ expect(receptor['nombre']).to eq('PUBLICO EN GENERAL') } - end - - context 'domilicio' do - let(:domicilio){ prueba.to_h['Domicilio'] } - it{ expect(domicilio['calle']).to eq('Calle 3') } - it{ expect(domicilio['noExterior']).to eq('Número Exterior 3') } - it{ expect(domicilio['noInterior']).to eq('Número Interior 3') } - it{ expect(domicilio['colonia']).to eq('Colonia 3') } - it{ expect(domicilio['localidad']).to eq('Localidad 3') } - it{ expect(domicilio['municipio']).to eq('Municipio 3') } - it{ expect(domicilio['estado']).to eq('PUEBLA') } - it{ expect(domicilio['pais']).to eq('México') } - it{ expect(domicilio['codigoPostal']).to eq('72500') } + it{ expect(receptor['Rfc']).to eq('XAXX010101000') } + it{ expect(receptor['Nombre']).to eq('PUBLICO EN GENERAL') } end context 'primer concepto' do - let(:concepto){ prueba.to_h['Conceptos'].first['Concepto'] } - it{ expect(concepto['cantidad']).to eq(1) } - it{ expect(concepto['unidad']).to eq('No Aplica') } - it{ expect(concepto['noIdentificacion']).to eq('111222333') } - it{ expect(concepto['descripcion']).to eq('Caja Hojas Blancas Tamaño Carta') } - it{ expect(concepto['valorUnitario']).to eq(100.00) } - it{ expect(concepto['importe']).to eq(100.00) } - it{ expect(concepto['CuentaPredial']).to eq('123-132123') } + let(:concepto){ prueba.to_h['Conceptos'].first['Concepto#1'] } + it{ expect(concepto['ClaveProdServ']).to eq('01010101') } + it{ expect(concepto['NoIdentificacion']).to eq('111222333') } + it{ expect(concepto['Cantidad']).to eq(1) } + it{ expect(concepto['ClaveUnidad']).to eq('H87') } + it{ expect(concepto['Unidad']).to eq('No Aplica') } + it{ expect(concepto['Descripcion']).to eq('Caja Hojas Blancas Tamaño Carta') } + it{ expect(concepto['ValorUnitario']).to eq(110.00) } + it{ expect(concepto['Importe']).to eq(110.00) } + it{ expect(concepto['Descuento']).to eq(10.00) } + + it{ expect(concepto['Parte.ClaveProdServ']).to eq("[01010101,01010101]") } + it{ expect(concepto['Parte.NoIdentificacion']).to eq("[112233,112234]") } + it{ expect(concepto['Parte.Cantidad']).to eq("[1,1]") } + it{ expect(concepto['Parte.Unidad']).to eq("[No aplica,No aplica]") } + it{ expect(concepto['Parte.Descripcion']).to eq("[Una descripcion,Otra descripcion]") } + + it{ expect(concepto['Impuestos.Traslados.Base']).to eq("[100.0]") } + it{ expect(concepto['Impuestos.Traslados.Impuesto']).to eq("[002]") } + it{ expect(concepto['Impuestos.Traslados.TipoFactor']).to eq("[Tasa]") } + it{ expect(concepto['Impuestos.Traslados.TasaOCuota']).to eq("[0.16]") } + it{ expect(concepto['Impuestos.Traslados.Importe']).to eq("[16]") } + + it{ expect(concepto['Impuestos.Retenciones.Base']).to eq("[100.0]") } + it{ expect(concepto['Impuestos.Retenciones.Impuesto']).to eq("[001]") } + it{ expect(concepto['Impuestos.Retenciones.TipoFactor']).to eq("[Tasa]") } + it{ expect(concepto['Impuestos.Retenciones.TasaOCuota']).to eq("[0.2]") } + it{ expect(concepto['Impuestos.Retenciones.Importe']).to eq("[20]") } + #it{ expect(concepto['CuentaPredial']).to eq('123-132123') } end context 'segundo concepto' do - let(:concepto){ prueba.to_h['Conceptos'].last['Concepto'] } - it{ expect(concepto['cantidad']).to eq(2) } - it{ expect(concepto['unidad']).to eq('mts') } - it{ expect(concepto['noIdentificacion']).to eq('1111') } - it{ expect(concepto['descripcion']).to eq('Plástico para forrar libros') } - it{ expect(concepto['valorUnitario']).to eq(10.00) } - it{ expect(concepto['importe']).to eq(20.00) } - it{ expect(concepto['CuentaPredial']).to eq(nil) } - end - - context 'primer impuesto trasladado' do - let(:traslado){ prueba.to_h['ImpuestosTrasladados'].first['ImpuestoTrasladado'] } - it{ expect(traslado['impuesto']).to eq('IVA') } - it{ expect(traslado['importe']).to eq(150.00) } - it{ expect(traslado['tasa']).to eq(16.00) } - end - - context 'primer impuesto retenido' do - let(:retencion){ prueba.to_h['ImpuestosRetenidos'].first['ImpuestoRetenido'] } - it{ expect(retencion['impuesto']).to eq('IVA') } - it{ expect(retencion['importe']).to eq(100.00) } + let(:concepto){ prueba.to_h['Conceptos'].last['Concepto#2'] } + it{ expect(concepto['ClaveProdServ']).to eq('10101502') } + it{ expect(concepto['NoIdentificacion']).to eq('111222334') } + it{ expect(concepto['Cantidad']).to eq(2) } + it{ expect(concepto['ClaveUnidad']).to eq('H87') } + it{ expect(concepto['Unidad']).to eq('No Aplica') } + it{ expect(concepto['Descripcion']).to eq('Plástico para forrar libros') } + it{ expect(concepto['ValorUnitario']).to eq(10.00) } + it{ expect(concepto['Importe']).to eq(20.00) } + + it{ expect(concepto['Impuestos.Traslados.Base']).to eq("[20.0]") } + it{ expect(concepto['Impuestos.Traslados.Impuesto']).to eq("[002]") } + it{ expect(concepto['Impuestos.Traslados.TipoFactor']).to eq("[Tasa]") } + it{ expect(concepto['Impuestos.Traslados.TasaOCuota']).to eq("[0.16]") } + it{ expect(concepto['Impuestos.Traslados.Importe']).to eq("[3.2]") } + + it{ expect(concepto['Impuestos.Retenciones.Base']).to eq("[20.0]") } + it{ expect(concepto['Impuestos.Retenciones.Impuesto']).to eq("[001]") } + it{ expect(concepto['Impuestos.Retenciones.TipoFactor']).to eq("[Tasa]") } + it{ expect(concepto['Impuestos.Retenciones.TasaOCuota']).to eq("[0.2]") } + it{ expect(concepto['Impuestos.Retenciones.Importe']).to eq("[4]") } end - context 'segundo impuesto retenido' do - let(:retencion){ prueba.to_h['ImpuestosRetenidos'].last['ImpuestoRetenido'] } - it{ expect(retencion['impuesto']).to eq('ISR') } - it{ expect(retencion['importe']).to eq(10.00) } + context 'impuestos trasladados' do + let(:traslado){ prueba.to_h['ImpuestosTrasladados']['Traslados'] } + it{ expect(traslado['TotalImpuestosTrasladados']).to eq(19.2) } + it{ expect(traslado['Impuesto']).to eq('[002]') } + it{ expect(traslado['TasaOCuota']).to eq("[0.16]") } + it{ expect(traslado['Importe']).to eq("[19.2]") } end - context 'primer impuesto trasladado local' do - let(:traslado_local){ prueba.to_h['ImpuestosTrasladadosLocales'].first['TrasladoLocal'] } - it{ expect(traslado_local['ImpLocTrasladado']).to eq('ISH') } - it{ expect(traslado_local['Importe']).to eq(110.00) } - it{ expect(traslado_local['TasadeTraslado']).to eq(11.00) } + context 'impuestos retenidos' do + let(:retencion){ prueba.to_h['ImpuestosRetenidos']['Retenciones'] } + it{ expect(retencion['TotalImpuestosRetenidos']).to eq(24) } + it{ expect(retencion['Impuesto']).to eq("[001]") } + it{ expect(retencion['Importe']).to eq("[24]") } end - context 'primer impuesto retenido local' do - let(:retencion_local){ prueba.to_h['ImpuestosRetenidosLocales'].first['RetencionLocal'] } - it{ expect(retencion_local['ImpLocRetenido']).to eq('IVA LOCAL') } - it{ expect(retencion_local['Importe']).to eq(110.00) } - it{ expect(retencion_local['TasadeRetencion']).to eq(16.00) } + context 'impuestos trasladados locales' do + let(:traslado_local){ prueba.to_h['ImpuestosTrasladadosLocales']['TrasladosLocales'] } + it{ expect(traslado_local['ImpLocTrasladado']).to eq('[ISH]') } + it{ expect(traslado_local['TasadeTraslado']).to eq("[0.11]") } + it{ expect(traslado_local['Importe']).to eq("[110.0]") } end - context 'segundo impuesto retenido local' do - let(:retencion_local){ prueba.to_h['ImpuestosRetenidosLocales'].last['RetencionLocal'] } - it{ expect(retencion_local['ImpLocRetenido']).to eq('ISR LOCAL') } - it{ expect(retencion_local['Importe']).to eq(110.00) } - it{ expect(retencion_local['TasadeRetencion']).to eq(16.00) } + context 'impuestos retenidos locales' do + let(:retencion_local){ prueba.to_h['ImpuestosRetenidosLocales']['RetencionesLocales'] } + it{ expect(retencion_local['ImpLocRetenido']).to eq('[IVA LOCAL,ISR LOCAL]') } + it{ expect(retencion_local['TasadeRetencion']).to eq("[0.16,0.16]") } + it{ expect(retencion_local['Importe']).to eq("[110.0,110.0]") } end context 'ComplementoINE' do @@ -288,18 +282,16 @@ context 'salida en texto' do let(:salida){ prueba.to_s } - it{ expect(salida).to match(/\[Encabezado\]/) } - it{ expect(salida).to match(/\[Datos Adicionales\]/) } + it{ expect(salida).to match(/\[ComprobanteFiscalDigital\]/) } + it{ expect(salida).to match(/\[DatosAdicionales\]/) } it{ expect(salida).to match(/\[Emisor\]/) } - it{ expect(salida).to match(/\[DomicilioFiscal\]/) } - it{ expect(salida).to match(/\[ExpedidoEn\]/) } it{ expect(salida).to match(/\[Receptor\]/) } - it{ expect(salida).to match(/\[Domicilio\]/) } - it{ expect(salida).to match(/\[Concepto\]/) } - it{ expect(salida).to match(/\[ImpuestoTrasladado\]/) } - it{ expect(salida).to match(/\[ImpuestoRetenido\]/) } - it{ expect(salida).to match(/\[TrasladoLocal\]/) } - it{ expect(salida).to match(/\[RetencionLocal\]/) } + it{ expect(salida).to match(/\[Concepto#1\]/) } + it{ expect(salida).to match(/\[Concepto#2\]/) } + it{ expect(salida).to match(/\[Traslados\]/) } + it{ expect(salida).to match(/\[Retenciones\]/) } + it{ expect(salida).to match(/\[TrasladosLocales\]/) } + it{ expect(salida).to match(/\[RetencionesLocales\]/) } it{ expect(salida).to match(/\[ComplementoINE\]/) } it{ expect(salida).to match(/\[Entidad\]/) } end @@ -318,8 +310,6 @@ end f.receptor do |r| end - f.domicilio do |d| - end f.concepto do |c| end f.impuesto_trasladado do |i| @@ -330,39 +320,31 @@ end context 'encabezado' do - let(:encabezado){ prueba.to_h['Encabezado'] } - it{ expect(encabezado['fecha']).to eq('asignarFecha') } - it{ expect(encabezado['folio']).to eq('asignarFolio') } + let(:encabezado){ prueba.to_h['ComprobanteFiscalDigital'] } + it{ expect(encabezado['Fecha']).to eq('asignarFecha') } + it{ expect(encabezado['Folio']).to eq('asignarFolio') } end context 'datos adicionales' do - let(:datos_adicionales){ prueba.to_h['Datos Adicionales'] } + let(:datos_adicionales){ prueba.to_h['DatosAdicionales'] } it{ expect(datos_adicionales['tipoDocumento']).to eq('Factura') } end - context 'domicilio fiscal' do - let(:domicilio){ prueba.to_h['Domicilio'] } - it{ expect(domicilio['pais']).to eq('México') } - end - context 'primer concepto' do - let(:concepto){ prueba.to_h['Conceptos'].first['Concepto'] } - it{ expect(concepto['cantidad']).to eq(1) } + let(:concepto){ prueba.to_h['Conceptos'].first['Concepto#1'] } + it{ expect(concepto['Cantidad']).to eq(1) } end context 'salida en texto' do let(:salida){ prueba.to_s } - it{ expect(salida).to match(/\[Encabezado\]/) } - it{ expect(salida).to match(/\[Datos Adicionales\]/) } + it{ expect(salida).to match(/\[ComprobanteFiscalDigital\]/) } + it{ expect(salida).to match(/\[DatosAdicionales\]/) } it{ expect(salida).to match("TransID|5") } it{ expect(salida).to match(/\[Emisor\]/) } it{ expect(salida).not_to match(/\[DomicilioFiscal\]/) } it{ expect(salida).not_to match(/\[ExpedidoEn\]/) } it{ expect(salida).to match(/\[Receptor\]/) } - it{ expect(salida).to match(/\[Domicilio\]/) } - it{ expect(salida).to match(/\[Concepto\]/) } - it{ expect(salida).to match(/\[ImpuestoTrasladado\]/) } - it{ expect(salida).to match(/\[ImpuestoRetenido\]/) } + it{ expect(salida).to match(/\[Concepto#1\]/) } end end From 7fc0ecfc3ff586235aba80cf4a40dc8f30da5818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 5 Jul 2017 10:07:19 -0500 Subject: [PATCH 31/56] Add support for cfdi_relacionado --- lib/fm_layout/cfdi_relacionados.rb | 25 +++++++++++++++++++++++++ lib/fm_layout/fm_layout.rb | 20 ++++++++++++++++---- spec/fm_layout_spec.rb | 10 ++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 lib/fm_layout/cfdi_relacionados.rb diff --git a/lib/fm_layout/cfdi_relacionados.rb b/lib/fm_layout/cfdi_relacionados.rb new file mode 100644 index 0000000..e07ff44 --- /dev/null +++ b/lib/fm_layout/cfdi_relacionados.rb @@ -0,0 +1,25 @@ +require 'fm_layout/fm_seccion' + +module FmLayout + class CfdiRelacionados + include FmSeccion + attr_reader :datos + + def initialize + @titulo = 'CfdiRelacionados' + @datos = {} + end + + def tipo_relacion value + @datos["TipoRelacion"] = value + end + + def uuids value + @datos["UUID"] = "[#{value}]" + end + + def con_relaciones? + @datos.any? + end + end +end diff --git a/lib/fm_layout/fm_layout.rb b/lib/fm_layout/fm_layout.rb index 02d6197..837b65d 100644 --- a/lib/fm_layout/fm_layout.rb +++ b/lib/fm_layout/fm_layout.rb @@ -10,6 +10,7 @@ require 'fm_layout/impuesto_retenido_local' require 'fm_layout/complemento_ine' require 'fm_layout/entidad_ine' +require 'fm_layout/cfdi_relacionados' module FmLayout class FmLayout @@ -26,6 +27,7 @@ def initialize @impuesto_retenido = ImpuestoRetenido.new @impuesto_trasladado_local = ImpuestoTrasladadoLocal.new @impuesto_retenido_local = ImpuestoRetenidoLocal.new + @cfdi_relacionados = CfdiRelacionados.new end def encabezado @@ -149,8 +151,20 @@ def entidad_ine end end + def cfdi_relacionados + if block_given? + yield(@cfdi_relacionados) + else + @cfdi_relacionados + end + end + def to_s - salida = @encabezado.to_s + @datos_adicionales.to_s + @emisor.to_s + @domicilio_fiscal.to_s + @expedido_en.to_s + @receptor.to_s + @domicilio.to_s + salida = @encabezado.to_s + salida += @cfdi_relacionados.to_s if @cfdi_relacionados.con_relaciones? + salida += @datos_adicionales.to_s + salida += @emisor.to_s + salida += @receptor.to_s salida += @conceptos.map(&:to_s).reduce(:+).to_s salida += @impuesto_trasladado.to_s if @impuesto_trasladado.con_impuestos? salida += @impuesto_retenido.to_s if @impuesto_retenido.con_impuestos? @@ -165,16 +179,14 @@ def to_h encabezado.to_h .merge(@datos_adicionales.to_h) .merge(@emisor.to_h) - .merge(@domicilio_fiscal.to_h) - .merge(@expedido_en.to_h) .merge(@receptor.to_h) - .merge(@domicilio.to_h) .merge(obtener_hash_conceptos) .merge(obtener_hash_traslados) .merge(obtener_hash_retenciones) .merge(obtener_hash_traslados_locales) .merge(obtener_hash_retenciones_locales) .merge(@complemento_ine.to_h) + .merge(@cfdi_relacionados.to_h) .merge(obtener_hash_entidades_ine) end diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index cc7ad94..ec952dc 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -23,6 +23,10 @@ e.metodo_de_pago 'PUE' e.lugar_de_expedicion '68000' end + f.cfdi_relacionados do |cfdi| + cfdi.tipo_relacion '04' + cfdi.uuids "FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623" + end f.datos_adicionales do |d| d.tipo_de_documento 'Factura' d.observaciones 'Efectos Fiscales al Pago' @@ -163,6 +167,12 @@ it{ expect(comprobante_fiscal_digital['LugarExpedicion']).to eq('68000') } end + context "cfdi relacionados" do + let(:cfdi_relacionado) { prueba.to_h['CfdiRelacionados'] } + it{ expect(cfdi_relacionado['TipoRelacion']).to eq('04') } + it{ expect(cfdi_relacionado['UUID']).to eq('[FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623]') } + end # context cfdi relacionados + context 'datos adicionales' do let(:datos_adicionales){ prueba.to_h['DatosAdicionales'] } it{ expect(datos_adicionales['tipoDocumento']).to eq('Factura') } From 3f3a3f3924f88fb58872e41b3e979fb2ef958c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 19 Jul 2017 16:32:57 -0500 Subject: [PATCH 32/56] Enable version 3.3 in nomina --- lib/fm_layout/recibo_nomina.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/fm_layout/recibo_nomina.rb b/lib/fm_layout/recibo_nomina.rb index b25845b..6df93e3 100644 --- a/lib/fm_layout/recibo_nomina.rb +++ b/lib/fm_layout/recibo_nomina.rb @@ -34,6 +34,7 @@ def self.campos_vs_metodos private def valores_iniciales + @datos['Version'] = '3.3' @datos['serie'] = nil @datos['folio'] = 'asignarFolio' @datos['fecha'] = nil From c5eeeed0c4026583bcc4c0fc119f69b749d0fef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 26 Jul 2017 14:39:02 -0500 Subject: [PATCH 33/56] Updating ruby-version --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 222078e..81ead5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: ruby rvm: - - 1.9.3 - 2.0.0 + - 2.3.3 From 5101f1049c5fc077e3a19106f6df619e1be6611f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Thu, 10 Aug 2017 09:47:44 -0500 Subject: [PATCH 34/56] Now asignarFecha and asignarFolio aren't avaliables for version 3.3 --- lib/fm_layout/comprobante_fiscal_digital.rb | 5 ++--- lib/fm_layout/recibo_nomina.rb | 2 +- spec/fm_layout_spec.rb | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/fm_layout/comprobante_fiscal_digital.rb b/lib/fm_layout/comprobante_fiscal_digital.rb index af9010c..8021736 100644 --- a/lib/fm_layout/comprobante_fiscal_digital.rb +++ b/lib/fm_layout/comprobante_fiscal_digital.rb @@ -40,9 +40,8 @@ def self.campos_vs_metodos def valores_iniciales @datos['Version'] = '3.3' - @datos['Fecha'] = 'asignarFecha' - @datos['Folio'] = 'asignarFolio' - #@datos['NumCtaPago'] = 'No identificado' + @datos['fecha'] = nil + @datos['folio'] = nil @datos['NoCertificado'] = nil @datos['SubTotal'] = nil @datos['Descuento'] = nil diff --git a/lib/fm_layout/recibo_nomina.rb b/lib/fm_layout/recibo_nomina.rb index 6df93e3..eb322ab 100644 --- a/lib/fm_layout/recibo_nomina.rb +++ b/lib/fm_layout/recibo_nomina.rb @@ -36,7 +36,7 @@ def self.campos_vs_metodos def valores_iniciales @datos['Version'] = '3.3' @datos['serie'] = nil - @datos['folio'] = 'asignarFolio' + @datos['folio'] = nil @datos['fecha'] = nil @datos['subTotal'] = nil @datos['descuento'] = nil diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index ec952dc..99a5093 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -331,8 +331,7 @@ context 'encabezado' do let(:encabezado){ prueba.to_h['ComprobanteFiscalDigital'] } - it{ expect(encabezado['Fecha']).to eq('asignarFecha') } - it{ expect(encabezado['Folio']).to eq('asignarFolio') } + it{ expect(encabezado['Version']).to eq('3.3') } end context 'datos adicionales' do From 4dfcab89b7bdd6350603b9c96597f3ef50e8238f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Thu, 10 Aug 2017 11:35:56 -0500 Subject: [PATCH 35/56] Fix error The first letter of Fecha and Folio must be capital letters --- lib/fm_layout/comprobante_fiscal_digital.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/fm_layout/comprobante_fiscal_digital.rb b/lib/fm_layout/comprobante_fiscal_digital.rb index 8021736..156cf9d 100644 --- a/lib/fm_layout/comprobante_fiscal_digital.rb +++ b/lib/fm_layout/comprobante_fiscal_digital.rb @@ -40,8 +40,8 @@ def self.campos_vs_metodos def valores_iniciales @datos['Version'] = '3.3' - @datos['fecha'] = nil - @datos['folio'] = nil + @datos['Fecha'] = nil + @datos['Folio'] = nil @datos['NoCertificado'] = nil @datos['SubTotal'] = nil @datos['Descuento'] = nil From e53be63bbc3fc2fef81b0872603cd5b9a3cb2c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Fri, 6 Oct 2017 17:50:58 -0500 Subject: [PATCH 36/56] Enable support to ReciboPago Layout --- lib/fm_layout.rb | 7 + lib/fm_layout/documento_relacionado.rb | 75 ++++++++++ lib/fm_layout/fm_layout_pago.rb | 34 +++++ lib/fm_layout/pago.rb | 59 ++++++++ lib/fm_layout/recibo_pago.rb | 42 ++++++ spec/fm_layout_recibo_pago_spec.rb | 189 +++++++++++++++++++++++++ 6 files changed, 406 insertions(+) create mode 100644 lib/fm_layout/documento_relacionado.rb create mode 100644 lib/fm_layout/fm_layout_pago.rb create mode 100644 lib/fm_layout/pago.rb create mode 100644 lib/fm_layout/recibo_pago.rb create mode 100644 spec/fm_layout_recibo_pago_spec.rb diff --git a/lib/fm_layout.rb b/lib/fm_layout.rb index 8821a4c..b105f50 100644 --- a/lib/fm_layout.rb +++ b/lib/fm_layout.rb @@ -1,6 +1,7 @@ require "fm_layout/version" require "fm_layout/fm_layout" require "fm_layout/fm_layout_nomina" +require "fm_layout/fm_layout_pago" module FmLayout def self.define_layout @@ -14,6 +15,12 @@ def self.define_layout_nomina yield(layout) if block_given? layout end + + def self.define_layout_recibo_pago + layout = FmLayoutPago.new + yield(layout) if block_given? + layout + end end # Monkeypatch diff --git a/lib/fm_layout/documento_relacionado.rb b/lib/fm_layout/documento_relacionado.rb new file mode 100644 index 0000000..d326363 --- /dev/null +++ b/lib/fm_layout/documento_relacionado.rb @@ -0,0 +1,75 @@ +require 'fm_layout/fm_seccion' + +module FmLayout + class DocumentoRelacionado + attr_reader :datos + attr_accessor :arr_id_documento, :arr_serie, :arr_folio, :arr_moneda, :arr_tipo_cambio, + :arr_metodo_pago, :arr_metodo_pago, :arr_num_parcialidad, :arr_imp_saldo_ant, :arr_imp_pagado, + :arr_saldo_insoluto + include FmSeccion + + def initialize + @arr_id_documento = [] + @arr_serie = [] + @arr_folio = [] + @arr_moneda = [] + @arr_tipo_cambio = [] + @arr_metodo_pago = [] + @arr_num_parcialidad = [] + @arr_imp_saldo_ant = [] + @arr_imp_pagado = [] + @arr_saldo_insoluto = [] + @datos = {} + end + + def id_documento value + arr_id_documento.push value + @datos["IdDocumento"] = "[#{arr_id_documento.join(',')}]" + end + + def serie value = '' + arr_serie.push value + @datos["Serie"] = "[#{arr_serie.join(',')}]" + end + + def folio value = '' + arr_folio.push value + @datos["Folio"] = "[#{arr_folio.join(',')}]" + end + + def moneda value + arr_moneda.push value + @datos["MonedaDR"] = "[#{arr_moneda.join(',')}]" + end + + def tipo_cambio value = '' + arr_tipo_cambio.push value + @datos["TipoCambioDR"] = "[#{arr_tipo_cambio.join(',')}]" + end + + def metodo_pago value + arr_metodo_pago.push value + @datos["MetodoDePagoDR"] = "[#{arr_metodo_pago.join(',')}]" + end + + def numero_parcialidad value = '' + arr_num_parcialidad.push value + @datos["NumParcialidad"] = "[#{arr_num_parcialidad.join(',')}]" + end + + def importe_saldo_anterior value = '' + arr_imp_saldo_ant.push value + @datos["ImpSaldoAnt"] = "[#{arr_imp_saldo_ant.join(',')}]" + end + + def importe_pagado value = '' + arr_imp_pagado.push value + @datos["ImpPagado"] = "[#{arr_imp_pagado.join(',')}]" + end + + def importe_saldo_insoluto value = '' + arr_saldo_insoluto.push value + @datos["ImpSaldoInsoluto"] = "[#{arr_saldo_insoluto.join(',')}]" + end + end +end diff --git a/lib/fm_layout/fm_layout_pago.rb b/lib/fm_layout/fm_layout_pago.rb new file mode 100644 index 0000000..15337af --- /dev/null +++ b/lib/fm_layout/fm_layout_pago.rb @@ -0,0 +1,34 @@ +require "fm_layout/fm_layout" +require "fm_layout/recibo_pago" +require "fm_layout/pago" + +module FmLayout + class FmLayoutPago < FmLayout + def initialize + super + @encabezado = ReciboPago.new + @pago = Pago.new + end + + def pago + yield(@pago) if block_given? + @pago + end + + def to_h + super.merge(obtener_hash_pago) + end + + def to_s + salida = super + salida += @pago.to_s + salida + end + + private + + def obtener_hash_pago + {'Pago' => @pago.to_h } + end + end +end diff --git a/lib/fm_layout/pago.rb b/lib/fm_layout/pago.rb new file mode 100644 index 0000000..b370ce0 --- /dev/null +++ b/lib/fm_layout/pago.rb @@ -0,0 +1,59 @@ +require 'fm_layout/fm_seccion' +require 'fm_layout/documento_relacionado' + +module FmLayout + class Pago + include FmSeccion + + def initialize + @titulo = "Pago#1" + @datos = {} + @documento_relacionado = DocumentoRelacionado.new + end + + def self.campos_vs_metodos + { + 'FechaPago' => 'fecha_pago', + 'FormaDePagoP' => 'forma_de_pago', + 'MonedaP' => 'moneda', + 'TipoCambioP' => 'tipo_cambio', + 'Monto' => 'monto', + 'NumOperacion' => 'numero_operacion', + 'RfcEmisorCtaOrd' => 'rfc_emisor_cuenta_ordenante', + 'NomBancoOrdExt' => 'nombre_banco_ordenante', + 'CtaOrdenante' => 'numero_cuenta_ordenante', + 'RfcEmisorCtaBen' => 'rfc_emisor_cuenta_beneficiario', + 'CtaBeneficiario' => 'numero_cuenta_beneficiario', + 'TipoCadPago' => 'tipo_cadena_pago', + 'CertPago' => 'cetificado_pago', + 'CadPago' => 'cadena_pago', + 'SelloPago' => 'sello_pago', + } + end + + def documento_relacionado + if block_given? + yield @documento_relacionado + @datos["DoctoRelacionado.IdDocumento"] = @documento_relacionado.datos["IdDocumento"] + @datos["DoctoRelacionado.Serie"] = @documento_relacionado.datos["Serie"] + @datos["DoctoRelacionado.Folio"] = @documento_relacionado.datos["Folio"] + @datos["DoctoRelacionado.MonedaDR"] = @documento_relacionado.datos["MonedaDR"] + @datos["DoctoRelacionado.TipoCambioDR"] = @documento_relacionado.datos["TipoCambioDR"] + @datos["DoctoRelacionado.MetodoDePagoDR"] = @documento_relacionado.datos["MetodoDePagoDR"] + @datos["DoctoRelacionado.NumParcialidad"] = @documento_relacionado.datos["NumParcialidad"] + @datos["DoctoRelacionado.ImpSaldoAnt"] = @documento_relacionado.datos["ImpSaldoAnt"] + @datos["DoctoRelacionado.ImpPagado"] = @documento_relacionado.datos["ImpPagado"] + @datos["DoctoRelacionado.ImpSaldoInsoluto"] = @documento_relacionado.datos["ImpSaldoInsoluto"] + else + @documento_relacionado + end + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + end +end diff --git a/lib/fm_layout/recibo_pago.rb b/lib/fm_layout/recibo_pago.rb new file mode 100644 index 0000000..0012b71 --- /dev/null +++ b/lib/fm_layout/recibo_pago.rb @@ -0,0 +1,42 @@ +require 'fm_layout/fm_seccion' +module FmLayout + class ReciboPago + include FmSeccion + + def initialize + @titulo= 'ReciboPagos' + @datos= {} + valores_iniciales + end + + def self.campos_vs_metodos + { + 'Serie' => 'serie', + 'Folio' => 'folio', + 'Fecha' => 'fecha', + 'NoCertificado' => 'numero_de_certificado', + 'Moneda' => 'moneda', + 'TipoDeComprobante' => 'tipo_de_comprobante', + 'LugarExpedicion' => 'lugar_de_expedicion', + 'TipoCambio' => 'tipo_de_cambio' + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + + private + + def valores_iniciales + @datos['Fecha'] = nil + @datos['Folio'] = nil + @datos['NoCertificado'] = nil + end + end + +end diff --git a/spec/fm_layout_recibo_pago_spec.rb b/spec/fm_layout_recibo_pago_spec.rb new file mode 100644 index 0000000..ff625e5 --- /dev/null +++ b/spec/fm_layout_recibo_pago_spec.rb @@ -0,0 +1,189 @@ +# encoding: utf-8 +require 'spec_helper' + +describe 'DSL para generar el layout_recibo_pago de Facturación moderna' do + context 'ReciboElectronicoPago' do + context 'llenando todos los campos' do + let(:hora) {Time.now.strftime("%FT%T")} + let(:prueba) do + # DSL + FmLayout.define_layout_recibo_pago do |f| + f.encabezado do |e| + e.serie 'A' + e.folio 10 + e.fecha hora + e.numero_de_certificado '111222111' + e.moneda 'MXN' + e.tipo_de_comprobante 'P' + e.lugar_de_expedicion '68000' + end + f.datos_adicionales do |d| + d.tipo_de_documento 'Recibo electrónico de pago' + d.observaciones 'Efectos Fiscales al Pago' + d.id_transaccion 5 + end + f.emisor do |e| + e.rfc 'TUMG620310R95' + e.nombre 'FACTURACION MODERNA S.A de C.V.' + e.regimen_fiscal '612' + end + f.receptor do |r| + r.rfc 'XAXX010101000' + r.nombre 'PUBLICO EN GENERAL' + end + f.pago do |p| + p.fecha_pago '2017-07-02T16:47:00' + p.forma_de_pago '01' + p.moneda 'MXN' + p.monto '1800' + p.numero_operacion '1' + p.rfc_emisor_cuenta_ordenante 'XAXX010101000' + p.nombre_banco_ordenante 'Banamex' + p.numero_cuenta_ordenante '1234-1234-1234-1234' + p.rfc_emisor_cuenta_beneficiario 'TUMG620310R95' + p.numero_cuenta_beneficiario '4321-4321-4321-4321' + p.tipo_cadena_pago 'tipo_cadena' + p.cetificado_pago 'certificado' + p.cadena_pago 'cadena' + p.sello_pago 'sello' + + p.documento_relacionado do |dr| + dr.id_documento "00000000-0000-0000-0000-000000000000" + dr.serie 'RP' + dr.folio '01' + dr.moneda 'MXN' + dr.tipo_cambio + dr.metodo_pago 'PPD' + dr.numero_parcialidad '1' + dr.importe_saldo_anterior 2500 + dr.importe_pagado 2000 + dr.importe_saldo_insoluto 500 + end + + p.documento_relacionado do |dr| + dr.id_documento "00000000-0000-0000-0000-000000000000" + dr.serie 'RP' + dr.folio '02' + dr.moneda 'MXN' + dr.tipo_cambio + dr.metodo_pago 'PPD' + dr.numero_parcialidad '01' + dr.importe_saldo_anterior 3500 + dr.importe_pagado 500 + dr.importe_saldo_insoluto 3000 + end + end + end + end + + context 'recibo pagos' do + let(:recibo_pagos){ prueba.to_h['ReciboPagos'] } + it{ expect(recibo_pagos['Serie']).to eq('A') } + it{ expect(recibo_pagos['Folio']).to eq(10) } + it{ expect(recibo_pagos['Fecha']).to eq(hora) } + it{ expect(recibo_pagos['NoCertificado']).to eq('111222111') } + it{ expect(recibo_pagos['Moneda']).to eq('MXN') } + it{ expect(recibo_pagos['TipoDeComprobante']).to eq('P') } + it{ expect(recibo_pagos['LugarExpedicion']).to eq('68000') } + end + + context 'datos adicionales' do + let(:datos_adicionales){ prueba.to_h['DatosAdicionales'] } + it{ expect(datos_adicionales['tipoDocumento']).to eq('Recibo electrónico de pago') } + it{ expect(datos_adicionales['observaciones']).to eq('Efectos Fiscales al Pago') } + it{ expect(datos_adicionales['TransID']).to eq(5) } + end + + context 'emisor' do + let(:emisor){ prueba.to_h['Emisor'] } + it{ expect(emisor['Rfc']).to eq('TUMG620310R95') } + it{ expect(emisor['Nombre']).to eq('FACTURACION MODERNA S.A de C.V.') } + it{ expect(emisor['RegimenFiscal']).to eq('612') } + end + + context 'receptor' do + let(:receptor){ prueba.to_h['Receptor'] } + it{ expect(receptor['Rfc']).to eq('XAXX010101000') } + it{ expect(receptor['Nombre']).to eq('PUBLICO EN GENERAL') } + end + + context "pago" do + let(:pago){ prueba.to_h['Pago']['Pago#1'] } + it { expect(pago['FechaPago']).to eq '2017-07-02T16:47:00' } + it { expect(pago['FormaDePagoP']).to eq '01' } + it { expect(pago['MonedaP']).to eq 'MXN' } + it { expect(pago['Monto']).to eq '1800' } + it { expect(pago['NumOperacion']).to eq '1' } + it { expect(pago['RfcEmisorCtaOrd']).to eq 'XAXX010101000' } + it { expect(pago['NomBancoOrdExt']).to eq 'Banamex' } + it { expect(pago['CtaOrdenante']).to eq '1234-1234-1234-1234' } + it { expect(pago['RfcEmisorCtaBen']).to eq 'TUMG620310R95' } + it { expect(pago['CtaBeneficiario']).to eq '4321-4321-4321-4321' } + it { expect(pago['TipoCadPago']).to eq 'tipo_cadena' } + it { expect(pago['CertPago']).to eq 'certificado' } + it { expect(pago['CadPago']).to eq 'cadena' } + it { expect(pago['SelloPago']).to eq 'sello' } + + it { expect(pago['DoctoRelacionado.IdDocumento']).to eq '[00000000-0000-0000-0000-000000000000,00000000-0000-0000-0000-000000000000]' } + it { expect(pago['DoctoRelacionado.Serie']).to eq '[RP,RP]' } + it { expect(pago['DoctoRelacionado.Folio']).to eq '[01,02]' } + it { expect(pago['DoctoRelacionado.MonedaDR']).to eq '[MXN,MXN]' } + it { expect(pago['DoctoRelacionado.TipoCambioDR']).to eq '[,]' } + it { expect(pago['DoctoRelacionado.MetodoDePagoDR']).to eq '[PPD,PPD]' } + it { expect(pago['DoctoRelacionado.NumParcialidad']).to eq '[1,01]' } + it { expect(pago['DoctoRelacionado.ImpSaldoAnt']).to eq '[2500,3500]' } + it { expect(pago['DoctoRelacionado.ImpPagado']).to eq '[2000,500]' } + it { expect(pago['DoctoRelacionado.ImpSaldoInsoluto']).to eq '[500,3000]' } + end # context Pago1 + + context 'salida en texto' do + let(:salida){ prueba.to_s } + it{ expect(salida).to match(/\[ReciboPagos\]/) } + it{ expect(salida).to match(/\[DatosAdicionales\]/) } + it{ expect(salida).to match(/\[Emisor\]/) } + it{ expect(salida).to match(/\[Receptor\]/) } + it{ expect(salida).to match(/\[Pago#1\]/) } + end + + end + + context 'llenado sin campos' do + let(:prueba) do + # DSL + FmLayout.define_layout_recibo_pago do |f| + f.encabezado do |e| + end + f.datos_adicionales do |d| + d.id_transaccion 5 + end + f.emisor do |e| + end + f.receptor do |r| + end + end + end + + context 'recibo pagos' do + let(:encabezado){ prueba.to_h['ReciboPagos'] } + it{ expect(encabezado['Fecha']).to be_nil } + it{ expect(encabezado['Folio']).to be_nil } + it{ expect(encabezado['NoCertificado']).to be_nil } + end + + context 'datos adicionales' do + let(:datos_adicionales){ prueba.to_h['DatosAdicionales'] } + it{ expect(datos_adicionales['tipoDocumento']).to eq('Factura') } + end + + context 'salida en texto' do + let(:salida){ prueba.to_s } + it{ expect(salida).to match(/\[ReciboPagos\]/) } + it{ expect(salida).to match(/\[DatosAdicionales\]/) } + it{ expect(salida).to match("TransID|5") } + it{ expect(salida).to match(/\[Emisor\]/) } + it{ expect(salida).to match(/\[Receptor\]/) } + it{ expect(salida).to match(/\[Pago#1\]/) } + end + end + end +end From 2ade52b869ad01b80cf73c378cc7a0ebafff92ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Thu, 12 Oct 2017 13:34:46 -0500 Subject: [PATCH 37/56] Remove default value of unidad in concepto --- lib/fm_layout/concepto.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/fm_layout/concepto.rb b/lib/fm_layout/concepto.rb index a4e4b6c..48b310d 100644 --- a/lib/fm_layout/concepto.rb +++ b/lib/fm_layout/concepto.rb @@ -79,7 +79,6 @@ def impuesto_retenido def valores_iniciales @datos['Cantidad'] = 1 - @datos['Unidad'] = 'ACT' end end end From 7a84247dc06288711e1671bc1fea0fac4947c2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 1 Nov 2017 13:41:25 -0600 Subject: [PATCH 38/56] Add support to receive more than one pago in ReciboElectronicoPagoLayout --- lib/fm_layout/fm_layout_pago.rb | 17 +++++--- lib/fm_layout/pago.rb | 4 +- spec/fm_layout_recibo_pago_spec.rb | 63 ++++++++++++++++++++++++++++-- 3 files changed, 74 insertions(+), 10 deletions(-) diff --git a/lib/fm_layout/fm_layout_pago.rb b/lib/fm_layout/fm_layout_pago.rb index 15337af..6ce0ca0 100644 --- a/lib/fm_layout/fm_layout_pago.rb +++ b/lib/fm_layout/fm_layout_pago.rb @@ -7,12 +7,19 @@ class FmLayoutPago < FmLayout def initialize super @encabezado = ReciboPago.new - @pago = Pago.new + @pagos = [] + @num_pago = 0 end def pago - yield(@pago) if block_given? - @pago + @num_pago += 1 + pago = Pago.new @num_pago + if block_given? + yield(pago) if block_given? + @pagos << pago + else + pago + end end def to_h @@ -21,14 +28,14 @@ def to_h def to_s salida = super - salida += @pago.to_s + salida += @pagos.map(&:to_s).reduce(:+).to_s salida end private def obtener_hash_pago - {'Pago' => @pago.to_h } + { 'Pagos' => @pagos.map(&:to_h) } end end end diff --git a/lib/fm_layout/pago.rb b/lib/fm_layout/pago.rb index b370ce0..4c6e6e0 100644 --- a/lib/fm_layout/pago.rb +++ b/lib/fm_layout/pago.rb @@ -5,8 +5,8 @@ module FmLayout class Pago include FmSeccion - def initialize - @titulo = "Pago#1" + def initialize num_pago + @titulo = "Pago##{num_pago}" @datos = {} @documento_relacionado = DocumentoRelacionado.new end diff --git a/spec/fm_layout_recibo_pago_spec.rb b/spec/fm_layout_recibo_pago_spec.rb index ff625e5..529f9eb 100644 --- a/spec/fm_layout_recibo_pago_spec.rb +++ b/spec/fm_layout_recibo_pago_spec.rb @@ -73,6 +73,35 @@ dr.importe_saldo_insoluto 3000 end end + f.pago do |p| + p.fecha_pago '2017-07-02T16:47:00' + p.forma_de_pago '01' + p.moneda 'MXN' + p.monto '1800' + p.numero_operacion '1' + p.rfc_emisor_cuenta_ordenante 'XAXX010101000' + p.nombre_banco_ordenante 'Banamex' + p.numero_cuenta_ordenante '1234-1234-1234-1234' + p.rfc_emisor_cuenta_beneficiario 'TUMG620310R95' + p.numero_cuenta_beneficiario '4321-4321-4321-4321' + p.tipo_cadena_pago 'tipo_cadena' + p.cetificado_pago 'certificado' + p.cadena_pago 'cadena' + p.sello_pago 'sello' + + p.documento_relacionado do |dr| + dr.id_documento "00000000-0000-0000-0000-000000000000" + dr.serie 'RP' + dr.folio '01' + dr.moneda 'MXN' + dr.tipo_cambio + dr.metodo_pago 'PPD' + dr.numero_parcialidad '1' + dr.importe_saldo_anterior 2500 + dr.importe_pagado 2000 + dr.importe_saldo_insoluto 500 + end + end end end @@ -107,8 +136,8 @@ it{ expect(receptor['Nombre']).to eq('PUBLICO EN GENERAL') } end - context "pago" do - let(:pago){ prueba.to_h['Pago']['Pago#1'] } + context "pago#1" do + let(:pago){ prueba.to_h['Pagos'][0]['Pago#1'] } it { expect(pago['FechaPago']).to eq '2017-07-02T16:47:00' } it { expect(pago['FormaDePagoP']).to eq '01' } it { expect(pago['MonedaP']).to eq 'MXN' } @@ -136,6 +165,35 @@ it { expect(pago['DoctoRelacionado.ImpSaldoInsoluto']).to eq '[500,3000]' } end # context Pago1 + context "pago#2" do + let(:pago){ prueba.to_h['Pagos'][1]['Pago#2'] } + it { expect(pago['FechaPago']).to eq '2017-07-02T16:47:00' } + it { expect(pago['FormaDePagoP']).to eq '01' } + it { expect(pago['MonedaP']).to eq 'MXN' } + it { expect(pago['Monto']).to eq '1800' } + it { expect(pago['NumOperacion']).to eq '1' } + it { expect(pago['RfcEmisorCtaOrd']).to eq 'XAXX010101000' } + it { expect(pago['NomBancoOrdExt']).to eq 'Banamex' } + it { expect(pago['CtaOrdenante']).to eq '1234-1234-1234-1234' } + it { expect(pago['RfcEmisorCtaBen']).to eq 'TUMG620310R95' } + it { expect(pago['CtaBeneficiario']).to eq '4321-4321-4321-4321' } + it { expect(pago['TipoCadPago']).to eq 'tipo_cadena' } + it { expect(pago['CertPago']).to eq 'certificado' } + it { expect(pago['CadPago']).to eq 'cadena' } + it { expect(pago['SelloPago']).to eq 'sello' } + + it { expect(pago['DoctoRelacionado.IdDocumento']).to eq '[00000000-0000-0000-0000-000000000000]' } + it { expect(pago['DoctoRelacionado.Serie']).to eq '[RP]' } + it { expect(pago['DoctoRelacionado.Folio']).to eq '[01]' } + it { expect(pago['DoctoRelacionado.MonedaDR']).to eq '[MXN]' } + it { expect(pago['DoctoRelacionado.TipoCambioDR']).to eq '[]' } + it { expect(pago['DoctoRelacionado.MetodoDePagoDR']).to eq '[PPD]' } + it { expect(pago['DoctoRelacionado.NumParcialidad']).to eq '[1]' } + it { expect(pago['DoctoRelacionado.ImpSaldoAnt']).to eq '[2500]' } + it { expect(pago['DoctoRelacionado.ImpPagado']).to eq '[2000]' } + it { expect(pago['DoctoRelacionado.ImpSaldoInsoluto']).to eq '[500]' } + end # context Pago1 + context 'salida en texto' do let(:salida){ prueba.to_s } it{ expect(salida).to match(/\[ReciboPagos\]/) } @@ -182,7 +240,6 @@ it{ expect(salida).to match("TransID|5") } it{ expect(salida).to match(/\[Emisor\]/) } it{ expect(salida).to match(/\[Receptor\]/) } - it{ expect(salida).to match(/\[Pago#1\]/) } end end end From 14a18e6e9221b9ee3bd3d4827fe84efbb2834188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 10 Jan 2018 13:28:16 -0600 Subject: [PATCH 39/56] Update ruby-version to 2.5.0 --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 0bee604..437459c 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.3.3 +2.5.0 From 9f239652085a2ed482e7c904d03efe92c4996b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 10 Jan 2018 13:35:43 -0600 Subject: [PATCH 40/56] Updating ruby-version in travis file --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 81ead5d..3f499a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: ruby rvm: - 2.0.0 - - 2.3.3 + - 2.5.0 From e1f987823bc133c4a4fa9b10699d8e5b5a335d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 10 Jan 2018 14:12:03 -0600 Subject: [PATCH 41/56] Fix problem ruby-version in travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3f499a6..0ff2947 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,3 +2,5 @@ language: ruby rvm: - 2.0.0 - 2.5.0 +before_install: + 'gem update --system' From ac6c613cbd550d1fb1770895eba16d9f4947f881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Silva=20Mart=C3=ADnez?= Date: Wed, 10 Jan 2018 14:27:21 -0600 Subject: [PATCH 42/56] Update gems --- Gemfile.lock | 54 +++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 166cf56..3c1d448 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,38 +6,43 @@ PATH GEM remote: https://rubygems.org/ specs: - coveralls (0.8.16) + coderay (1.1.2) + coveralls (0.8.21) json (>= 1.8, < 3) - simplecov (~> 0.12.0) - term-ansicolor (~> 1.3.0) - thor (~> 0.19.1) - tins (>= 1.6.0, < 2) - diff-lcs (1.2.5) + simplecov (~> 0.14.1) + term-ansicolor (~> 1.3) + thor (~> 0.19.4) + tins (~> 1.6) + diff-lcs (1.3) docile (1.1.5) - json (2.0.2) - rake (11.3.0) - rspec (3.5.0) - rspec-core (~> 3.5.0) - rspec-expectations (~> 3.5.0) - rspec-mocks (~> 3.5.0) - rspec-core (3.5.4) - rspec-support (~> 3.5.0) - rspec-expectations (3.5.0) + json (2.1.0) + method_source (0.9.0) + pry (0.11.3) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + rake (12.3.0) + rspec (3.7.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-core (3.7.1) + rspec-support (~> 3.7.0) + rspec-expectations (3.7.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.5.0) - rspec-mocks (3.5.0) + rspec-support (~> 3.7.0) + rspec-mocks (3.7.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.5.0) - rspec-support (3.5.0) - simplecov (0.12.0) + rspec-support (~> 3.7.0) + rspec-support (3.7.0) + simplecov (0.14.1) docile (~> 1.1.0) json (>= 1.8, < 3) simplecov-html (~> 0.10.0) - simplecov-html (0.10.0) - term-ansicolor (1.3.2) + simplecov-html (0.10.2) + term-ansicolor (1.6.0) tins (~> 1.0) thor (0.19.4) - tins (1.13.0) + tins (1.16.3) PLATFORMS ruby @@ -46,8 +51,9 @@ DEPENDENCIES bundler (~> 1.3) coveralls fm_layout! + pry rake rspec BUNDLED WITH - 1.13.6 + 1.16.1 From a4be905fb81cc909da08b265e5bd23862cd5bb8b Mon Sep 17 00:00:00 2001 From: Azarel Doroteo Pacheco Date: Tue, 14 May 2019 21:58:45 -0500 Subject: [PATCH 43/56] Update ruby to 2.5.5 --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 437459c..0cadbc1 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.5.0 +2.5.5 From 1e6edf08394a584946bec575b99c356a135ef3d4 Mon Sep 17 00:00:00 2001 From: Azarel Doroteo Pacheco Date: Tue, 14 May 2019 21:59:12 -0500 Subject: [PATCH 44/56] Add cfdi_relacionados to fm_layout_nomina --- lib/fm_layout/fm_layout_nomina.rb | 15 ++++++++++++++- spec/fm_layout_nomina_spec.rb | 15 +++++++++++++++ spec/fm_layout_spec.rb | 27 +++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/lib/fm_layout/fm_layout_nomina.rb b/lib/fm_layout/fm_layout_nomina.rb index ac7e830..f8bbbcc 100644 --- a/lib/fm_layout/fm_layout_nomina.rb +++ b/lib/fm_layout/fm_layout_nomina.rb @@ -2,6 +2,7 @@ require 'fm_layout/entidad_sncf' require 'fm_layout/recibo_nomina' require 'fm_layout/nomina/nomina' +require 'fm_layout/cfdi_relacionados' module FmLayout class FmLayoutNomina @@ -10,6 +11,7 @@ def initialize @datos_adicionales = DatosAdicionales.new @emisor = Nomina::Emisor.new @receptor= Nomina::Receptor.new + @cfdi_relacionados = CfdiRelacionados.new @conceptos = [] @num_concepto = 0 end @@ -75,8 +77,18 @@ def nomina end end + def cfdi_relacionados + if block_given? + yield(@cfdi_relacionados) + else + @cfdi_relacionados + end + end + def to_s - salida = @recibo_nomina.to_s + @datos_adicionales.to_s + @emisor.to_s + @entidad_sncf.to_s + @receptor.to_s + salida = @recibo_nomina.to_s + salida += @cfdi_relacionados.to_s if @cfdi_relacionados.con_relaciones? + salida += @datos_adicionales.to_s + @emisor.to_s + @entidad_sncf.to_s + @receptor.to_s salida += @conceptos.map(&:to_s).reduce(:+).to_s salida += @nomina.to_s salida @@ -85,6 +97,7 @@ def to_s def to_h recibo_nomina.to_h .merge(@datos_adicionales.to_h) + .merge(@cfdi_relacionados.to_h) .merge(@emisor.to_h) .merge(@entidad_sncf.to_h) .merge(@expedido_en.to_h) diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 8597bfc..ae078c9 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -180,11 +180,17 @@ end end + + f.cfdi_relacionados do |cr| + cr.tipo_relacion "Un tipo de relacion" + cr.uuids "UUIDS" + end end end context 'recibo_nomina' do let(:recibo_nomina){ prueba.to_h['ReciboNomina'] } + it{ expect(recibo_nomina['serie']).to eq('RN') } it{ expect(recibo_nomina['folio']).to eq('105') } it{ expect(recibo_nomina['fecha']).to eq('2016-11-29T16:07:43') } @@ -404,6 +410,12 @@ end end + context "#cfdi_relacionados" do + let(:cfdi_relacionados) { prueba.to_h['CfdiRelacionados'] } + + it { expect(cfdi_relacionados['TipoRelacion']).to eq("Un tipo de relacion")} + it { expect(cfdi_relacionados['UUID']).to eq("[UUIDS]")} + end # context #cfdi_relacionados end context 'salida en texto' do @@ -420,6 +432,9 @@ it{ expect(salida).to match(/\[SeparacionIndemnizacion\]/) } it{ expect(salida).to match(/\[Deduccion#1\]/) } it{ expect(salida).to match(/\[Incapacidad#1\]/) } + it { expect(salida).to match(/\[CfdiRelacionados\]/) } + it { expect(salida).to match(/TipoRelacion=Un tipo de relacion/) } + it { expect(salida).to match(/UUID=\[UUIDS\]/) } end end end diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index 99a5093..320c59d 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -23,24 +23,29 @@ e.metodo_de_pago 'PUE' e.lugar_de_expedicion '68000' end + f.cfdi_relacionados do |cfdi| cfdi.tipo_relacion '04' cfdi.uuids "FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623" end + f.datos_adicionales do |d| d.tipo_de_documento 'Factura' d.observaciones 'Efectos Fiscales al Pago' d.id_transaccion 5 end + f.emisor do |e| e.rfc 'TUMG620310R95' e.nombre 'FACTURACION MODERNA S.A de C.V.' e.regimen_fiscal '612' end + f.receptor do |r| r.rfc 'XAXX010101000' r.nombre 'PUBLICO EN GENERAL' end + f.concepto do |c| c.clave_producto_servicio '01010101' c.numero_de_identificacion '111222333' @@ -85,6 +90,7 @@ i.importe 20 end end + f.concepto do |c| c.clave_producto_servicio '10101502' c.numero_de_identificacion '111222334' @@ -111,6 +117,7 @@ i.importe 4 end end + f.impuesto_trasladado do |i| i.total_impuestos 19.2 i.impuesto "002" @@ -118,30 +125,36 @@ i.tasa_o_cuota 0.16 i.importe 19.2 end + f.impuesto_trasladado_local do |i| i.impuesto 'ISH' i.importe 110.0 i.tasa 0.11 end + f.impuesto_retenido do |i| i.total_impuestos 24 i.impuesto "001" i.importe 24 end + f.impuesto_retenido_local do |i| i.impuesto 'IVA LOCAL' i.importe 110.00 i.tasa 0.16 end + f.impuesto_retenido_local do |i| i.impuesto 'ISR LOCAL' i.importe 110.00 i.tasa 0.16 end + f.complemento_ine do |i| i.tipo_proceso 'Ordinario' i.tipo_comite 'Ejecutivo Estatal' end + f.entidad_ine do |e| e.clave_entidad 'OAX' e.id_contabilidad '000516' @@ -313,39 +326,45 @@ FmLayout.define_layout do |f| f.encabezado do |e| end + f.datos_adicionales do |d| d.id_transaccion 5 end + f.emisor do |e| end + f.receptor do |r| end + f.concepto do |c| end + f.impuesto_trasladado do |i| end + f.impuesto_retenido do |i| end end end context 'encabezado' do - let(:encabezado){ prueba.to_h['ComprobanteFiscalDigital'] } + let(:encabezado) { prueba.to_h['ComprobanteFiscalDigital'] } it{ expect(encabezado['Version']).to eq('3.3') } end context 'datos adicionales' do - let(:datos_adicionales){ prueba.to_h['DatosAdicionales'] } + let(:datos_adicionales) { prueba.to_h['DatosAdicionales'] } it{ expect(datos_adicionales['tipoDocumento']).to eq('Factura') } end context 'primer concepto' do - let(:concepto){ prueba.to_h['Conceptos'].first['Concepto#1'] } + let(:concepto) { prueba.to_h['Conceptos'].first['Concepto#1'] } it{ expect(concepto['Cantidad']).to eq(1) } end context 'salida en texto' do - let(:salida){ prueba.to_s } + let(:salida) { prueba.to_s } it{ expect(salida).to match(/\[ComprobanteFiscalDigital\]/) } it{ expect(salida).to match(/\[DatosAdicionales\]/) } it{ expect(salida).to match("TransID|5") } From f287a35c6b141b5a41dc5a8a4066f3da5e118db7 Mon Sep 17 00:00:00 2001 From: Azarel Doroteo Pacheco Date: Tue, 14 May 2019 22:01:20 -0500 Subject: [PATCH 45/56] Fix ruby version for travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c905c3a..2844847 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: ruby rvm: - 2.0.0 - - 2.5.0 + - 2.5.5 before_install: - 'gem update --system' From 978095f1c5c823b1ad2fb426dee5f2f90b53eb56 Mon Sep 17 00:00:00 2001 From: Kevin Hernandez Date: Fri, 22 Apr 2022 18:48:52 -0500 Subject: [PATCH 46/56] feat: Add Template General --- lib/fm_layout/comprobante_fiscal_digital.rb | 6 +- lib/fm_layout/concepto.rb | 4 +- lib/fm_layout/fm_layout.rb | 1 + lib/fm_layout/impuesto_trasladado.rb | 1 + lib/fm_layout/receptor.rb | 8 +- lib/fm_layout/recibo_nomina.rb | 2 +- spec/fm_layout_spec.rb | 25 +++- template.txt | 130 ++++++++++++++++++++ 8 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 template.txt diff --git a/lib/fm_layout/comprobante_fiscal_digital.rb b/lib/fm_layout/comprobante_fiscal_digital.rb index 156cf9d..3df122f 100644 --- a/lib/fm_layout/comprobante_fiscal_digital.rb +++ b/lib/fm_layout/comprobante_fiscal_digital.rb @@ -24,7 +24,8 @@ def self.campos_vs_metodos 'TipoDeComprobante' => 'tipo_de_comprobante', 'MetodoPago' => 'metodo_de_pago', 'LugarExpedicion' => 'lugar_de_expedicion', - 'TipoCambio' => 'tipo_de_cambio' + 'TipoCambio' => 'tipo_de_cambio', + 'Exportacion' => 'exportacion' } end @@ -39,13 +40,14 @@ def self.campos_vs_metodos private def valores_iniciales - @datos['Version'] = '3.3' + @datos['Version'] = '4.0' @datos['Fecha'] = nil @datos['Folio'] = nil @datos['NoCertificado'] = nil @datos['SubTotal'] = nil @datos['Descuento'] = nil @datos['Total'] = nil + @datos['Exportacion'] = '01' end end diff --git a/lib/fm_layout/concepto.rb b/lib/fm_layout/concepto.rb index 48b310d..817264e 100644 --- a/lib/fm_layout/concepto.rb +++ b/lib/fm_layout/concepto.rb @@ -26,6 +26,7 @@ def self.campos_vs_metodos 'Importe' => 'importe', 'Descuento' => 'descuento', 'CuentaPredial' => 'cuenta_predial', + 'ObjetoImp' => 'objeto_imp' } end @@ -78,7 +79,8 @@ def impuesto_retenido private def valores_iniciales - @datos['Cantidad'] = 1 + @datos['Cantidad'] = 1 + @datos['ObjetoImp'] = '02' end end end diff --git a/lib/fm_layout/fm_layout.rb b/lib/fm_layout/fm_layout.rb index 837b65d..c2cc652 100644 --- a/lib/fm_layout/fm_layout.rb +++ b/lib/fm_layout/fm_layout.rb @@ -11,6 +11,7 @@ require 'fm_layout/complemento_ine' require 'fm_layout/entidad_ine' require 'fm_layout/cfdi_relacionados' +require 'pry' module FmLayout class FmLayout diff --git a/lib/fm_layout/impuesto_trasladado.rb b/lib/fm_layout/impuesto_trasladado.rb index b9c0bc8..99115a1 100644 --- a/lib/fm_layout/impuesto_trasladado.rb +++ b/lib/fm_layout/impuesto_trasladado.rb @@ -1,4 +1,5 @@ require 'fm_layout/fm_seccion' +require 'pry' module FmLayout class ImpuestoTrasladado diff --git a/lib/fm_layout/receptor.rb b/lib/fm_layout/receptor.rb index 0e7f17e..891d148 100644 --- a/lib/fm_layout/receptor.rb +++ b/lib/fm_layout/receptor.rb @@ -11,9 +11,11 @@ def initialize def self.campos_vs_metodos { - 'Rfc' => 'rfc', - 'Nombre' => 'nombre', - 'UsoCFDI' => 'uso_cfdi', + 'Rfc' => 'rfc', + 'Nombre' => 'nombre', + 'UsoCFDI' => 'uso_cfdi', + 'DomicilioFiscalReceptor' => 'domicilio_fiscal', + 'RegimenFiscalReceptor' => 'regimen_fiscal' } end diff --git a/lib/fm_layout/recibo_nomina.rb b/lib/fm_layout/recibo_nomina.rb index eb322ab..89173a5 100644 --- a/lib/fm_layout/recibo_nomina.rb +++ b/lib/fm_layout/recibo_nomina.rb @@ -34,7 +34,7 @@ def self.campos_vs_metodos private def valores_iniciales - @datos['Version'] = '3.3' + @datos['Version'] = '4.0' @datos['serie'] = nil @datos['folio'] = nil @datos['fecha'] = nil diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index 320c59d..8b8da53 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -36,7 +36,7 @@ end f.emisor do |e| - e.rfc 'TUMG620310R95' + e.rfc 'XIA190128J61' e.nombre 'FACTURACION MODERNA S.A de C.V.' e.regimen_fiscal '612' end @@ -44,6 +44,9 @@ f.receptor do |r| r.rfc 'XAXX010101000' r.nombre 'PUBLICO EN GENERAL' + r.uso_cfdi 'G03' + r.domicilio_fiscal '71243' + r.regimen_fiscal '616' end f.concepto do |c| @@ -56,6 +59,7 @@ c.valor_unitario 110.00 c.importe 110.00 c.descuento 10.00 + c.objeto_imp '02' #c.cuenta_predial '123-132123' c.partes do |c| @@ -124,6 +128,7 @@ i.tipo_factor "Tasa" i.tasa_o_cuota 0.16 i.importe 19.2 + i.base 120 end f.impuesto_trasladado_local do |i| @@ -164,7 +169,7 @@ context 'comprobante fiscal digital' do let(:comprobante_fiscal_digital){ prueba.to_h['ComprobanteFiscalDigital'] } - it{ expect(comprobante_fiscal_digital['Version']).to eq('3.3') } + it{ expect(comprobante_fiscal_digital['Version']).to eq('4.0') } it{ expect(comprobante_fiscal_digital['Serie']).to eq('A') } it{ expect(comprobante_fiscal_digital['Folio']).to eq(10) } it{ expect(comprobante_fiscal_digital['Fecha']).to eq(hora) } @@ -178,6 +183,7 @@ it{ expect(comprobante_fiscal_digital['TipoDeComprobante']).to eq('I') } it{ expect(comprobante_fiscal_digital['MetodoPago']).to eq('PUE') } it{ expect(comprobante_fiscal_digital['LugarExpedicion']).to eq('68000') } + it{ expect(comprobante_fiscal_digital['Exportacion']).to eq('01') } end context "cfdi relacionados" do @@ -195,7 +201,7 @@ context 'emisor' do let(:emisor){ prueba.to_h['Emisor'] } - it{ expect(emisor['Rfc']).to eq('TUMG620310R95') } + it{ expect(emisor['Rfc']).to eq('XIA190128J61') } it{ expect(emisor['Nombre']).to eq('FACTURACION MODERNA S.A de C.V.') } it{ expect(emisor['RegimenFiscal']).to eq('612') } end @@ -203,7 +209,10 @@ context 'receptor' do let(:receptor){ prueba.to_h['Receptor'] } it{ expect(receptor['Rfc']).to eq('XAXX010101000') } + it{ expect(receptor['UsoCFDI']).to eq('G03') } it{ expect(receptor['Nombre']).to eq('PUBLICO EN GENERAL') } + it{ expect(receptor['DomicilioFiscalReceptor']).to eq('71243') } + it{ expect(receptor['RegimenFiscalReceptor']).to eq('616') } end context 'primer concepto' do @@ -318,6 +327,14 @@ it{ expect(salida).to match(/\[ComplementoINE\]/) } it{ expect(salida).to match(/\[Entidad\]/) } end + + context 'put file' do + it { + file = File.open('template.txt', 'w') + file.write(prueba) + file.close + } + end end context 'llenado sin campos' do @@ -350,7 +367,7 @@ context 'encabezado' do let(:encabezado) { prueba.to_h['ComprobanteFiscalDigital'] } - it{ expect(encabezado['Version']).to eq('3.3') } + it{ expect(encabezado['Version']).to eq('4.0') } end context 'datos adicionales' do diff --git a/template.txt b/template.txt new file mode 100644 index 0000000..46f3b3b --- /dev/null +++ b/template.txt @@ -0,0 +1,130 @@ +[ComprobanteFiscalDigital] + +Version=4.0 +Fecha=2022-04-22T03:12:58 +Folio=10 +NoCertificado=111222111 +SubTotal=100.0 +Descuento=0.0 +Total=116.0 +Exportacion=01 +Serie=A +FormaPago=01 +CondicionesDePago=Contado +Moneda=MXN +TipoDeComprobante=I +MetodoPago=PUE +LugarExpedicion=68000 + +[CfdiRelacionados] + +TipoRelacion=04 +UUID=[FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623] + +[DatosAdicionales] + +tipoDocumento=Factura +observaciones=Efectos Fiscales al Pago +TransID=5 + +[Emisor] + +Rfc=XIA190128J61 +Nombre=FACTURACION MODERNA S.A de C.V. +RegimenFiscal=612 + +[Receptor] + +Rfc=XAXX010101000 +Nombre=PUBLICO EN GENERAL +UsoCFDI=G03 +DomicilioFiscalReceptor=71243 +RegimenFiscalReceptor=616 + +[Concepto#1] + +Cantidad=1 +ObjetoImp=02 +ClaveProdServ=01010101 +NoIdentificacion=111222333 +ClaveUnidad=H87 +Unidad=No Aplica +Descripcion=Caja Hojas Blancas Tamaño Carta +ValorUnitario=110.0 +Importe=110.0 +Descuento=10.0 +Parte.ClaveProdServ=[01010101,01010101] +Parte.NoIdentificacion=[112233,112234] +Parte.Cantidad=[1,1] +Parte.Unidad=[No aplica,No aplica] +Parte.Descripcion=[Una descripcion,Otra descripcion] +Impuestos.Traslados.Base=[100.0] +Impuestos.Traslados.Impuesto=[002] +Impuestos.Traslados.TipoFactor=[Tasa] +Impuestos.Traslados.TasaOCuota=[0.16] +Impuestos.Traslados.Importe=[16] +Impuestos.Retenciones.Base=[100.0] +Impuestos.Retenciones.Impuesto=[001] +Impuestos.Retenciones.TipoFactor=[Tasa] +Impuestos.Retenciones.TasaOCuota=[0.2] +Impuestos.Retenciones.Importe=[20] + +[Concepto#2] + +Cantidad=2 +ObjetoImp=02 +ClaveProdServ=10101502 +NoIdentificacion=111222334 +ClaveUnidad=H87 +Unidad=No Aplica +Descripcion=Plástico para forrar libros +ValorUnitario=10.0 +Importe=20.0 +Impuestos.Traslados.Base=[20.0] +Impuestos.Traslados.Impuesto=[002] +Impuestos.Traslados.TipoFactor=[Tasa] +Impuestos.Traslados.TasaOCuota=[0.16] +Impuestos.Traslados.Importe=[3.2] +Impuestos.Retenciones.Base=[20.0] +Impuestos.Retenciones.Impuesto=[001] +Impuestos.Retenciones.TipoFactor=[Tasa] +Impuestos.Retenciones.TasaOCuota=[0.2] +Impuestos.Retenciones.Importe=[4] + +[Traslados] + +TotalImpuestosTrasladados=19.2 +Impuesto=[002] +TipoFactor=[Tasa] +TasaOCuota=[0.16] +Importe=[19.2] +Base=[120] + +[Retenciones] + +TotalImpuestosRetenidos=24 +Impuesto=[001] +Importe=[24] + +[TrasladosLocales] + +ImpLocTrasladado=[ISH] +Importe=[110.0] +TasadeTraslado=[0.11] + +[RetencionesLocales] + +ImpLocRetenido=[IVA LOCAL,ISR LOCAL] +Importe=[110.0,110.0] +TasadeRetencion=[0.16,0.16] + +[ComplementoINE] + +TipoProceso=Ordinario +TipoComite=Ejecutivo Estatal + +[Entidad] + +ClaveEntidad=OAX +IdContabilidad=000516 + From b80dfd8f859ca8c4644eafd29e893366f70c1354 Mon Sep 17 00:00:00 2001 From: Kevin Hernandez Date: Mon, 25 Apr 2022 23:58:33 -0500 Subject: [PATCH 47/56] feat: Add InformacionGlobal --- lib/fm_layout/fm_layout.rb | 12 ++++++++++ lib/fm_layout/informacion_global.rb | 35 +++++++++++++++++++++++++++++ spec/fm_layout_spec.rb | 14 ++++++++++++ template.txt | 8 ++++++- 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 lib/fm_layout/informacion_global.rb diff --git a/lib/fm_layout/fm_layout.rb b/lib/fm_layout/fm_layout.rb index c2cc652..34286fd 100644 --- a/lib/fm_layout/fm_layout.rb +++ b/lib/fm_layout/fm_layout.rb @@ -1,4 +1,5 @@ require 'fm_layout/comprobante_fiscal_digital' +require 'fm_layout/informacion_global' require 'fm_layout/datos_adicionales' require 'fm_layout/emisor' require 'fm_layout/receptor' @@ -17,6 +18,7 @@ module FmLayout class FmLayout def initialize @encabezado = ComprobanteFiscalDigital.new + @informacion_global = InformacionGlobal.new @datos_adicionales = DatosAdicionales.new @emisor = Emisor.new @receptor= Receptor.new @@ -39,6 +41,14 @@ def encabezado end end + def informacion_global + if block_given? + yield(@informacion_global) + else + @informacion_global + end + end + def datos_adicionales if block_given? yield(@datos_adicionales) @@ -162,6 +172,7 @@ def cfdi_relacionados def to_s salida = @encabezado.to_s + salida += @informacion_global.to_s salida += @cfdi_relacionados.to_s if @cfdi_relacionados.con_relaciones? salida += @datos_adicionales.to_s salida += @emisor.to_s @@ -178,6 +189,7 @@ def to_s def to_h encabezado.to_h + .merge(informacion_global.to_h) .merge(@datos_adicionales.to_h) .merge(@emisor.to_h) .merge(@receptor.to_h) diff --git a/lib/fm_layout/informacion_global.rb b/lib/fm_layout/informacion_global.rb new file mode 100644 index 0000000..daa5246 --- /dev/null +++ b/lib/fm_layout/informacion_global.rb @@ -0,0 +1,35 @@ +require 'fm_layout/fm_seccion' +module FmLayout + class InformacionGlobal + include FmSeccion + + def initialize + @titulo= 'InformacionGlobal' + @datos= {} + valores_iniciales + end + + def self.campos_vs_metodos + { + 'Periodicidad' => 'periodicidad', + 'Meses' => 'meses', + 'Año' => 'anio', + + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + + private + + def valores_iniciales + end + end + +end diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index 8b8da53..d7b5151 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -24,6 +24,12 @@ e.lugar_de_expedicion '68000' end + f.informacion_global do |e| + e.periodicidad '01' + e.meses '1' + e.anio '2022' + end + f.cfdi_relacionados do |cfdi| cfdi.tipo_relacion '04' cfdi.uuids "FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623" @@ -186,6 +192,13 @@ it{ expect(comprobante_fiscal_digital['Exportacion']).to eq('01') } end + context 'informacion global' do + let(:informacion_global){ prueba.to_h['InformacionGlobal'] } + it{ expect(informacion_global['Periodicidad']).to eq('01') } + it{ expect(informacion_global['Meses']).to eq('1') } + it{ expect(informacion_global['Año']).to eq('2022') } + end + context "cfdi relacionados" do let(:cfdi_relacionado) { prueba.to_h['CfdiRelacionados'] } it{ expect(cfdi_relacionado['TipoRelacion']).to eq('04') } @@ -315,6 +328,7 @@ context 'salida en texto' do let(:salida){ prueba.to_s } it{ expect(salida).to match(/\[ComprobanteFiscalDigital\]/) } + it{ expect(salida).to match(/\[InformacionGlobal\]/) } it{ expect(salida).to match(/\[DatosAdicionales\]/) } it{ expect(salida).to match(/\[Emisor\]/) } it{ expect(salida).to match(/\[Receptor\]/) } diff --git a/template.txt b/template.txt index 46f3b3b..a8e4a10 100644 --- a/template.txt +++ b/template.txt @@ -1,7 +1,7 @@ [ComprobanteFiscalDigital] Version=4.0 -Fecha=2022-04-22T03:12:58 +Fecha=2022-04-25T23:56:47 Folio=10 NoCertificado=111222111 SubTotal=100.0 @@ -16,6 +16,12 @@ TipoDeComprobante=I MetodoPago=PUE LugarExpedicion=68000 +[InformacionGlobal] + +Periodicidad=01 +Meses=1 +Año=2022 + [CfdiRelacionados] TipoRelacion=04 From c2895afb541beb4af02303d01d54f2cc1f18ddd1 Mon Sep 17 00:00:00 2001 From: Kevin Hernandez Date: Tue, 26 Apr 2022 01:22:47 -0500 Subject: [PATCH 48/56] feat: Change Test InformacionGlobal --- spec/fm_layout_spec.rb | 4 ++-- template.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index d7b5151..c7f630e 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -26,7 +26,7 @@ f.informacion_global do |e| e.periodicidad '01' - e.meses '1' + e.meses '01' e.anio '2022' end @@ -195,7 +195,7 @@ context 'informacion global' do let(:informacion_global){ prueba.to_h['InformacionGlobal'] } it{ expect(informacion_global['Periodicidad']).to eq('01') } - it{ expect(informacion_global['Meses']).to eq('1') } + it{ expect(informacion_global['Meses']).to eq('01') } it{ expect(informacion_global['Año']).to eq('2022') } end diff --git a/template.txt b/template.txt index a8e4a10..9c66bfa 100644 --- a/template.txt +++ b/template.txt @@ -1,7 +1,7 @@ [ComprobanteFiscalDigital] Version=4.0 -Fecha=2022-04-25T23:56:47 +Fecha=2022-04-26T01:04:49 Folio=10 NoCertificado=111222111 SubTotal=100.0 @@ -19,7 +19,7 @@ LugarExpedicion=68000 [InformacionGlobal] Periodicidad=01 -Meses=1 +Meses=01 Año=2022 [CfdiRelacionados] From 052c4f47eb88216cbb327b0822c2192603ce6b4c Mon Sep 17 00:00:00 2001 From: Kevin Hernandez Date: Tue, 26 Apr 2022 01:31:43 -0500 Subject: [PATCH 49/56] feat: Deleted Template.txt --- .gitignore | 1 + template.txt | 136 --------------------------------------------------- 2 files changed, 1 insertion(+), 136 deletions(-) delete mode 100644 template.txt diff --git a/.gitignore b/.gitignore index ee854e4..61c1909 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ test/tmp test/version_tmp tmp *swp +template.txt \ No newline at end of file diff --git a/template.txt b/template.txt deleted file mode 100644 index 9c66bfa..0000000 --- a/template.txt +++ /dev/null @@ -1,136 +0,0 @@ -[ComprobanteFiscalDigital] - -Version=4.0 -Fecha=2022-04-26T01:04:49 -Folio=10 -NoCertificado=111222111 -SubTotal=100.0 -Descuento=0.0 -Total=116.0 -Exportacion=01 -Serie=A -FormaPago=01 -CondicionesDePago=Contado -Moneda=MXN -TipoDeComprobante=I -MetodoPago=PUE -LugarExpedicion=68000 - -[InformacionGlobal] - -Periodicidad=01 -Meses=01 -Año=2022 - -[CfdiRelacionados] - -TipoRelacion=04 -UUID=[FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623] - -[DatosAdicionales] - -tipoDocumento=Factura -observaciones=Efectos Fiscales al Pago -TransID=5 - -[Emisor] - -Rfc=XIA190128J61 -Nombre=FACTURACION MODERNA S.A de C.V. -RegimenFiscal=612 - -[Receptor] - -Rfc=XAXX010101000 -Nombre=PUBLICO EN GENERAL -UsoCFDI=G03 -DomicilioFiscalReceptor=71243 -RegimenFiscalReceptor=616 - -[Concepto#1] - -Cantidad=1 -ObjetoImp=02 -ClaveProdServ=01010101 -NoIdentificacion=111222333 -ClaveUnidad=H87 -Unidad=No Aplica -Descripcion=Caja Hojas Blancas Tamaño Carta -ValorUnitario=110.0 -Importe=110.0 -Descuento=10.0 -Parte.ClaveProdServ=[01010101,01010101] -Parte.NoIdentificacion=[112233,112234] -Parte.Cantidad=[1,1] -Parte.Unidad=[No aplica,No aplica] -Parte.Descripcion=[Una descripcion,Otra descripcion] -Impuestos.Traslados.Base=[100.0] -Impuestos.Traslados.Impuesto=[002] -Impuestos.Traslados.TipoFactor=[Tasa] -Impuestos.Traslados.TasaOCuota=[0.16] -Impuestos.Traslados.Importe=[16] -Impuestos.Retenciones.Base=[100.0] -Impuestos.Retenciones.Impuesto=[001] -Impuestos.Retenciones.TipoFactor=[Tasa] -Impuestos.Retenciones.TasaOCuota=[0.2] -Impuestos.Retenciones.Importe=[20] - -[Concepto#2] - -Cantidad=2 -ObjetoImp=02 -ClaveProdServ=10101502 -NoIdentificacion=111222334 -ClaveUnidad=H87 -Unidad=No Aplica -Descripcion=Plástico para forrar libros -ValorUnitario=10.0 -Importe=20.0 -Impuestos.Traslados.Base=[20.0] -Impuestos.Traslados.Impuesto=[002] -Impuestos.Traslados.TipoFactor=[Tasa] -Impuestos.Traslados.TasaOCuota=[0.16] -Impuestos.Traslados.Importe=[3.2] -Impuestos.Retenciones.Base=[20.0] -Impuestos.Retenciones.Impuesto=[001] -Impuestos.Retenciones.TipoFactor=[Tasa] -Impuestos.Retenciones.TasaOCuota=[0.2] -Impuestos.Retenciones.Importe=[4] - -[Traslados] - -TotalImpuestosTrasladados=19.2 -Impuesto=[002] -TipoFactor=[Tasa] -TasaOCuota=[0.16] -Importe=[19.2] -Base=[120] - -[Retenciones] - -TotalImpuestosRetenidos=24 -Impuesto=[001] -Importe=[24] - -[TrasladosLocales] - -ImpLocTrasladado=[ISH] -Importe=[110.0] -TasadeTraslado=[0.11] - -[RetencionesLocales] - -ImpLocRetenido=[IVA LOCAL,ISR LOCAL] -Importe=[110.0,110.0] -TasadeRetencion=[0.16,0.16] - -[ComplementoINE] - -TipoProceso=Ordinario -TipoComite=Ejecutivo Estatal - -[Entidad] - -ClaveEntidad=OAX -IdContabilidad=000516 - From 0f40adc04de9e6ef54b21837815a01d758dcb9c8 Mon Sep 17 00:00:00 2001 From: Kevin Hernandez Date: Tue, 26 Apr 2022 03:28:49 -0500 Subject: [PATCH 50/56] feat: Add Node Receptor y Emisor --- lib/fm_layout/emisor.rb | 1 + spec/fm_layout_spec.rb | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/fm_layout/emisor.rb b/lib/fm_layout/emisor.rb index 4111bda..bbf2022 100644 --- a/lib/fm_layout/emisor.rb +++ b/lib/fm_layout/emisor.rb @@ -15,6 +15,7 @@ def self.campos_vs_metodos 'Rfc' => 'rfc', 'Nombre' => 'nombre', 'RegimenFiscal' => 'regimen_fiscal', + 'FacAtrAdquirente' => 'fac_atr_adquirente' } end diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index c7f630e..1822e83 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -45,6 +45,7 @@ e.rfc 'XIA190128J61' e.nombre 'FACTURACION MODERNA S.A de C.V.' e.regimen_fiscal '612' + e.fac_atr_adquirente '0123456789' end f.receptor do |r| @@ -217,6 +218,7 @@ it{ expect(emisor['Rfc']).to eq('XIA190128J61') } it{ expect(emisor['Nombre']).to eq('FACTURACION MODERNA S.A de C.V.') } it{ expect(emisor['RegimenFiscal']).to eq('612') } + it{ expect(emisor['FacAtrAdquirente']).to eq('0123456789') } end context 'receptor' do From 2ca5096de9573118e6e58ba666989b42e0722c36 Mon Sep 17 00:00:00 2001 From: Kevin Hernandez Date: Tue, 26 Apr 2022 13:44:16 -0500 Subject: [PATCH 51/56] feat: a cuenta de terceros --- lib/fm_layout/a_cuenta_terceros.rb | 61 ++++++++++++++++++++++++++++++ lib/fm_layout/concepto.rb | 17 ++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 lib/fm_layout/a_cuenta_terceros.rb diff --git a/lib/fm_layout/a_cuenta_terceros.rb b/lib/fm_layout/a_cuenta_terceros.rb new file mode 100644 index 0000000..a770d9d --- /dev/null +++ b/lib/fm_layout/a_cuenta_terceros.rb @@ -0,0 +1,61 @@ +require 'fm_layout/fm_seccion' + +module FmLayout + class ACuentaTerceros + include FmSeccion + attr_reader :datos + attr_accessor :arr_base, :arr_impuesto, :arr_tipo_factor, :arr_tasa_o_cuota, :arr_importe + + def initialize + @titulo = 'Retenciones' + @arr_base = [] + @arr_impuesto = [] + @arr_tipo_factor = [] + @arr_tasa_o_cuota = [] + @arr_importe = [] + @datos = {} + end + + def self.campos_vs_metodos + { + 'TotalImpuestosRetenidos' => 'total_impuestos', + } + end + + # Creación de los métodos de acceso dinámicamente + campos_vs_metodos.each do |campo, metodo| + define_method(metodo) do |dato| + @datos[campo] = dato + end + end + + def base value + arr_base.push value + @datos["Base"] = "[#{arr_base.join(',')}]" + end + + def impuesto value + arr_impuesto.push value + @datos["Impuesto"] = "[#{arr_impuesto.join(',')}]" + end + + def tipo_factor value + arr_tipo_factor.push value + @datos["TipoFactor"] = "[#{arr_tipo_factor.join(',')}]" + end + + def tasa_o_cuota value + arr_tasa_o_cuota.push value + @datos["TasaOCuota"] = "[#{arr_tasa_o_cuota.join(',')}]" + end + + def importe value + arr_importe.push value + @datos["Importe"] = "[#{arr_importe.join(',')}]" + end + + def con_impuestos? + @datos.any? + end + end +end diff --git a/lib/fm_layout/concepto.rb b/lib/fm_layout/concepto.rb index 817264e..3fd565b 100644 --- a/lib/fm_layout/concepto.rb +++ b/lib/fm_layout/concepto.rb @@ -12,6 +12,7 @@ def initialize num_concepto @impuesto_t = ImpuestoTrasladado.new @impuesto_r = ImpuestoRetenido.new @parte = Parte.new + end def self.campos_vs_metodos @@ -25,8 +26,8 @@ def self.campos_vs_metodos 'ValorUnitario' => 'valor_unitario', 'Importe' => 'importe', 'Descuento' => 'descuento', - 'CuentaPredial' => 'cuenta_predial', - 'ObjetoImp' => 'objeto_imp' + 'ObjetoImp' => 'objeto_imp', + 'CuentaPredial' => 'cuenta_predial' } end @@ -69,6 +70,18 @@ def impuesto_retenido end end + def a_cuenta_terceros + if block_given? + yield @impuesto_r + @datos["ACuentaTerceros.RfcACuentaTerceros"] = @impuesto_r.datos["RfcACuentaTerceros"] + @datos["ACuentaTerceros.NombreACuentaTerceros"] = @impuesto_r.datos["NombreACuentaTerceros"] + @datos["ACuentaTerceros.RegimenFiscalACuentaTerceros"] = @impuesto_r.datos["RegimenFiscalACuentaTerceros"] + @datos["ACuentaTerceros.DomicilioFiscalACuentaTerceros"] = @impuesto_r.datos["DomicilioFiscalACuentaTerceros"] + else + @impuesto_r + end + end + # Creación de los métodos de acceso dinámicamente campos_vs_metodos.each do |campo, metodo| define_method(metodo) do |dato| From e0c7b1933e357c80171699d76d0fdd00ff15ac0a Mon Sep 17 00:00:00 2001 From: Kevin Hernandez Date: Tue, 26 Apr 2022 18:45:39 -0500 Subject: [PATCH 52/56] feat: Add ACuentaTerceros en Concepto --- lib/fm_layout/a_cuenta_terceros.rb | 47 +++++++----------------------- lib/fm_layout/concepto.rb | 14 +++++---- spec/fm_layout_spec.rb | 12 ++++++++ 3 files changed, 30 insertions(+), 43 deletions(-) diff --git a/lib/fm_layout/a_cuenta_terceros.rb b/lib/fm_layout/a_cuenta_terceros.rb index a770d9d..1233586 100644 --- a/lib/fm_layout/a_cuenta_terceros.rb +++ b/lib/fm_layout/a_cuenta_terceros.rb @@ -4,21 +4,23 @@ module FmLayout class ACuentaTerceros include FmSeccion attr_reader :datos - attr_accessor :arr_base, :arr_impuesto, :arr_tipo_factor, :arr_tasa_o_cuota, :arr_importe + attr_accessor :rfc_cuenta_terceros, :nombre_cuenta_terceros, :regimen_fiscal_cuenta_terceros, :domicilio_fiscal_cuenta_terceros def initialize - @titulo = 'Retenciones' - @arr_base = [] - @arr_impuesto = [] - @arr_tipo_factor = [] - @arr_tasa_o_cuota = [] - @arr_importe = [] + @titulo = 'ACuentaTerceros' + @rfc_cuenta_terceros = '' + @nombre_cuenta_terceros = '' + @regimen_fiscal_cuenta_terceros = '' + @domicilio_fiscal_cuenta_terceros = '' @datos = {} end def self.campos_vs_metodos { - 'TotalImpuestosRetenidos' => 'total_impuestos', + 'RfcACuentaTerceros' => 'rfc_cuenta_terceros', + 'NombreACuentaTerceros' => 'nombre_cuenta_terceros', + 'RegimenFiscalACuentaTerceros' => 'regimen_fiscal_cuenta_terceros', + 'DomicilioFiscalACuentaTerceros' => 'domicilio_fiscal_cuenta_terceros' } end @@ -28,34 +30,5 @@ def self.campos_vs_metodos @datos[campo] = dato end end - - def base value - arr_base.push value - @datos["Base"] = "[#{arr_base.join(',')}]" - end - - def impuesto value - arr_impuesto.push value - @datos["Impuesto"] = "[#{arr_impuesto.join(',')}]" - end - - def tipo_factor value - arr_tipo_factor.push value - @datos["TipoFactor"] = "[#{arr_tipo_factor.join(',')}]" - end - - def tasa_o_cuota value - arr_tasa_o_cuota.push value - @datos["TasaOCuota"] = "[#{arr_tasa_o_cuota.join(',')}]" - end - - def importe value - arr_importe.push value - @datos["Importe"] = "[#{arr_importe.join(',')}]" - end - - def con_impuestos? - @datos.any? - end end end diff --git a/lib/fm_layout/concepto.rb b/lib/fm_layout/concepto.rb index 3fd565b..ebdd366 100644 --- a/lib/fm_layout/concepto.rb +++ b/lib/fm_layout/concepto.rb @@ -1,5 +1,6 @@ require 'fm_layout/fm_seccion' require 'fm_layout/parte' +require 'fm_layout/a_cuenta_terceros' module FmLayout class Concepto @@ -9,6 +10,7 @@ def initialize num_concepto @titulo = "Concepto##{num_concepto}" @datos = {} valores_iniciales + @cuenta_terceros = ACuentaTerceros.new @impuesto_t = ImpuestoTrasladado.new @impuesto_r = ImpuestoRetenido.new @parte = Parte.new @@ -72,13 +74,13 @@ def impuesto_retenido def a_cuenta_terceros if block_given? - yield @impuesto_r - @datos["ACuentaTerceros.RfcACuentaTerceros"] = @impuesto_r.datos["RfcACuentaTerceros"] - @datos["ACuentaTerceros.NombreACuentaTerceros"] = @impuesto_r.datos["NombreACuentaTerceros"] - @datos["ACuentaTerceros.RegimenFiscalACuentaTerceros"] = @impuesto_r.datos["RegimenFiscalACuentaTerceros"] - @datos["ACuentaTerceros.DomicilioFiscalACuentaTerceros"] = @impuesto_r.datos["DomicilioFiscalACuentaTerceros"] + yield @cuenta_terceros + @datos["ACuentaTerceros.RfcACuentaTerceros"] = @cuenta_terceros.datos["RfcACuentaTerceros"] + @datos["ACuentaTerceros.NombreACuentaTerceros"] = @cuenta_terceros.datos["NombreACuentaTerceros"] + @datos["ACuentaTerceros.RegimenFiscalACuentaTerceros"] = @cuenta_terceros.datos["RegimenFiscalACuentaTerceros"] + @datos["ACuentaTerceros.DomicilioFiscalACuentaTerceros"] = @cuenta_terceros.datos["DomicilioFiscalACuentaTerceros"] else - @impuesto_r + @cuenta_terceros end end diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index 1822e83..8d855bd 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -69,6 +69,13 @@ c.objeto_imp '02' #c.cuenta_predial '123-132123' + c.a_cuenta_terceros do |c| + c.rfc_cuenta_terceros 'XAXX010101000' + c.nombre_cuenta_terceros 'PUBLICO EN GENERAL' + c.regimen_fiscal_cuenta_terceros '612' + c.domicilio_fiscal_cuenta_terceros '71243' + end + c.partes do |c| c.clave_producto_servicio '01010101' c.numero_de_identificacion '112233' @@ -242,6 +249,11 @@ it{ expect(concepto['Importe']).to eq(110.00) } it{ expect(concepto['Descuento']).to eq(10.00) } + it{ expect(concepto['ACuentaTerceros.RfcACuentaTerceros']).to eq("XAXX010101000") } + it{ expect(concepto['ACuentaTerceros.NombreACuentaTerceros']).to eq("PUBLICO EN GENERAL") } + it{ expect(concepto['ACuentaTerceros.RegimenFiscalACuentaTerceros']).to eq("612") } + it{ expect(concepto['ACuentaTerceros.DomicilioFiscalACuentaTerceros']).to eq("71243") } + it{ expect(concepto['Parte.ClaveProdServ']).to eq("[01010101,01010101]") } it{ expect(concepto['Parte.NoIdentificacion']).to eq("[112233,112234]") } it{ expect(concepto['Parte.Cantidad']).to eq("[1,1]") } From 62f950457d1d46825ed63a7fa90126d26ecf361d Mon Sep 17 00:00:00 2001 From: Kevin Hernandez Date: Tue, 26 Apr 2022 23:06:06 -0500 Subject: [PATCH 53/56] feat: Add CFDI Relacionados General y Nomina --- lib/fm_layout/cfdi_relacionados.rb | 4 ++-- lib/fm_layout/fm_layout.rb | 18 +++++++++++++----- lib/fm_layout/fm_layout_nomina.rb | 17 ++++++++++++----- spec/fm_layout_nomina_spec.rb | 4 ++-- spec/fm_layout_spec.rb | 15 +++++++++++++-- 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/lib/fm_layout/cfdi_relacionados.rb b/lib/fm_layout/cfdi_relacionados.rb index e07ff44..04c2e0d 100644 --- a/lib/fm_layout/cfdi_relacionados.rb +++ b/lib/fm_layout/cfdi_relacionados.rb @@ -5,8 +5,8 @@ class CfdiRelacionados include FmSeccion attr_reader :datos - def initialize - @titulo = 'CfdiRelacionados' + def initialize num_relacionado + @titulo = "CfdiRelacionados##{num_relacionado}" @datos = {} end diff --git a/lib/fm_layout/fm_layout.rb b/lib/fm_layout/fm_layout.rb index 34286fd..f97c3da 100644 --- a/lib/fm_layout/fm_layout.rb +++ b/lib/fm_layout/fm_layout.rb @@ -30,7 +30,8 @@ def initialize @impuesto_retenido = ImpuestoRetenido.new @impuesto_trasladado_local = ImpuestoTrasladadoLocal.new @impuesto_retenido_local = ImpuestoRetenidoLocal.new - @cfdi_relacionados = CfdiRelacionados.new + @cfdi_relacionados = [] + @num_cfdi_relacionados = 0 end def encabezado @@ -163,17 +164,20 @@ def entidad_ine end def cfdi_relacionados + @num_cfdi_relacionados += 1 + relacionado = CfdiRelacionados.new @num_cfdi_relacionados if block_given? - yield(@cfdi_relacionados) + yield(relacionado) + @cfdi_relacionados << relacionado else - @cfdi_relacionados + relacionado end end def to_s salida = @encabezado.to_s salida += @informacion_global.to_s - salida += @cfdi_relacionados.to_s if @cfdi_relacionados.con_relaciones? + salida += @cfdi_relacionados.map(&:to_s).reduce(:+).to_s if @num_cfdi_relacionados > 0 salida += @datos_adicionales.to_s salida += @emisor.to_s salida += @receptor.to_s @@ -199,7 +203,7 @@ def to_h .merge(obtener_hash_traslados_locales) .merge(obtener_hash_retenciones_locales) .merge(@complemento_ine.to_h) - .merge(@cfdi_relacionados.to_h) + .merge(obtener_hash_cfdi_relacionados) .merge(obtener_hash_entidades_ine) end @@ -228,5 +232,9 @@ def obtener_hash_retenciones_locales def obtener_hash_entidades_ine { 'EntidadesINE' => @entidades_ine.map(&:to_h) } end + + def obtener_hash_cfdi_relacionados + { 'CfdiRelacionados' => @cfdi_relacionados.map(&:to_h) } + end end end diff --git a/lib/fm_layout/fm_layout_nomina.rb b/lib/fm_layout/fm_layout_nomina.rb index f8bbbcc..304d73d 100644 --- a/lib/fm_layout/fm_layout_nomina.rb +++ b/lib/fm_layout/fm_layout_nomina.rb @@ -11,7 +11,8 @@ def initialize @datos_adicionales = DatosAdicionales.new @emisor = Nomina::Emisor.new @receptor= Nomina::Receptor.new - @cfdi_relacionados = CfdiRelacionados.new + @cfdi_relacionados = [] + @num_cfdi_relacionados = 0 @conceptos = [] @num_concepto = 0 end @@ -78,16 +79,19 @@ def nomina end def cfdi_relacionados + @num_cfdi_relacionados += 1 + relacionado = CfdiRelacionados.new @num_cfdi_relacionados if block_given? - yield(@cfdi_relacionados) + yield(relacionado) + @cfdi_relacionados << relacionado else - @cfdi_relacionados + relacionado end end def to_s salida = @recibo_nomina.to_s - salida += @cfdi_relacionados.to_s if @cfdi_relacionados.con_relaciones? + salida += @cfdi_relacionados.map(&:to_s).reduce(:+).to_s if @num_cfdi_relacionados > 0 salida += @datos_adicionales.to_s + @emisor.to_s + @entidad_sncf.to_s + @receptor.to_s salida += @conceptos.map(&:to_s).reduce(:+).to_s salida += @nomina.to_s @@ -97,7 +101,7 @@ def to_s def to_h recibo_nomina.to_h .merge(@datos_adicionales.to_h) - .merge(@cfdi_relacionados.to_h) + .merge(obtener_hash_cfdi_relacionados) .merge(@emisor.to_h) .merge(@entidad_sncf.to_h) .merge(@expedido_en.to_h) @@ -112,5 +116,8 @@ def obtener_hash_conceptos { 'Conceptos' => @conceptos.map(&:to_h) } end + def obtener_hash_cfdi_relacionados + { 'CfdiRelacionados' => @cfdi_relacionados.map(&:to_h) } + end end end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index ae078c9..ca04d83 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -411,7 +411,7 @@ end context "#cfdi_relacionados" do - let(:cfdi_relacionados) { prueba.to_h['CfdiRelacionados'] } + let(:cfdi_relacionados) { prueba.to_h['CfdiRelacionados'].first['CfdiRelacionados#1'] } it { expect(cfdi_relacionados['TipoRelacion']).to eq("Un tipo de relacion")} it { expect(cfdi_relacionados['UUID']).to eq("[UUIDS]")} @@ -432,7 +432,7 @@ it{ expect(salida).to match(/\[SeparacionIndemnizacion\]/) } it{ expect(salida).to match(/\[Deduccion#1\]/) } it{ expect(salida).to match(/\[Incapacidad#1\]/) } - it { expect(salida).to match(/\[CfdiRelacionados\]/) } + it { expect(salida).to match(/\[CfdiRelacionados#1\]/) } it { expect(salida).to match(/TipoRelacion=Un tipo de relacion/) } it { expect(salida).to match(/UUID=\[UUIDS\]/) } end diff --git a/spec/fm_layout_spec.rb b/spec/fm_layout_spec.rb index 8d855bd..d983162 100644 --- a/spec/fm_layout_spec.rb +++ b/spec/fm_layout_spec.rb @@ -35,6 +35,11 @@ cfdi.uuids "FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623" end + f.cfdi_relacionados do |cfdi| + cfdi.tipo_relacion '01' + cfdi.uuids "FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623" + end + f.datos_adicionales do |d| d.tipo_de_documento 'Factura' d.observaciones 'Efectos Fiscales al Pago' @@ -207,12 +212,18 @@ it{ expect(informacion_global['Año']).to eq('2022') } end - context "cfdi relacionados" do - let(:cfdi_relacionado) { prueba.to_h['CfdiRelacionados'] } + context "cfdi relacionado 01" do + let(:cfdi_relacionado) { prueba.to_h['CfdiRelacionados'].first['CfdiRelacionados#1'] } it{ expect(cfdi_relacionado['TipoRelacion']).to eq('04') } it{ expect(cfdi_relacionado['UUID']).to eq('[FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623]') } end # context cfdi relacionados + context "cfdi relacionado 02" do + let(:cfdi_relacionado) { prueba.to_h['CfdiRelacionados'].last['CfdiRelacionados#2'] } + it{ expect(cfdi_relacionado['TipoRelacion']).to eq('01') } + it{ expect(cfdi_relacionado['UUID']).to eq('[FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623]') } + end # context cfdi relacionados + context 'datos adicionales' do let(:datos_adicionales){ prueba.to_h['DatosAdicionales'] } it{ expect(datos_adicionales['tipoDocumento']).to eq('Factura') } From 1f886a07cdf5302df4e46f72234bd9632f1f97c9 Mon Sep 17 00:00:00 2001 From: Kevin Hernandez Date: Fri, 29 Apr 2022 14:23:12 -0500 Subject: [PATCH 54/56] feat: add txt gitignore --- .gitignore | 2 + template.txt | 136 --------------------------------------------------- 2 files changed, 2 insertions(+), 136 deletions(-) delete mode 100644 template.txt diff --git a/.gitignore b/.gitignore index ee854e4..bf50d08 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ test/tmp test/version_tmp tmp *swp +*template.txt +*nomina.txt \ No newline at end of file diff --git a/template.txt b/template.txt deleted file mode 100644 index a8e4a10..0000000 --- a/template.txt +++ /dev/null @@ -1,136 +0,0 @@ -[ComprobanteFiscalDigital] - -Version=4.0 -Fecha=2022-04-25T23:56:47 -Folio=10 -NoCertificado=111222111 -SubTotal=100.0 -Descuento=0.0 -Total=116.0 -Exportacion=01 -Serie=A -FormaPago=01 -CondicionesDePago=Contado -Moneda=MXN -TipoDeComprobante=I -MetodoPago=PUE -LugarExpedicion=68000 - -[InformacionGlobal] - -Periodicidad=01 -Meses=1 -Año=2022 - -[CfdiRelacionados] - -TipoRelacion=04 -UUID=[FCA37E7F-80FF-4CAE-9A03-37E095233F23,6424C23D-77B7-4F13-AD01-8CA0092D9623] - -[DatosAdicionales] - -tipoDocumento=Factura -observaciones=Efectos Fiscales al Pago -TransID=5 - -[Emisor] - -Rfc=XIA190128J61 -Nombre=FACTURACION MODERNA S.A de C.V. -RegimenFiscal=612 - -[Receptor] - -Rfc=XAXX010101000 -Nombre=PUBLICO EN GENERAL -UsoCFDI=G03 -DomicilioFiscalReceptor=71243 -RegimenFiscalReceptor=616 - -[Concepto#1] - -Cantidad=1 -ObjetoImp=02 -ClaveProdServ=01010101 -NoIdentificacion=111222333 -ClaveUnidad=H87 -Unidad=No Aplica -Descripcion=Caja Hojas Blancas Tamaño Carta -ValorUnitario=110.0 -Importe=110.0 -Descuento=10.0 -Parte.ClaveProdServ=[01010101,01010101] -Parte.NoIdentificacion=[112233,112234] -Parte.Cantidad=[1,1] -Parte.Unidad=[No aplica,No aplica] -Parte.Descripcion=[Una descripcion,Otra descripcion] -Impuestos.Traslados.Base=[100.0] -Impuestos.Traslados.Impuesto=[002] -Impuestos.Traslados.TipoFactor=[Tasa] -Impuestos.Traslados.TasaOCuota=[0.16] -Impuestos.Traslados.Importe=[16] -Impuestos.Retenciones.Base=[100.0] -Impuestos.Retenciones.Impuesto=[001] -Impuestos.Retenciones.TipoFactor=[Tasa] -Impuestos.Retenciones.TasaOCuota=[0.2] -Impuestos.Retenciones.Importe=[20] - -[Concepto#2] - -Cantidad=2 -ObjetoImp=02 -ClaveProdServ=10101502 -NoIdentificacion=111222334 -ClaveUnidad=H87 -Unidad=No Aplica -Descripcion=Plástico para forrar libros -ValorUnitario=10.0 -Importe=20.0 -Impuestos.Traslados.Base=[20.0] -Impuestos.Traslados.Impuesto=[002] -Impuestos.Traslados.TipoFactor=[Tasa] -Impuestos.Traslados.TasaOCuota=[0.16] -Impuestos.Traslados.Importe=[3.2] -Impuestos.Retenciones.Base=[20.0] -Impuestos.Retenciones.Impuesto=[001] -Impuestos.Retenciones.TipoFactor=[Tasa] -Impuestos.Retenciones.TasaOCuota=[0.2] -Impuestos.Retenciones.Importe=[4] - -[Traslados] - -TotalImpuestosTrasladados=19.2 -Impuesto=[002] -TipoFactor=[Tasa] -TasaOCuota=[0.16] -Importe=[19.2] -Base=[120] - -[Retenciones] - -TotalImpuestosRetenidos=24 -Impuesto=[001] -Importe=[24] - -[TrasladosLocales] - -ImpLocTrasladado=[ISH] -Importe=[110.0] -TasadeTraslado=[0.11] - -[RetencionesLocales] - -ImpLocRetenido=[IVA LOCAL,ISR LOCAL] -Importe=[110.0,110.0] -TasadeRetencion=[0.16,0.16] - -[ComplementoINE] - -TipoProceso=Ordinario -TipoComite=Ejecutivo Estatal - -[Entidad] - -ClaveEntidad=OAX -IdContabilidad=000516 - From e353c762efc40219beb88ae74cca5da089b43044 Mon Sep 17 00:00:00 2001 From: Kevin Hernandez Date: Fri, 29 Apr 2022 20:44:39 -0500 Subject: [PATCH 55/56] feat: Add Data Nomina cfdi 4.0 --- lib/fm_layout/nomina/receptor.rb | 3 +++ lib/fm_layout/recibo_nomina.rb | 2 ++ spec/fm_layout_nomina_spec.rb | 14 ++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/lib/fm_layout/nomina/receptor.rb b/lib/fm_layout/nomina/receptor.rb index 3b63fd3..b715574 100644 --- a/lib/fm_layout/nomina/receptor.rb +++ b/lib/fm_layout/nomina/receptor.rb @@ -30,6 +30,9 @@ def self.campos_vs_metodos 'SalarioDiarioIntegrado' => 'salario_diario_integrado', 'ClaveEntFed' => 'clave_entidad_federativa', 'emailCliente' => 'email', + 'UsoCFDI' => 'uso_cfdi', + 'DomicilioFiscalReceptor' => 'domicilio_fiscal', + 'RegimenFiscalReceptor' => 'regimen_fiscal' } end diff --git a/lib/fm_layout/recibo_nomina.rb b/lib/fm_layout/recibo_nomina.rb index 89173a5..da34389 100644 --- a/lib/fm_layout/recibo_nomina.rb +++ b/lib/fm_layout/recibo_nomina.rb @@ -21,6 +21,7 @@ def self.campos_vs_metodos 'Moneda' => 'moneda', 'noCertificado' => 'numero_de_certificado', 'LugarExpedicion' => 'lugar_de_expedicion', + 'Exportacion' => 'exportacion' } end @@ -42,6 +43,7 @@ def valores_iniciales @datos['descuento'] = nil @datos['total'] = nil @datos['noCertificado'] = nil + @datos['Exportacion'] = '01' end end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index ca04d83..7439e96 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -18,6 +18,7 @@ e.subtotal '4420.00' e.descuento '193.43' e.total '4226.57' + e.exportacion '01' end f.datos_adicionales do |d| @@ -57,6 +58,8 @@ r.salario_base 200 r.salario_diario_integrado 209.04 r.clave_entidad_federativa 'OAX' + r.regimen_fiscal '605' + r.domicilio_fiscal '01001' end f.concepto do |c| @@ -197,6 +200,7 @@ it{ expect(recibo_nomina['subTotal']).to eq('4420.00') } it{ expect(recibo_nomina['descuento']).to eq('193.43') } it{ expect(recibo_nomina['total']).to eq('4226.57') } + it{ expect(recibo_nomina['Exportacion']).to eq('01') } end context 'datos adicionales' do @@ -244,6 +248,8 @@ it { expect(receptor['SalarioBaseCotApor']).to eq(200.0)} it { expect(receptor['SalarioDiarioIntegrado']).to eq(209.04)} it { expect(receptor['ClaveEntFed']).to eq('OAX')} + it { expect(receptor['DomicilioFiscalReceptor']).to eq('01001')} + it { expect(receptor['RegimenFiscalReceptor']).to eq('605')} end context 'concepto' do @@ -436,6 +442,14 @@ it { expect(salida).to match(/TipoRelacion=Un tipo de relacion/) } it { expect(salida).to match(/UUID=\[UUIDS\]/) } end + + context 'put file' do + it { + file = File.open('nomina.txt', 'w') + file.write(prueba) + file.close + } + end end end end From 3f7cf52dd15d52c1bd83fa6e617ecc43cf2ed8c1 Mon Sep 17 00:00:00 2001 From: kevhernandez Date: Sat, 30 Apr 2022 18:20:59 -0500 Subject: [PATCH 56/56] =?UTF-8?q?feat:=20Cambios=20en=20N=C3=B3mina?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/fm_layout.rb | 2 +- lib/fm_layout/nomina/receptor.rb | 4 ++-- spec/fm_layout_nomina_spec.rb | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/fm_layout.rb b/lib/fm_layout.rb index b105f50..853402c 100644 --- a/lib/fm_layout.rb +++ b/lib/fm_layout.rb @@ -6,7 +6,7 @@ module FmLayout def self.define_layout layout = FmLayout.new - yield(layout) if block_given? + yield(layout) if block_given? layout end diff --git a/lib/fm_layout/nomina/receptor.rb b/lib/fm_layout/nomina/receptor.rb index b715574..c6add92 100644 --- a/lib/fm_layout/nomina/receptor.rb +++ b/lib/fm_layout/nomina/receptor.rb @@ -31,8 +31,8 @@ def self.campos_vs_metodos 'ClaveEntFed' => 'clave_entidad_federativa', 'emailCliente' => 'email', 'UsoCFDI' => 'uso_cfdi', - 'DomicilioFiscalReceptor' => 'domicilio_fiscal', - 'RegimenFiscalReceptor' => 'regimen_fiscal' + 'DomicilioFiscalReceptor' => 'domicilio_fiscal_receptor', + 'RegimenFiscalReceptor' => 'regimen_fiscal_receptor' } end diff --git a/spec/fm_layout_nomina_spec.rb b/spec/fm_layout_nomina_spec.rb index 7439e96..9b91918 100644 --- a/spec/fm_layout_nomina_spec.rb +++ b/spec/fm_layout_nomina_spec.rb @@ -58,8 +58,9 @@ r.salario_base 200 r.salario_diario_integrado 209.04 r.clave_entidad_federativa 'OAX' - r.regimen_fiscal '605' - r.domicilio_fiscal '01001' + r.uso_cfdi 'CN01' + r.regimen_fiscal_receptor '605' + r.domicilio_fiscal_receptor '01001' end f.concepto do |c|