File manager - Edit - /var/www/html/portalHomolog/database/seeders/ConveniosPlanilhaImportSeeder.php
Back
<?php namespace Database\Seeders; use App\Models\Convenio; use Carbon\Carbon; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; use PhpOffice\PhpSpreadsheet\IOFactory; use Symfony\Component\Console\Helper\ProgressBar; /** * Importa convênios da planilha institucional (PPPs e Convênios). * * Execute: php artisan db:seed --class=ConveniosPlanilhaImportSeeder */ class ConveniosPlanilhaImportSeeder extends Seeder { private const PLANILHA_PATH = 'temp/Planilha_CONVENIOS (1).xlsx'; private const LINHA_CABECALHO = 4; private const CONCEDENTE_PADRAO = 'Estado do Rio de Janeiro'; private ?ProgressBar $barraProgresso = null; /** @var array<int, string> */ private array $idsImportados = []; /** @var array<int, array{linha: int, motivo: string, dados?: array<string, string|null>}> */ private array $ignorados = []; /** @var array<int, array{linha: int, erro: string, dados?: array<string, string|null>}> */ private array $erros = []; private int $totalLinhasDados = 0; private float $inicio = 0; public function run(): void { $this->inicio = microtime(true); $this->exibirCabecalho(); $caminho = base_path(self::PLANILHA_PATH); if (!is_file($caminho)) { $this->command?->error(__('Planilha não encontrada: :path', ['path' => self::PLANILHA_PATH])); throw new \RuntimeException('Planilha de convênios não encontrada.'); } $linhasDados = $this->carregarLinhasDados($caminho); $this->totalLinhasDados = count($linhasDados); $this->command?->info(__('Linhas de dados identificadas: :total', ['total' => $this->totalLinhasDados])); $this->command?->newLine(); DB::beginTransaction(); try { $this->iniciarBarraProgresso(); foreach ($linhasDados as $numeroLinha => $linha) { $this->processarLinha($numeroLinha, $linha); $this->barraProgresso?->advance(); $this->barraProgresso?->setMessage($this->formatarMensagemProgresso()); } $this->finalizarBarraProgresso(); if ($this->erros !== []) { throw new \RuntimeException( __('Importação interrompida: :total erro(s) encontrado(s). Nenhum registro foi persistido.', [ 'total' => count($this->erros), ]) ); } DB::commit(); $this->exibirRelatorioFinal(true); } catch (\Throwable $exception) { DB::rollBack(); $this->finalizarBarraProgresso(); $this->exibirRelatorioFinal(false, $exception->getMessage()); throw $exception; } } private function exibirCabecalho(): void { $this->command?->info(str_repeat('=', 60)); $this->command?->info(__('Importação de Convênios — Planilha institucional')); $this->command?->info(str_repeat('=', 60)); $this->command?->info(__('Arquivo: :path', ['path' => self::PLANILHA_PATH])); } /** * @return array<int, array<string, string|null>> */ private function carregarLinhasDados(string $caminho): array { $sheet = IOFactory::load($caminho)->getActiveSheet(); $rows = $sheet->toArray(null, true, true, true); $linhas = []; foreach ($rows as $numeroLinha => $row) { if ($numeroLinha <= self::LINHA_CABECALHO) { continue; } $normalizada = [ 'processo' => $this->nullableString($row['A'] ?? null), 'objeto' => $this->nullableString($row['B'] ?? null), 'numero_convenio' => $this->nullableString($row['C'] ?? null), 'saldo' => $this->nullableString($row['D'] ?? null), 'unidade' => $this->nullableString($row['E'] ?? null), 'fase_atual' => $this->nullableString($row['F'] ?? null), 'vigencia' => $this->nullableString($row['G'] ?? null), ]; if ($this->linhaVazia($normalizada)) { continue; } $linhas[$numeroLinha] = $normalizada; } return $linhas; } /** * @param array<string, string|null> $linha */ private function processarLinha(int $numeroLinha, array $linha): void { if ($linha['objeto'] === null && $linha['numero_convenio'] === null) { $this->ignorados[] = [ 'linha' => $numeroLinha, 'motivo' => __('Linha sem objeto e sem número de convênio.'), 'dados' => $linha, ]; return; } if ($this->registroJaExiste($linha)) { $this->ignorados[] = [ 'linha' => $numeroLinha, 'motivo' => __('Registro já existente no banco (mesmo número de convênio e objeto).'), 'dados' => $linha, ]; return; } try { $dados = $this->mapearParaConvenio($linha); $convenio = Convenio::query()->create($dados); $this->idsImportados[] = $convenio->id; } catch (\Throwable $exception) { $this->erros[] = [ 'linha' => $numeroLinha, 'erro' => $exception->getMessage(), 'dados' => $linha, ]; } } /** * @param array<string, string|null> $linha */ private function registroJaExiste(array $linha): bool { $query = Convenio::query(); if ($linha['numero_convenio'] !== null) { $query->where('numero_instrumento', $linha['numero_convenio']); } if ($linha['objeto'] !== null) { $query->where('objeto', $linha['objeto']); } if ($linha['numero_convenio'] === null && $linha['objeto'] === null) { return false; } return $query->exists(); } /** * @param array<string, string|null> $linha * @return array<string, mixed> */ private function mapearParaConvenio(array $linha): array { $faseAtual = $linha['fase_atual'] ?? ''; $vigencia = $this->parseData($linha['vigencia']); $temSuspensiva = $faseAtual !== '' && str_contains(mb_strtolower($faseAtual), 'suspensiva'); $status = 'ATIVADO'; $saldoUpper = mb_strtoupper((string) ($linha['saldo'] ?? '')); $faseUpper = mb_strtoupper($faseAtual); if ( str_contains($saldoUpper, 'ENCERRADO') || str_contains($saldoUpper, 'DISTRATO') || str_contains($faseUpper, 'ENCERRADO') || str_contains($faseUpper, 'CANCELADO') || str_contains($faseUpper, 'DISTRATO') ) { $status = 'DESATIVADO'; } return [ 'id' => (string) Str::uuid(), 'objeto' => $linha['objeto'] ?? __('Sem objeto informado na planilha'), 'numero_instrumento' => $linha['numero_convenio'], 'numero_processo_sei' => $linha['processo'], 'executor_ordenador' => $linha['unidade'], 'concedente' => self::CONCEDENTE_PADRAO, 'status_plataforma' => $linha['saldo'], 'andamento' => $linha['fase_atual'], 'vigencia_prazo_contratual' => $vigencia, 'vigencia_clausula_suspensiva' => $temSuspensiva ? $vigencia : null, 'porcentagem_conclusao' => $this->inferirPorcentagemConclusao($linha), 'status' => $status, 'show_objeto' => true, 'show_numero_instrumento' => true, 'show_numero_processo_sei' => true, 'show_executor_ordenador' => true, 'show_concedente' => true, 'show_status_plataforma' => true, 'show_andamento' => true, 'show_vigencia_prazo_contratual' => $vigencia !== null, 'show_vigencia_clausula_suspensiva' => $temSuspensiva && $vigencia !== null, ]; } /** * @param array<string, string|null> $linha */ private function inferirPorcentagemConclusao(array $linha): ?float { $texto = mb_strtoupper(implode(' ', array_filter([ $linha['saldo'] ?? '', $linha['fase_atual'] ?? '', ]))); if ( str_contains($texto, 'ENCERRADO') || (str_contains($texto, 'APROVADO') && str_contains($texto, 'FINAL')) ) { return 100.0; } if (str_contains($texto, 'FINALIZANDO')) { return 90.0; } if (str_contains($texto, 'LICITADO') || str_contains($texto, 'LICITAÇÃO') || str_contains($texto, 'LICITACAO')) { return 60.0; } if (str_contains($texto, 'AGUARDANDO') || str_contains($texto, 'ELABORANDO')) { return 30.0; } return null; } private function parseData(?string $valor): ?string { $valor = trim((string) $valor); if ($valor === '') { return null; } $formatos = ['d/m/Y', 'd/m/y', 'Y-m-d']; foreach ($formatos as $formato) { try { $data = Carbon::createFromFormat($formato, $valor); return $data->format('Y-m-d'); } catch (\Throwable) { continue; } } throw new \InvalidArgumentException(__('Data de vigência inválida: :valor', ['valor' => $valor])); } /** * @param array<string, string|null> $linha */ private function linhaVazia(array $linha): bool { foreach ($linha as $valor) { if ($valor !== null && trim($valor) !== '') { return false; } } return true; } private function nullableString(mixed $valor): ?string { $valor = trim((string) $valor); return $valor !== '' ? $valor : null; } private function iniciarBarraProgresso(): void { if ($this->command === null || $this->totalLinhasDados === 0) { return; } $this->barraProgresso = $this->command->getOutput()->createProgressBar($this->totalLinhasDados); $this->barraProgresso->setFormat( " %current%/%max% [%bar%] %percent:3s%% — %message%\n" ); $this->barraProgresso->setMessage($this->formatarMensagemProgresso()); $this->barraProgresso->start(); } private function finalizarBarraProgresso(): void { if ($this->barraProgresso === null) { return; } $this->barraProgresso->finish(); $this->command?->newLine(2); $this->barraProgresso = null; } private function formatarMensagemProgresso(): string { return sprintf( 'importados: %d | ignorados: %d | erros: %d', count($this->idsImportados), count($this->ignorados), count($this->erros) ); } private function exibirRelatorioFinal(bool $sucesso, ?string $mensagemFalha = null): void { $duracao = round(microtime(true) - $this->inicio, 2); $this->command?->info(str_repeat('=', 60)); $this->command?->info(__('RELATÓRIO FINAL — Importação de Convênios')); $this->command?->info(str_repeat('=', 60)); $this->command?->info(__('Status : :status', [ 'status' => $sucesso ? __('SUCESSO') : __('FALHA (rollback aplicado)'), ])); $this->command?->info(__('Linhas na planilha: :total', ['total' => $this->totalLinhasDados])); $this->command?->info(__('Importadas : :total', ['total' => count($this->idsImportados)])); $this->command?->info(__('Ignoradas : :total', ['total' => count($this->ignorados)])); $this->command?->info(__('Erros : :total', ['total' => count($this->erros)])); $this->command?->info(__('Duração : :segundos s', ['segundos' => $duracao])); if ($mensagemFalha !== null) { $this->command?->error(__('Motivo : :msg', ['msg' => $mensagemFalha])); } if ($this->ignorados !== []) { $this->command?->newLine(); $this->command?->warn(__('Detalhe das linhas ignoradas:')); foreach ($this->ignorados as $item) { $this->command?->warn(sprintf( ' Linha %d — %s | Convênio: %s | Objeto: %s', $item['linha'], $item['motivo'], $item['dados']['numero_convenio'] ?? '—', Str::limit($item['dados']['objeto'] ?? '—', 50) )); } } if ($this->erros !== []) { $this->command?->newLine(); $this->command?->error(__('Detalhe dos erros:')); foreach ($this->erros as $item) { $this->command?->error(sprintf( ' Linha %d — %s | Convênio: %s | Objeto: %s', $item['linha'], $item['erro'], $item['dados']['numero_convenio'] ?? '—', Str::limit($item['dados']['objeto'] ?? '—', 50) )); } } if ($sucesso && $this->idsImportados !== []) { $this->command?->newLine(); $this->command?->info(__('IDs importados (amostra até 5):')); foreach (array_slice($this->idsImportados, 0, 5) as $id) { $this->command?->line(' - ' . $id); } if (count($this->idsImportados) > 5) { $this->command?->line(__(' ... e mais :n registro(s).', ['n' => count($this->idsImportados) - 5])); } } $this->command?->info(str_repeat('=', 60)); } }
| ver. 1.4 |
Github
|
.
| PHP 8.3.28 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings