odorico 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +7 -0
  2. data/bin/odorico +3 -0
  3. data/lib/odorico/arquivo_atestado_de_saude_ocupacional.rb +60 -0
  4. data/lib/odorico/arquivo_aviso_previo.rb +69 -0
  5. data/lib/odorico/arquivo_cargo.rb +60 -0
  6. data/lib/odorico/arquivo_comunicacao_de_acidente_de_trabalho.rb +86 -0
  7. data/lib/odorico/arquivo_condicao_ambiental_de_trabalho.rb +83 -0
  8. data/lib/odorico/arquivo_data.rb +251 -0
  9. data/lib/odorico/arquivo_empregado.rb +401 -0
  10. data/lib/odorico/arquivo_empregado_afastamento_inicio.rb +109 -0
  11. data/lib/odorico/arquivo_empregado_afastamento_termino.rb +102 -0
  12. data/lib/odorico/arquivo_empregado_desligamento.rb +237 -0
  13. data/lib/odorico/arquivo_empregado_historico_cadastral.rb +194 -0
  14. data/lib/odorico/arquivo_empregado_historico_contratual.rb +157 -0
  15. data/lib/odorico/arquivo_empresa.rb +158 -0
  16. data/lib/odorico/arquivo_estabelecimento.rb +138 -0
  17. data/lib/odorico/arquivo_horario.rb +69 -0
  18. data/lib/odorico/arquivo_lotacao.rb +60 -0
  19. data/lib/odorico/arquivo_trabalhador_sem_vinculo.rb +305 -0
  20. data/lib/odorico/arquivo_trabalhador_sem_vinculo_historico_contratual.rb +86 -0
  21. data/lib/odorico/arquivo_trabalhador_sem_vinculo_termino.rb +204 -0
  22. data/lib/odorico/console.rb +11 -0
  23. data/lib/odorico/gerador_de_arquivos.rb +126 -0
  24. data/lib/odorico/gerador_de_arquivos_csv.rb +25 -0
  25. data/lib/odorico/jornada.rb +21 -0
  26. data/lib/odorico/processamento.rb +375 -0
  27. data/lib/odorico/sistema_operacional.rb +33 -0
  28. data/lib/odorico/types.rb +203 -0
  29. data/lib/odorico/version.rb +3 -0
  30. data/lib/odorico.rb +115 -0
  31. metadata +184 -0
@@ -0,0 +1,126 @@
1
+ require_relative 'gerador_de_arquivos_csv'
2
+
3
+ class GeradorDeArquivos
4
+ private
5
+
6
+ def initialize(gerador_de_arquivos_csv:, arquivos_convertidos:)
7
+ @gerador_de_arquivos_csv = gerador_de_arquivos_csv
8
+ @arquivos_convertidos = arquivos_convertidos
9
+ end
10
+
11
+ attr_reader :gerador_de_arquivos_csv, :arquivos_convertidos
12
+
13
+ public
14
+
15
+ def executar
16
+ cargos =
17
+ arquivos_convertidos.select { _1[:fw_tipo] == 'cargo' }
18
+ lotacoes =
19
+ arquivos_convertidos.select { _1[:fw_tipo] == 'lotacao' }
20
+ empregado_desligamento =
21
+ arquivos_convertidos.select { _1[:fw_tipo] == 'empregado_desligamento' }
22
+ empregado_historico_cadastral =
23
+ arquivos_convertidos.select { _1[:fw_tipo] == 'empregado_historico_cadastral' }
24
+ empregado_historico_contratual =
25
+ arquivos_convertidos.select { _1[:fw_tipo] == 'empregado_historico_contratual' }
26
+ empregado =
27
+ arquivos_convertidos.select { _1[:fw_tipo] == 'empregado' }
28
+ empresa =
29
+ arquivos_convertidos.select { _1[:fw_tipo] == 'empresa' }
30
+ estabelecimento =
31
+ arquivos_convertidos.select { _1[:fw_tipo] == 'estabelecimento' }
32
+ horario =
33
+ arquivos_convertidos.select { _1[:fw_tipo] == 'horario' }
34
+ empregados_afastamentos_inicio =
35
+ arquivos_convertidos.select { _1[:fw_tipo] == 'empregado_afastamento_inicio' }
36
+ empregados_afastamentos_termino =
37
+ arquivos_convertidos.select { _1[:fw_tipo] == 'empregado_afastamento_termino' }
38
+ trabalhador_sem_vinculo =
39
+ arquivos_convertidos.select { _1[:fw_tipo] == 'trabalhador_sem_vinculo' }
40
+ trabalhador_sem_vinculo_historico_contratual =
41
+ arquivos_convertidos.select { _1[:fw_tipo] == 'trabalhador_sem_vinculo_historico_contratual' }
42
+ trabalhador_sem_vinculo_termino =
43
+ arquivos_convertidos.select { _1[:fw_tipo] == 'trabalhador_sem_vinculo_termino' }
44
+ aviso_previo =
45
+ arquivos_convertidos.select { _1[:fw_tipo] == 'aviso_previo' }
46
+ comunicacao_de_acidente_de_trabalho =
47
+ arquivos_convertidos.select { _1[:fw_tipo] == 'comunicacao_de_acidente_de_trabalho' }
48
+ atestado_de_saude_ocupacional =
49
+ arquivos_convertidos.select { _1[:fw_tipo] == 'atestado_de_saude_ocupacional' }
50
+ condicao_ambiental_de_trabalho =
51
+ arquivos_convertidos.select { _1[:fw_tipo] == 'condicao_ambiental_de_trabalho' }
52
+
53
+ gerador_de_arquivos_csv.executar(
54
+ nome_do_arquivo: 'cargo',
55
+ dados: cargos
56
+ )
57
+ gerador_de_arquivos_csv.executar(
58
+ nome_do_arquivo: 'lotacao',
59
+ dados: lotacoes
60
+ )
61
+ gerador_de_arquivos_csv.executar(
62
+ nome_do_arquivo: 'empregado_desligamento',
63
+ dados: empregado_desligamento
64
+ )
65
+ gerador_de_arquivos_csv.executar(
66
+ nome_do_arquivo: 'empregado_historico_cadastral',
67
+ dados: empregado_historico_cadastral
68
+ )
69
+ gerador_de_arquivos_csv.executar(
70
+ nome_do_arquivo: 'empregado_historico_contratual',
71
+ dados: empregado_historico_contratual
72
+ )
73
+ gerador_de_arquivos_csv.executar(
74
+ nome_do_arquivo: 'empregado',
75
+ dados: empregado
76
+ )
77
+ gerador_de_arquivos_csv.executar(
78
+ nome_do_arquivo: 'empresa',
79
+ dados: empresa
80
+ )
81
+ gerador_de_arquivos_csv.executar(
82
+ nome_do_arquivo: 'estabelecimento',
83
+ dados: estabelecimento
84
+ )
85
+ gerador_de_arquivos_csv.executar(
86
+ nome_do_arquivo: 'horario',
87
+ dados: horario
88
+ )
89
+ gerador_de_arquivos_csv.executar(
90
+ nome_do_arquivo: 'empregado_afastamento_inicio',
91
+ dados: empregados_afastamentos_inicio
92
+ )
93
+ gerador_de_arquivos_csv.executar(
94
+ nome_do_arquivo: 'empregado_afastamento_termino',
95
+ dados: empregados_afastamentos_termino
96
+ )
97
+ gerador_de_arquivos_csv.executar(
98
+ nome_do_arquivo: 'trabalhador_sem_vinculo',
99
+ dados: trabalhador_sem_vinculo
100
+ )
101
+ gerador_de_arquivos_csv.executar(
102
+ nome_do_arquivo: 'trabalhador_sem_vinculo_historico_contratual',
103
+ dados: trabalhador_sem_vinculo_historico_contratual
104
+ )
105
+ gerador_de_arquivos_csv.executar(
106
+ nome_do_arquivo: 'trabalhador_sem_vinculo_termino',
107
+ dados: trabalhador_sem_vinculo_termino
108
+ )
109
+ gerador_de_arquivos_csv.executar(
110
+ nome_do_arquivo: 'aviso_previo',
111
+ dados: aviso_previo
112
+ )
113
+ gerador_de_arquivos_csv.executar(
114
+ nome_do_arquivo: 'comunicacao_de_acidente_de_trabalho',
115
+ dados: comunicacao_de_acidente_de_trabalho
116
+ )
117
+ gerador_de_arquivos_csv.executar(
118
+ nome_do_arquivo: 'atestado_de_saude_ocupacional',
119
+ dados: atestado_de_saude_ocupacional
120
+ )
121
+ gerador_de_arquivos_csv.executar(
122
+ nome_do_arquivo: 'condicao_ambiental_de_trabalho',
123
+ dados: condicao_ambiental_de_trabalho
124
+ )
125
+ end
126
+ end
@@ -0,0 +1,25 @@
1
+ require 'csv'
2
+ require_relative 'sistema_operacional'
3
+
4
+ class GeradorDeArquivosCsv
5
+ private
6
+
7
+ def initialize(pasta_destino)
8
+ @pasta_destino = pasta_destino
9
+ end
10
+
11
+ attr_reader :pasta_destino
12
+
13
+ public
14
+
15
+ def executar(nome_do_arquivo:, dados:)
16
+ if dados.any?
17
+ CSV.open("#{pasta_destino}#{SistemaOperacional.separador}#{nome_do_arquivo}.csv", 'w') do |csv|
18
+ csv << dados.first.keys
19
+ dados.each { csv << _1.values }
20
+ end
21
+ else
22
+ puts "# Gerador de CSV: Não existe dados para o arquivo: #{nome_do_arquivo}"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ class Jornada
2
+ def self.consistente?(tipo_jornada, horarios) # rubocop:disable Metrics/CyclomaticComplexity
3
+ case tipo_jornada
4
+ when nil
5
+ true
6
+ when 1
7
+ horarios.all? { (1..7).cover? _1[:dia] } &&
8
+ horarios.map { _1[:dia] }.then { _1 == _1.uniq }
9
+ when 2
10
+ horarios.size == 1 && horarios.first[:dia] == 8
11
+ when 3
12
+ horarios.all? { _1[:dia] == 8 }
13
+ when 9
14
+ horarios.nil? || horarios.empty?
15
+ end
16
+ end
17
+
18
+ def self.reconstrucao_fiel?(tipo_jornada)
19
+ ![2, 3].include? tipo_jornada
20
+ end
21
+ end
@@ -0,0 +1,375 @@
1
+ require_relative 'types'
2
+ require_relative 'arquivo_data'
3
+ require_relative 'arquivo_cargo'
4
+ require_relative 'arquivo_empregado'
5
+ require_relative 'arquivo_empresa'
6
+ require_relative 'arquivo_horario'
7
+ require_relative 'arquivo_lotacao'
8
+ require_relative 'arquivo_estabelecimento'
9
+ require_relative 'arquivo_trabalhador_sem_vinculo'
10
+ require_relative 'arquivo_empregado_historico_cadastral'
11
+ require_relative 'arquivo_empregado_historico_contratual'
12
+ require_relative 'arquivo_empregado_desligamento'
13
+ require_relative 'arquivo_trabalhador_sem_vinculo_historico_contratual'
14
+ require_relative 'arquivo_empregado_afastamento_inicio'
15
+ require_relative 'arquivo_empregado_afastamento_termino'
16
+ require_relative 'arquivo_trabalhador_sem_vinculo_termino'
17
+ require_relative 'arquivo_aviso_previo'
18
+ require_relative 'arquivo_comunicacao_de_acidente_de_trabalho'
19
+ require_relative 'arquivo_atestado_de_saude_ocupacional'
20
+ require_relative 'arquivo_condicao_ambiental_de_trabalho'
21
+ require_relative 'gerador_de_arquivos'
22
+ require_relative 'sistema_operacional'
23
+
24
+ class Processamento
25
+ private
26
+
27
+ def initialize(caminho_do_diretorio_data, grupo_informado)
28
+ @caminho_do_diretorio_data = caminho_do_diretorio_data
29
+ @grupo_informado = grupo_informado
30
+
31
+ @erros = []
32
+ @erros_lotacoes_gerais = []
33
+ @alertas = []
34
+ @arquivos_convertidos = []
35
+ @prefixos_nao_configurados = Set.new
36
+ @gerador_de_arquivos_csv = GeradorDeArquivosCsv.new(pasta_destino_csv)
37
+ end
38
+
39
+ attr_reader :caminho_do_diretorio_data,
40
+ :grupo_informado,
41
+ :arquivos_convertidos,
42
+ :alertas,
43
+ :erros,
44
+ :prefixos_nao_configurados,
45
+ :gerador_de_arquivos_csv
46
+
47
+ public
48
+
49
+ def executar
50
+ return arquivos_data_nao_encontrados_erro if arquivos_data_nao_encontrados?
51
+
52
+ processar_arquivos_data
53
+
54
+ ajustar_afastamentos_de_inicio
55
+
56
+ gerar_erros_afastamentos_com_termino_sem_inicio
57
+ gerar_erros_horarios_duplicados
58
+ gerar_erros_cargos_duplicados
59
+ gerar_erros_empregado_com_contrato_concomitante
60
+
61
+ criar_pasta_destino_csv
62
+
63
+ erros_ordenados = erros.sort_by { [_1[:type_file], _1[:file_name], _1[:error_message]] }
64
+ alertas_ordenados = alertas.sort_by { [_1[:type_file], _1[:file_name], _1[:alert_message]] }
65
+ gerador_de_arquivos_csv.executar(nome_do_arquivo: 'INFO_erros', dados: erros_ordenados)
66
+ gerador_de_arquivos_csv.executar(nome_do_arquivo: 'INFO_alertas', dados: alertas_ordenados)
67
+ GeradorDeArquivos.new(
68
+ gerador_de_arquivos_csv: gerador_de_arquivos_csv,
69
+ arquivos_convertidos: arquivos_convertidos
70
+ ).executar
71
+
72
+ {
73
+ arquivos_convertidos: arquivos_convertidos,
74
+ erros: erros_ordenados,
75
+ alertas: alertas_ordenados,
76
+ prefixos_nao_configurados: prefixos_nao_configurados,
77
+ quantidade_de_erros: erros_ordenados.size,
78
+ quantidade_de_alertas: alertas_ordenados.size,
79
+ quantidade_de_arquivos_validos: arquivos_convertidos.size
80
+ }
81
+ end
82
+
83
+ private
84
+
85
+ def arquivos_data_nao_encontrados?
86
+ arquivos_data_nao_encontrados.any?
87
+ end
88
+
89
+ def arquivos_data_nao_encontrados
90
+ @arquivos_data_nao_encontrados ||=
91
+ (arquivos_html_que_requerem_arquivo_data - arquivos_data.map { _1.delete_suffix('.data') })
92
+ .map { "#{_1}.data" }
93
+ end
94
+
95
+ def arquivos_html_que_requerem_arquivo_data
96
+ @arquivos_html_que_requerem_arquivo_data ||=
97
+ [
98
+ *arquivos_html.select { _1.start_with?('CAR') },
99
+ *arquivos_html.select { _1.start_with?('HOR') },
100
+ *arquivos_html.select { _1.start_with?('LOT') },
101
+ *arquivos_html
102
+ .select { _1.start_with?('TRA') }
103
+ .reject { _1.include?('CAD') || _1.include?('CON') || _1.include?('DES') }
104
+ ].map { _1.delete_suffix('.html') }
105
+ end
106
+
107
+ def arquivos_html
108
+ @arquivos_html ||= arquivos_do_diretorio_data.select { File.extname(_1) == '.html' }
109
+ end
110
+
111
+ def arquivos_do_diretorio_data
112
+ @arquivos_do_diretorio_data ||= Dir.entries(caminho_do_diretorio_data).sort
113
+ end
114
+
115
+ def arquivos_data_nao_encontrados_erro
116
+ @arquivos_data_nao_encontrados_erro ||=
117
+ begin
118
+ fim_de_linha = SistemaOperacional.windows? ? "\r\n" : "\n"
119
+ <<~HEREDOC
120
+ Arquivo(s) .data não encontrado(s):
121
+ #{arquivos_data_nao_encontrados.join("#{fim_de_linha} ")}
122
+
123
+ AÇÃO SUGERIDA:
124
+ Executar robô novamente. Caso o problema continue, tratar com a equipe do robô.
125
+ HEREDOC
126
+ end
127
+ end
128
+
129
+ def arquivos_data
130
+ @arquivos_data ||=
131
+ arquivos_do_diretorio_data
132
+ .select { File.extname(_1) == '.data' }
133
+ .tap do |arquivos|
134
+ # move para o início da lista para garantir que a empresa seja processada antes dos desligamentos (validação do
135
+ # grupo)
136
+ arquivo_de_empresa = arquivos.select { _1.start_with?('EMP') }.min
137
+ arquivos.insert(0, arquivos.delete(arquivo_de_empresa)) if arquivo_de_empresa
138
+ end
139
+ end
140
+
141
+ def processar_arquivos_data # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
142
+ grupo_da_empresa = nil
143
+ arquivos_data.each do |nome_do_arquivo_data| # rubocop:disable Metrics/BlockLength
144
+ caminho_do_arquivo_data = "#{caminho_do_diretorio_data}#{separador}#{nome_do_arquivo_data}"
145
+ nome_base_do_arquivo_data = File.basename(nome_do_arquivo_data)
146
+ prefixo = nome_base_do_arquivo_data[0, 3]
147
+
148
+ case prefixo
149
+ when 'EMP'
150
+ arquivo_empresa = ArquivoEmpresa.new(caminho_do_arquivo_data, grupo_informado)
151
+ processar(arquivo_empresa)
152
+ grupo_da_empresa = arquivo_empresa.grupo_da_empresa
153
+ when 'EST'
154
+ processar(ArquivoEstabelecimento.new(caminho_do_arquivo_data))
155
+ when 'CAR'
156
+ processar(ArquivoCargo.new(caminho_do_arquivo_data))
157
+ when 'HOR'
158
+ processar(ArquivoHorario.new(caminho_do_arquivo_data))
159
+ when 'LOT'
160
+ processar(ArquivoLotacao.new(caminho_do_arquivo_data))
161
+ when 'TRA'
162
+ sufixo = nome_base_do_arquivo_data.split('-').last[0, 3]
163
+ if sufixo == 'ADM'
164
+ if nome_base_do_arquivo_data.include?('TSV_')
165
+ processar(ArquivoTrabalhadorSemVinculo.new(caminho_do_arquivo_data))
166
+ else
167
+ processar(ArquivoEmpregado.new(caminho_do_arquivo_data))
168
+ end
169
+ elsif nome_base_do_arquivo_data.include?('-ACA[')
170
+ processar(ArquivoEmpregadoHistoricoCadastral.new(caminho_do_arquivo_data))
171
+ elsif nome_base_do_arquivo_data.include?('-ACO[')
172
+ if nome_base_do_arquivo_data.include?('TSV_')
173
+ processar(ArquivoTrabalhadorSemVinculoHistoricoContratual.new(caminho_do_arquivo_data))
174
+ else
175
+ processar(ArquivoEmpregadoHistoricoContratual.new(caminho_do_arquivo_data))
176
+ end
177
+ elsif nome_base_do_arquivo_data.include?('-IAF[') && !nome_base_do_arquivo_data.include?('TSV_')
178
+ processar(ArquivoEmpregadoAfastamentoInicio.new(caminho_do_arquivo_data))
179
+ elsif nome_base_do_arquivo_data.include?('-TAF[') && !nome_base_do_arquivo_data.include?('TSV_')
180
+ processar(ArquivoEmpregadoAfastamentoTermino.new(caminho_do_arquivo_data))
181
+ elsif sufixo == 'GER'
182
+ if nome_base_do_arquivo_data.include?('TSV_')
183
+ processar(ArquivoTrabalhadorSemVinculoTermino.new(caminho_do_arquivo_data))
184
+ else
185
+ processar(ArquivoEmpregadoDesligamento.new(caminho_do_arquivo_data, grupo_da_empresa))
186
+ end
187
+ elsif sufixo == 'AVI'
188
+ processar(ArquivoAvisoPrevio.new(caminho_do_arquivo_data))
189
+ else
190
+ prefixos_nao_configurados << "#{prefixo}-#{sufixo}"
191
+ end
192
+ when 'CAT'
193
+ processar(ArquivoComunicacaoDeAcidenteDeTrabalho.new(caminho_do_arquivo_data))
194
+ when 'ASO'
195
+ processar(ArquivoAtestadoDeSaudeOcupacional.new(caminho_do_arquivo_data))
196
+ when 'AMB'
197
+ processar(ArquivoCondicaoAmbientalDeTrabalho.new(caminho_do_arquivo_data))
198
+ else
199
+ prefixos_nao_configurados << prefixo
200
+ end
201
+ end
202
+ end
203
+
204
+ def processar(arquivo)
205
+ arquivo.processar
206
+ if arquivo.erros.empty?
207
+ arquivos_convertidos << arquivo.atributos
208
+ alertas.push(*arquivo.alertas)
209
+ else
210
+ erros.push(*arquivo.erros)
211
+ end
212
+ arquivo.atributos
213
+ end
214
+
215
+ def ajustar_afastamentos_de_inicio
216
+ afastamentos_de_inicio.each do |afastamento|
217
+ afastamentos_no_inicio_da_fase_2
218
+ .find { _1[:matricula] == afastamento[:matricula] && _1[:data_inicio_afastamento] == afastamento[:data_inicio_afastamento] } # rubocop:disable Layout/LineLength
219
+ &.then do |afastamento_no_inicio_da_fase_2|
220
+ afastamento[:codigo_motivo] = afastamento_no_inicio_da_fase_2[:codigo_motivo]
221
+ end
222
+ end
223
+ end
224
+
225
+ def afastamentos_de_inicio
226
+ @afastamentos_de_inicio ||= arquivos_convertidos.select { _1[:fw_tipo] == 'empregado_afastamento_inicio' }
227
+ end
228
+
229
+ def afastamentos_no_inicio_da_fase_2
230
+ @afastamentos_no_inicio_da_fase_2 ||=
231
+ arquivos_convertidos
232
+ .select { _1[:fw_tipo] == 'empregado' && _1[:data_inicio_afastamento] }
233
+ .map do |empregado|
234
+ {
235
+ matricula: empregado[:matricula],
236
+ data_inicio_afastamento: empregado[:data_inicio_afastamento].to_s,
237
+ codigo_motivo: empregado[:motivo_afastamento]
238
+ }
239
+ end
240
+ end
241
+
242
+ def afastamentos_de_termino_ou_completos
243
+ arquivos_convertidos.select { _1[:fw_tipo] == 'empregado_afastamento_termino' }
244
+ end
245
+
246
+ def gerar_erros_afastamentos_com_termino_sem_inicio
247
+ afastamentos_incompletos
248
+ .select { _1[:fw_tipo] == 'empregado_afastamento_termino' && _1[:inicio_termino_enviados_juntos].nil? }
249
+ .each do |afastamento|
250
+ erros << {
251
+ file_name: afastamento[:file_name],
252
+ type_file: 'empregado_afastamento_termino',
253
+ error_message: "Empregado #{afastamento[:matricula]} possui afastamento de término " \
254
+ "#{afastamento[:data_termino_afastamento]} sem início."
255
+ }
256
+ end
257
+ end
258
+
259
+ def gerar_erros_horarios_duplicados
260
+ horarios
261
+ .map { _1[:codigo_horario_contratual] }
262
+ .tally
263
+ .select { |_, qtd| qtd > 1 }
264
+ .each_key do |codigo_do_horario|
265
+ erros << {
266
+ file_name: '- -',
267
+ type_file: 'horario',
268
+ error_message: "O Horário com código #{codigo_do_horario} possui histórico."
269
+ }
270
+ end
271
+ end
272
+
273
+ def horarios
274
+ arquivos_convertidos.select { _1[:fw_tipo] == 'horario' }
275
+ end
276
+
277
+ def gerar_erros_cargos_duplicados
278
+ cargos
279
+ .map { _1[:codigo_cargo] }
280
+ .tally
281
+ .select { |_, qtd| qtd > 1 }
282
+ .each_key do |codigo_do_cargo|
283
+ erros << {
284
+ file_name: '- -',
285
+ type_file: 'cargo',
286
+ error_message: "O Cargo com código #{codigo_do_cargo} possui histórico."
287
+ }
288
+ end
289
+ end
290
+
291
+ def cargos
292
+ arquivos_convertidos.select { _1[:fw_tipo] == 'cargo' }
293
+ end
294
+
295
+ def gerar_erros_empregado_com_contrato_concomitante
296
+ trabalhadores
297
+ .map { _1[:cpf] }
298
+ .tally
299
+ .select { |_, qtd| qtd > 1 }
300
+ .keys
301
+ .select { contrato_concomitante?(_1) }
302
+ .each do |trabalhador_cpf|
303
+ erros << {
304
+ file_name: '- -',
305
+ type_file: 'empregado',
306
+ error_message: "O Trabalhador com CPF #{trabalhador_cpf} possui contratos de emprego concomitantes."
307
+ }
308
+ end
309
+ end
310
+
311
+ def trabalhadores
312
+ arquivos_convertidos
313
+ .select { _1[:fw_tipo] == 'empregado' }
314
+ .sort_by { _1[:data_admissao_celetista] }
315
+ end
316
+
317
+ def contrato_concomitante?(trabalhador_cpf)
318
+ desligamentos_do_trabalhador = desligamentos.select { _1[:cpf] == trabalhador_cpf }
319
+
320
+ contratos_do_trabalhador =
321
+ trabalhadores
322
+ .select { _1[:cpf] == trabalhador_cpf }
323
+ .map do |trabalhador|
324
+ inicio = trabalhador[:data_admissao_celetista]
325
+ fim = (desligamentos_do_trabalhador.find { _1[:data_admissao] == inicio } || {})[:data_desligamento]
326
+ Struct.new(:inicio, :fim).new(inicio, fim)
327
+ end
328
+
329
+ contratos_do_trabalhador
330
+ .each_cons(2)
331
+ .any? { |contrato_1, contrato_2| contrato_1.fim.nil? || contrato_1.fim >= contrato_2.inicio }
332
+ end
333
+
334
+ def desligamentos
335
+ arquivos_convertidos
336
+ .select { _1[:fw_tipo] == 'empregado_desligamento' }
337
+ .sort_by { _1[:data_desligamento] }
338
+ end
339
+
340
+ def afastamentos_incompletos
341
+ @afastamentos_incompletos ||=
342
+ unir_inicio_termino_afastamentos
343
+ .values
344
+ .select { _1.size < 2 }
345
+ .flatten
346
+ end
347
+
348
+ def unir_inicio_termino_afastamentos
349
+ (afastamentos_de_inicio + afastamentos_de_termino_ou_completos)
350
+ .group_by { [_1[:matricula], _1[:data_inicio_afastamento]] }
351
+ end
352
+
353
+ def criar_pasta_destino_csv
354
+ criar_pasta(pasta_base)
355
+ criar_pasta(pasta_destino_csv)
356
+ end
357
+
358
+ def criar_pasta(pasta)
359
+ Dir.mkdir(pasta)
360
+ rescue Errno::EEXIST
361
+ nil
362
+ end
363
+
364
+ def pasta_base
365
+ @pasta_base ||= "#{SistemaOperacional.windows? ? 'C:\\tmp\\' : '/tmp/'}arquivos_csv_fw"
366
+ end
367
+
368
+ def pasta_destino_csv
369
+ @pasta_destino_csv ||= "#{pasta_base}#{separador}#{Time.now.strftime('%Y%m%d_%H%M%S')}"
370
+ end
371
+
372
+ def separador
373
+ @separador ||= SistemaOperacional.separador
374
+ end
375
+ end
@@ -0,0 +1,33 @@
1
+ module SistemaOperacional
2
+ class << self
3
+ def separador
4
+ windows? ? '\\' : '/'
5
+ end
6
+
7
+ def windows?
8
+ nome == :windows
9
+ end
10
+
11
+ def nome
12
+ host_os = RbConfig::CONFIG['host_os']
13
+ case host_os
14
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
15
+ :windows
16
+ when /darwin|mac os/
17
+ :macosx
18
+ when /linux/
19
+ :linux
20
+ when /solaris|bsd/
21
+ :unix
22
+ else
23
+ raise NaoIdentificado, host_os
24
+ end
25
+ end
26
+ end
27
+
28
+ class NaoIdentificado < StandardError
29
+ def initialize(nome_do_sistema_operacional)
30
+ super("Sistema operacional desconhecido: #{nome_do_sistema_operacional}")
31
+ end
32
+ end
33
+ end