Ir para o conteúdo principal

Meios técnicos para gerar relatórios de conflitos dos plantões dos servidores (Estado x Município)

Data de elaboração

06/02/2023

Responsável pelo estudo

Jose Lucas da Silva Costa (Analista de Desenvolvimento Full-Stack)


Equipe do estudo

João Pedro Rocha Brito (Assessor);

José Lucas da Silva Costa (Analista de Desenvolvimento Full-Stack)

Jônatas Neves Legal (Técnico em Tecnologia da Informação e Comunicação) 

Alvo Sistema Skala
Origem

Problemas de conflito de plantões dos servidores que trabalham com vínculo no estado e no município.

Objetivo

Elaborar os meios técnicos necessários, para gerar relatório dos servidores que estão em situação de conflito em seus plantões do estado e no município.
Documentação Correlata

Observações

Sem observações.

1. Glossário de Termos


  • API:  Application Programming Interface - uma interface de programação de aplicativos que permite que dois sistemas se comuniquem.
  • PDF: Portable Document Format - um formato de arquivo de computador usado para exibir documentos de forma consistente independentemente do dispositivo ou sistema operacional.
  • SQL Server: Sistema de Gerenciamento de Banco de Dados Relacional da Microsoft - um sistema de gerenciamento de banco de dados relacional usado para armazenar e acessar os dados de um aplicativo.

2. Introdução


Este estudo busca criar um relatório para identificar possíveis conflitos entre o Governo do Estado de Rondônia e a Prefeitura Municipal de Porto Velho, no que se refere às escalas de plantão dos servidores. Para isso, será utilizada a API da prefeitura, que receberá os parâmetros "CPF", "Ano" e "Mês", e retornará os plantões dos servidores da prefeitura. Esses dados serão comparados com os dados do sistema de escalas de plantões do Estado, chamado Skala, para verificar se há possíveis conflitos entre os plantões dos servidores envolvidos.

3. Meios técnicos para elaborar o relatório


3.1 Produto esperado

O relatório de conflitos entre as escalas de plantão do Estado e da Prefeitura será gerado por meio de uma API desenvolvida em C#. Com ela, será possível obter os dados necessários para a comparação das escalas. A conexão do C# ao Banco de Dados SQL Server será o primeiro passo. Após a conexão, será criada uma consulta para a extração dos dados. Para obter os resultados mais rapidamente possível, a query será otimizada. Uma vez extraídos os dados, serão comparados com os dados obtidos da API da prefeitura. Assim, serão identificados os possíveis conflitos entre as escalas. Por fim, a API será responsável por retornar os dados para a geração do PDF, que conterá o relatório de conflitos entre as escalas.

3.2 Diagrama de fluxo de dados

Considerando toda a problemática envolvida, os fluxos de dados fica da seguinte forma:

image.pngFonte: Titãs

3.3 Desempenho

O relatório de conflitos entre as escalas de plantão do Estado e da Prefeitura será gerado por meio de uma API desenvolvida em C#. Com ela, será possível obter os dados necessários para a comparação das escalas. O processo de extração dos dados se inicia com a conexão do C# ao Banco de Dados SQL Server.

Após a conexão, será criada uma consulta para a extração dos dados. Para obter os resultados mais rapidamente possível, a query será otimizada e executada em forma de multitarefa. Uma vez extraídos os dados, serão comparados com os dados obtidos da API da prefeitura. Assim, serão identificados os possíveis conflitos entre as escalas.

Por fim, a API será responsável por retornar os dados para a geração do PDF , que conterá o relatório de conflitos entre as escalas. A respeito do uso desta solução para outros sistemas, A solução desenvolvida para a geração do relatório de conflitos entre as escalas de plantão do Estado e da Prefeitura pode ser facilmente reutilizada para outras necessidades.

4.4 Processamento lógico

Observando o código a seguir pode-se verificar toda lógica envolvida para encontrar os conflitos, inclusive o processo multitarefa, vejamos:

        public async Task<List<ConflitoDto>> ProcessarConflitos(int ano, int mes)
        {
            var plantoesDoMunicipio = new List<PlantaoMunicipalDto>();

            var cpfs = await _repository.Cpfs(ano, mes);

            var blocosDeCpfs = cpfs.Chunk(EscalaConstant.tamanhoDoBlocoDeCpfs);

            var tarefaDosBlocosDosCpfs = blocosDeCpfs.Select(async (list, index) =>
            {
                var resultado = await _municipioService.BuscarPor(list.ToArray(), ano, mes);
                plantoesDoMunicipio.AddRange(resultado);
            });

            await Task.WhenAll(tarefaDosBlocosDosCpfs);

            var conflitos = await ExecutarTarefaEmParaleloDeConflitos(ano, mes, plantoesDoMunicipio);

            return conflitos;
        }

        private async Task<List<ConflitoDto>> ExecutarTarefaEmParaleloDeConflitos(int ano, int mes, List<PlantaoMunicipalDto> plantoesDoMunicipio)
        {
            var conflitos = new List<ConflitoDto>();

            int qtdeEscalas = await _repository.Count(ano, mes);

            int tamanhoDeItensPorPagina = EscalaConstant.tamanhoDeItensPorPagina;

            decimal qtdeDePaginas = Convert.ToDecimal(qtdeEscalas) / Convert.ToDecimal(tamanhoDeItensPorPagina);

            decimal qtdePaginas = Math.Ceiling(qtdeDePaginas);

            var tarefaDosBlocosDosPlantoesDoEstado = Enumerable.Range(1, (int)qtdePaginas).Select(async pagina =>
            {
                var plantoesDoEstado = await _repository.Get(pagina, tamanhoDeItensPorPagina, ano, mes);

                foreach (var plantaoDoEstado in plantoesDoEstado)
                {
                    foreach (var plantaoDoMunicipio in plantoesDoMunicipio.Where(x => x.Cpf == plantaoDoEstado.CpfServidor))
                    {
                        var possuiConflitoNaDataInicialDoEstado = DateTimeConflict.TemConflito(plantaoDoEstado.DataInicial, plantaoDoMunicipio.DataInicial.Value, plantaoDoMunicipio.DataFinal.Value);
                        var possuiConflitoNaDataFinalDoEstado = DateTimeConflict.TemConflito(plantaoDoEstado.DataFinal, plantaoDoMunicipio.DataInicial.Value, plantaoDoMunicipio.DataFinal.Value);

                        var possuiConflitoNaDataInicialDoMunicipio = DateTimeConflict.TemConflito(plantaoDoMunicipio.DataInicial.Value, plantaoDoEstado.DataInicial, plantaoDoEstado.DataFinal);
                        var possuiConflitoNaDataFinalDoMunicipio = DateTimeConflict.TemConflito(plantaoDoMunicipio.DataFinal.Value, plantaoDoEstado.DataInicial, plantaoDoEstado.DataFinal);

                        var possuiConflito = possuiConflitoNaDataInicialDoEstado || possuiConflitoNaDataFinalDoEstado || possuiConflitoNaDataInicialDoMunicipio || possuiConflitoNaDataFinalDoMunicipio;

                        if (possuiConflito)
                        {
                            var conflito = new ConflitoDto
                            {
                                Cpf = plantaoDoEstado.CpfServidor,
                                MatriculaEstado = plantaoDoEstado.Matricula,
                                MatriculaMunicipio = plantaoDoMunicipio.Matricula,
                                Servidor = plantaoDoEstado.Nome,
                                CargoEstado = plantaoDoEstado.Cargo,
                                CargoMunicipio = plantaoDoMunicipio.Cargo,
                                LocalEstado = plantaoDoEstado.Departamento,
                                LocalMunicipio = plantaoDoMunicipio.LocalDeServico,
                                DataInicioEstado = plantaoDoEstado.DataInicial,
                                DataFimEstado = plantaoDoEstado.DataFinal,
                                DataInicioMunicipio = plantaoDoMunicipio.DataInicial ?? new DateTime(),
                                DataFimMunicipio = plantaoDoMunicipio.DataFinal ?? new DateTime()
                            };

                            conflitos.Add(conflito);
                        }
                    }
                }
            });

            await Task.WhenAll(tarefaDosBlocosDosPlantoesDoEstado);

            return conflitos;
        }

O código acima é responsável por verificar possíveis conflitos entre as escalas de plantões dos servidores do município e estado. Primeiro busca-se os CPFs dos servidores que estão na escala do estado e, em seguida, faz-se a busca dos plantões municipais dos servidores para comparar com os plantões do Estado. Após isso, compara-se as datas de início e fim dos plantões municipais com os plantões do Estado para determinar se existe algum conflito. Por fim, são armazenados os possíveis conflitos numa lista para serem exibidos e retornados pela API. Especificamente o método que processa conflitos, é o mais importante pois possui a responsabilidade de ter desempenho. A lista de processamento é dividida em blocos para melhorar o desempenho da busca. Em seguida, é feita uma busca paralela dos plantões municipais dos servidores, usando os CPFs da lista. 

3.4 Valor agregado

A API desenvolvida para a geração do relatório de conflitos entre as escalas de plantão do Estado e da Prefeitura oferece diversos benefícios. Ela permite que os dados sejam extraídos rapidamente e facilita o processo de comparação entre as escalas. Além disso, o relatório pode ser gerado em poucos segundos, o que possibilita a tomada de decisão mais rápida. Dessa forma, os servidores poderão ser escalados de forma mais eficiente, com menos chances de conflitos.

4. Conclusão


O presente ESTUDO TÉCNICO PRELIMINAR, elaborado pelos integrantes TÉCNICOS do time TITÃS, considerando a análise dos desafios técnicos envolvidos e citados, conclui pela VIABILIDADE DA CONSTRUÇÃO DE UM API PARA PROCESSAR CONFLITOS DE PLANTÕES DO SISTEMA SKALA, uma vez que foram considerados os potenciais benefícios em termos de eficiência e também os problemas envolvidos, principalmente potenciais problemas de desempenho da aplicação. Em complemento, os contratempos identificados são administráveis, pelo que RECOMENDAMOS o prosseguimento da demanda. Ressalva-se que o ideal é a construção do processamento em paralelo para melhorias de tempo de resposta.

5. Referências