fm_layout 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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