fm_layout 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,31 @@
1
+ module FmLayout
2
+ module Nomina
3
+ class HorasExtra
4
+
5
+ include ::FmLayout::FmSeccion
6
+
7
+ def initialize
8
+ @titulo= 'HorasExtra'
9
+ @datos= {}
10
+ #valores_iniciales
11
+ end
12
+
13
+ def self.campos_vs_metodos
14
+ {
15
+ 'Dias' => 'dias',
16
+ 'TipoHoras' => 'tipo',
17
+ 'HorasExtra' => 'horas_extra',
18
+ 'ImportePagado' => 'importe',
19
+ }
20
+ end
21
+
22
+ # Creación de los métodos de acceso dinámicamente
23
+ campos_vs_metodos.each do |campo, metodo|
24
+ define_method(metodo) do |dato|
25
+ @datos[campo] = dato
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ module FmLayout
2
+ module Nomina
3
+ class Incapacidad
4
+
5
+ include ::FmLayout::FmSeccion
6
+
7
+ def initialize
8
+ @titulo= 'Incapacidad'
9
+ @datos= {}
10
+ #valores_iniciales
11
+ end
12
+
13
+ def self.campos_vs_metodos
14
+ {
15
+ 'DiasIncapacidad' => 'dias',
16
+ 'TipoIncapacidad' => 'tipo',
17
+ 'Descuento' => 'descuento',
18
+ }
19
+ end
20
+
21
+ # Creación de los métodos de acceso dinámicamente
22
+ campos_vs_metodos.each do |campo, metodo|
23
+ define_method(metodo) do |dato|
24
+ @datos[campo] = dato
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,96 @@
1
+ require 'fm_layout/nomina/complemento_nomina'
2
+ require 'fm_layout/nomina/percepcion'
3
+ require 'fm_layout/nomina/deduccion'
4
+ require 'fm_layout/nomina/incapacidad'
5
+ require 'fm_layout/nomina/horas_extra'
6
+
7
+ module FmLayout
8
+ module Nomina
9
+ class Nomina
10
+
11
+ def initialize
12
+ @complemento_nomina = ComplementoNomina.new
13
+ @percepciones = []
14
+ @deducciones = []
15
+ @incapacidades = []
16
+ @horas_extras = []
17
+ end
18
+
19
+ def complemento_nomina
20
+ if block_given?
21
+ yield(@complemento_nomina)
22
+ else
23
+ @complemento_nomina
24
+ end
25
+ end
26
+
27
+ def percepcion
28
+ percepcion = Percepcion.new
29
+ if block_given?
30
+ yield(percepcion)
31
+ @percepciones << percepcion
32
+ else
33
+ percepcion
34
+ end
35
+ end
36
+
37
+ def deduccion
38
+ deduccion = Deduccion.new
39
+ if block_given?
40
+ yield(deduccion)
41
+ @deducciones << deduccion
42
+ else
43
+ deduccion
44
+ end
45
+ end
46
+
47
+ def incapacidad
48
+ incapacidad = Incapacidad.new
49
+ if block_given?
50
+ yield(incapacidad)
51
+ @incapacidades << incapacidad
52
+ else
53
+ incapacidad
54
+ end
55
+ end
56
+
57
+ def horas_extra
58
+ horas_extra = HorasExtra.new
59
+ if block_given?
60
+ yield(horas_extra)
61
+ @horas_extras << horas_extra
62
+ else
63
+ horas_extra
64
+ end
65
+ end
66
+
67
+
68
+ def to_h
69
+ { 'Nomina' => {}.merge( @complemento_nomina.to_h).merge(obtener_hash_percepciones).merge(obtener_hash_deducciones).merge(obtener_hash_incapacidades).merge(obtener_hash_horas_extra) }
70
+ end
71
+
72
+ def to_s
73
+ @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
74
+ end
75
+
76
+ private
77
+
78
+ def obtener_hash_percepciones
79
+ { 'Percepciones' => @percepciones.map(&:to_h) }
80
+ end
81
+
82
+ def obtener_hash_deducciones
83
+ { 'Deducciones' => @deducciones.map(&:to_h) }
84
+ end
85
+
86
+ def obtener_hash_incapacidades
87
+ { 'Incapacidades' => @incapacidades.map(&:to_h) }
88
+ end
89
+
90
+ def obtener_hash_horas_extra
91
+ { 'InformacionHorasExtra' => @horas_extras.map(&:to_h) }
92
+ end
93
+
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,32 @@
1
+ module FmLayout
2
+ module Nomina
3
+ class Percepcion
4
+
5
+ include ::FmLayout::FmSeccion
6
+
7
+ def initialize
8
+ @titulo= 'Percepcion'
9
+ @datos= {}
10
+ #valores_iniciales
11
+ end
12
+
13
+ def self.campos_vs_metodos
14
+ {
15
+ 'TipoPercepcion' => 'tipo',
16
+ 'Clave' => 'clave',
17
+ 'Concepto' => 'concepto',
18
+ 'ImporteGravado' => 'importe_gravado',
19
+ 'ImporteExento' => 'importe_exento',
20
+ }
21
+ end
22
+
23
+ # Creación de los métodos de acceso dinámicamente
24
+ campos_vs_metodos.each do |campo, metodo|
25
+ define_method(metodo) do |dato|
26
+ @datos[campo] = dato
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ require 'fm_layout/fm_seccion'
2
+
3
+ module FmLayout
4
+ class Receptor
5
+ include FmSeccion
6
+
7
+ def initialize
8
+ @titulo = 'Receptor'
9
+ @datos = {}
10
+ end
11
+
12
+ def self.campos_vs_metodos
13
+ {
14
+ 'rfc' => 'rfc',
15
+ 'nombre' => 'nombre',
16
+ 'NumCliente' => 'numero_de_cliente',
17
+ 'emailCliente' => 'email',
18
+ }
19
+ end
20
+
21
+ # Creación de los métodos de acceso dinámicamente
22
+ campos_vs_metodos.each do |campo, metodo|
23
+ define_method(metodo) do |dato|
24
+ @datos[campo] = dato
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module FmLayout
2
+ VERSION = "0.0.1"
3
+ end
data/lib/fm_layout.rb ADDED
@@ -0,0 +1,19 @@
1
+ require "fm_layout/version"
2
+ require "fm_layout/fm_layout"
3
+
4
+ module FmLayout
5
+ def self.define_layout
6
+ layout = FmLayout.new
7
+ yield(layout) if block_given?
8
+ layout
9
+ end
10
+ end
11
+
12
+ # Monkeypatch
13
+ if RUBY_VERSION < '2.0'
14
+ class NilClass
15
+ def to_h
16
+ {}
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,276 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'DSL para generar el layout de Facturación Moderna para nómina' do
5
+ context 'nómina' do
6
+ context 'llenando todos los campos' do
7
+ let(:hoy){ Date.today }
8
+ let(:inicio_quincena){ Date.today - 15 }
9
+ let(:fin_quincena){ Date.today }
10
+ let(:inicio_relacion_laboral){ Date.today - 48*7 }
11
+ let(:prueba) do
12
+ # DSL
13
+ FmLayout.define_layout do |f|
14
+ f.encabezado do |e|
15
+ e.tipo_de_comprobante 'egreso'
16
+ e.forma_de_pago 'PAGO EN UNA SOLA EXHIBICIÓN'
17
+ e.metodo_de_pago 'Transferencia Electrónica'
18
+ e.condiciones_de_pago 'Contado'
19
+ e.motivo_de_descuento 'Deducciones de nómina'
20
+ e.lugar_de_expedicion 'Nuevo León, México'
21
+ end
22
+ f.datos_adicionales do |d|
23
+ d.tipo_de_documento 'RECIBO DE NOMINA'
24
+ d.id_de_nomina 'N-1'
25
+ d.id_de_trabajador ''
26
+ d.leyenda 'Leyenda al pie del recibo'
27
+ end
28
+ f.emisor do |e|
29
+ e.rfc 'ESI920427886'
30
+ e.nombre 'FACTURACION MODERNA S.A de C.V.'
31
+ e.regimen_fiscal 'REGIMEN GENERAL DE LEY PERSONAS MORALES'
32
+ end
33
+ f.receptor do |r|
34
+ r.rfc 'XAXX010101000'
35
+ r.nombre 'RAMIREZ MARTINEZ JUAN JOSE'
36
+ end
37
+ f.concepto do |c|
38
+ c.unidad 'Servicio'
39
+ c.descripcion 'Pago de Nómina'
40
+ c.valor_unitario 3100.00
41
+ c.importe 3100.00
42
+ end
43
+
44
+ f.nomina do |n|
45
+ n.complemento_nomina do |c|
46
+ c.registro_patronal 'P123456789'
47
+ c.numero_de_empleado '2013001'
48
+ c.curp 'XEXX010101MOCNRR02'
49
+ c.tipo_de_regimen 1
50
+ c.numero_de_seguridad_social '12345678912'
51
+ c.fecha_de_pago hoy.strftime("%F")
52
+ c.fecha_inicial_de_pago inicio_quincena.strftime("%F")
53
+ c.fecha_final_de_pago fin_quincena.strftime("%F")
54
+ c.dias_pagados 15
55
+ c.departamento 'Desarrollo'
56
+ c.clabe '123456789012345678'
57
+ c.banco '012'
58
+ c.inicio_de_relacion_laboral inicio_relacion_laboral.strftime("%F")
59
+ c.antiguedad 48
60
+ c.puesto 'Programador'
61
+ c.tipo_de_contrato 'Base'
62
+ c.tipo_de_jornada 'Mixta'
63
+ c.periodicidad_de_pago 'Quincenal'
64
+ c.salario_base 200
65
+ c.riesgo_del_puesto 5
66
+ c.salario_diario_integrado 209.04
67
+ end
68
+
69
+ n.percepcion do |p|
70
+ p.tipo '001'
71
+ p.clave '001'
72
+ p.concepto 'Sueldos'
73
+ p.importe_gravado 3000
74
+ p.importe_exento 0
75
+ end
76
+
77
+ n.percepcion do |p|
78
+ p.tipo '019'
79
+ p.clave '019'
80
+ p.concepto 'Horas extra'
81
+ p.importe_gravado 0.0
82
+ p.importe_exento 100.0
83
+ end
84
+
85
+ n.deduccion do |d|
86
+ d.tipo '002'
87
+ d.clave '001'
88
+ d.concepto 'ISR'
89
+ d.importe_gravado 0.0
90
+ d.importe_exento 76.97
91
+ end
92
+
93
+ n.deduccion do |d|
94
+ d.tipo '001'
95
+ d.clave '002'
96
+ d.concepto 'IMSS'
97
+ d.importe_gravado 0.0
98
+ d.importe_exento 75.36
99
+ end
100
+
101
+ n.deduccion do |d|
102
+ d.tipo '006'
103
+ d.clave '006'
104
+ d.concepto 'Descuento por incapacidad'
105
+ d.importe_gravado 0.0
106
+ d.importe_exento 200.00
107
+ end
108
+
109
+ n.incapacidad do |i|
110
+ i.dias 1
111
+ i.tipo 2
112
+ i.descuento 200.00
113
+ end
114
+
115
+ n.horas_extra do |h|
116
+ h.dias 1
117
+ h.tipo 'Dobles'
118
+ h.horas_extra 1
119
+ h.importe 100.00
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ context 'encabezado' do
126
+ let(:encabezado){ prueba.to_h['Encabezado'] }
127
+ it{ expect(encabezado['fecha']).to eq('asignarFecha') }
128
+ it{ expect(encabezado['tipoDeComprobante']).to eq('egreso') }
129
+ it{ expect(encabezado['formaDePago']).to eq('PAGO EN UNA SOLA EXHIBICIÓN') }
130
+ it{ expect(encabezado['condicionesDePago']).to eq('Contado') }
131
+ it{ expect(encabezado['motivoDescuento']).to eq('Deducciones de nómina') }
132
+ it{ expect(encabezado['LugarExpedicion']).to eq('Nuevo León, México') }
133
+ end
134
+
135
+ context 'datos adicionales' do
136
+ let(:datos_adicionales){ prueba.to_h['Datos Adicionales'] }
137
+ it{ expect(datos_adicionales['tipoDocumento']).to eq('RECIBO DE NOMINA') }
138
+ it{ expect(datos_adicionales['idNomina']).to eq('N-1') }
139
+ it{ expect(datos_adicionales['idTrabajador']).to eq('') }
140
+ it{ expect(datos_adicionales['leyenda']).to eq('Leyenda al pie del recibo') }
141
+ end
142
+
143
+ context 'emisor' do
144
+ let(:emisor){ prueba.to_h['Emisor'] }
145
+ it{ expect(emisor['rfc']).to eq('ESI920427886') }
146
+ it{ expect(emisor['nombre']).to eq('FACTURACION MODERNA S.A de C.V.') }
147
+ it{ expect(emisor['RegimenFiscal']).to eq('REGIMEN GENERAL DE LEY PERSONAS MORALES') }
148
+ end
149
+
150
+ context 'receptor' do
151
+ let(:receptor){ prueba.to_h['Receptor'] }
152
+ it{ expect(receptor['rfc']).to eq('XAXX010101000') }
153
+ it{ expect(receptor['nombre']).to eq('RAMIREZ MARTINEZ JUAN JOSE') }
154
+ end
155
+
156
+ context 'concepto' do
157
+ let(:concepto){ prueba.to_h['Conceptos'].first['Concepto'] }
158
+ it{ expect(concepto['cantidad']).to eq(1) }
159
+ it{ expect(concepto['unidad']).to eq('Servicio') }
160
+ it{ expect(concepto['descripcion']).to eq('Pago de Nómina') }
161
+ it{ expect(concepto['valorUnitario']).to eq(3100.00) }
162
+ it{ expect(concepto['importe']).to eq(3100.00) }
163
+ end
164
+
165
+ context 'nomina' do
166
+ let(:nomina){ prueba.to_h['Nomina'] }
167
+ context 'complemento nomina' do
168
+ let(:complemento){ nomina['ComplementoNomina'] }
169
+ it{ expect(complemento['RegistroPatronal']).to eq('P123456789') }
170
+ it{ expect(complemento['NumEmpleado']).to eq('2013001') }
171
+ it{ expect(complemento['CURP']).to eq('XEXX010101MOCNRR02') }
172
+ it{ expect(complemento['TipoRegimen']).to eq(1)}
173
+ it{ expect(complemento['NumSeguridadSocial']).to eq('12345678912')}
174
+ it{ expect(complemento['FechaPago']).to eq(hoy.strftime("%F"))}
175
+ it{ expect(complemento['FechaInicialPago']).to eq(inicio_quincena.strftime("%F"))}
176
+ it{ expect(complemento['FechaFinalPago']).to eq(fin_quincena.strftime("%F"))}
177
+ it{ expect(complemento['NumDiasPagados']).to eq(15)}
178
+ it{ expect(complemento['Departamento']).to eq('Desarrollo')}
179
+ it{ expect(complemento['CLABE']).to eq('123456789012345678')}
180
+ it{ expect(complemento['Banco']).to eq('012')}
181
+ it{ expect(complemento['FechaInicioRelLaboral']).to eq(inicio_relacion_laboral.strftime("%F"))}
182
+ it{ expect(complemento['Antiguedad']).to eq(48)}
183
+ it{ expect(complemento['Puesto']).to eq('Programador')}
184
+ it{ expect(complemento['TipoContrato']).to eq('Base')}
185
+ it{ expect(complemento['PeriodicidadPago']).to eq('Quincenal')}
186
+ it{ expect(complemento['SalarioBaseCotApor']).to eq(200.0)}
187
+ it{ expect(complemento['RiesgoPuesto']).to eq(5)}
188
+ it{ expect(complemento['SalarioDiarioIntegrado']).to eq(209.04)}
189
+ end
190
+
191
+ context 'percepciones' do
192
+ context 'primera percepcion' do
193
+ let(:percepcion) { nomina['Percepciones'].first['Percepcion'] }
194
+ it{ expect(percepcion['TipoPercepcion']).to eq('001')}
195
+ it{ expect(percepcion['Clave']).to eq('001')}
196
+ it{ expect(percepcion['Concepto']).to eq('Sueldos')}
197
+ it{ expect(percepcion['ImporteGravado']).to eq(3000.00)}
198
+ it{ expect(percepcion['ImporteExento']).to eq(0.00)}
199
+ end
200
+
201
+ context 'segunda percepcion' do
202
+ let(:percepcion) { nomina['Percepciones'].last['Percepcion'] }
203
+ it{ expect(percepcion['TipoPercepcion']).to eq('019')}
204
+ it{ expect(percepcion['Clave']).to eq('019')}
205
+ it{ expect(percepcion['Concepto']).to eq('Horas extra')}
206
+ it{ expect(percepcion['ImporteGravado']).to eq(0.00)}
207
+ it{ expect(percepcion['ImporteExento']).to eq(100.00)}
208
+ end
209
+ end
210
+
211
+ context 'deducciones' do
212
+ context 'primera deduccion' do
213
+ let(:deduccion) { nomina['Deducciones'][0]['Deduccion'] }
214
+ it{ expect(deduccion['TipoPercepcion']).to eq('002')}
215
+ it{ expect(deduccion['Clave']).to eq('001')}
216
+ it{ expect(deduccion['Concepto']).to eq('ISR')}
217
+ it{ expect(deduccion['ImporteGravado']).to eq(0.00)}
218
+ it{ expect(deduccion['ImporteExento']).to eq(76.97)}
219
+ end
220
+
221
+ context 'segunda deduccion' do
222
+ let(:deduccion) { nomina['Deducciones'][1]['Deduccion'] }
223
+ it{ expect(deduccion['TipoPercepcion']).to eq('001')}
224
+ it{ expect(deduccion['Clave']).to eq('002')}
225
+ it{ expect(deduccion['Concepto']).to eq('IMSS')}
226
+ it{ expect(deduccion['ImporteGravado']).to eq(0.00)}
227
+ it{ expect(deduccion['ImporteExento']).to eq(75.36)}
228
+ end
229
+
230
+ context 'tercera deduccion' do
231
+ let(:deduccion) { nomina['Deducciones'][2]['Deduccion'] }
232
+ it{ expect(deduccion['TipoPercepcion']).to eq('006')}
233
+ it{ expect(deduccion['Clave']).to eq('006')}
234
+ it{ expect(deduccion['Concepto']).to eq('Descuento por incapacidad')}
235
+ it{ expect(deduccion['ImporteGravado']).to eq(0.00)}
236
+ it{ expect(deduccion['ImporteExento']).to eq(200.0)}
237
+ end
238
+ end
239
+
240
+ context 'incapacidades' do
241
+ context 'primera incapacidad' do
242
+ let(:incapacidad) { nomina['Incapacidades'].first['Incapacidad'] }
243
+ it{ expect(incapacidad['DiasIncapacidad']).to eq(1)}
244
+ it{ expect(incapacidad['TipoIncapacidad']).to eq(2)}
245
+ it{ expect(incapacidad['Descuento']).to eq(200.00)}
246
+ end
247
+ end
248
+
249
+ context 'horas extra' do
250
+ context 'primera hora extra' do
251
+ let(:hora_extra) { nomina['InformacionHorasExtra'].first['HorasExtra'] }
252
+ it{ expect(hora_extra['Dias']).to eq(1)}
253
+ it{ expect(hora_extra['TipoHoras']).to eq('Dobles')}
254
+ it{ expect(hora_extra['HorasExtra']).to eq(1)}
255
+ it{ expect(hora_extra['ImportePagado']).to eq(100.00)}
256
+ end
257
+ end
258
+
259
+ end
260
+
261
+ context 'salida en texto' do
262
+ let(:salida){ prueba.to_s }
263
+ it{ expect(salida).to match(/\[Encabezado\]/) }
264
+ it{ expect(salida).to match(/\[Datos Adicionales\]/) }
265
+ it{ expect(salida).to match(/\[Emisor\]/) }
266
+ it{ expect(salida).to match(/\[Receptor\]/) }
267
+ it{ expect(salida).to match(/\[Concepto\]/) }
268
+ it{ expect(salida).to match(/\[ComplementoNomina\]/) }
269
+ it{ expect(salida).to match(/\[Percepcion\]/) }
270
+ it{ expect(salida).to match(/\[Deduccion\]/) }
271
+ it{ expect(salida).to match(/\[Incapacidad\]/) }
272
+ it{ expect(salida).to match(/\[HorasExtra\]/) }
273
+ end
274
+ end
275
+ end
276
+ end