File manager - Edit - /var/www/html/portal/app/Console/Commands/ImportMapaoProjetosProgramas.php
Back
<?php namespace App\Console\Commands; use App\Models\ProjetosProgramas\Objetivo; use App\Models\ProjetosProgramas\Programa; use App\Models\ProjetosProgramas\ProjetoPrograma; use App\Services\ProjetosProgramas\MapaoPdfImportService; use Illuminate\Console\Command; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; class ImportMapaoProjetosProgramas extends Command { protected $signature = 'projetos-programas:import-mapao {arquivo? : Caminho do PDF (default: temp/programaseprojetos/MAPÃO.pdf)} {--dry-run : Apenas simula, sem gravar no banco} {--force : Não pede confirmação} {--gestor= : ID do órgão gestor (structures.id)} {--tipo= : ID do tipo (project_program_types.id) para salvar como} {--data-inicio= : Data de início padrão (YYYY-MM-DD) quando o MAPÃO não informar}'; protected $description = 'Importa o MAPÃO (PDF) para o módulo Projetos e Programas, salvando todos os registros em modo de edição.'; public function handle(MapaoPdfImportService $parser): int { $arquivo = $this->argument('arquivo') ?: base_path('temp/programaseprojetos/MAPÃO.pdf'); $dryRun = (bool) $this->option('dry-run'); if (!is_file($arquivo)) { $this->error('Arquivo não encontrado: ' . $arquivo); return self::FAILURE; } $tipoId = (int) ($this->option('tipo') ?: (DB::table('project_program_types')->where('nome', 'Projeto')->value('id') ?? 0)); if ($tipoId <= 0) { $this->error('Não foi possível determinar o tipo_id (project_program_types). Use --tipo=ID.'); return self::FAILURE; } $gestorId = (string) ($this->option('gestor') ?: $this->resolveDefaultGestorId()); if ($gestorId === '') { $this->error('Não foi possível determinar gestor_structure_id. Use --gestor=UUID (structures.id).'); return self::FAILURE; } $dataInicio = $this->option('data-inicio') ? Carbon::parse((string) $this->option('data-inicio'))->toDateString() : now()->toDateString(); $objetivosNomes = [ 'PONTES MISTAS E PASSARELAS DE PEDESTRES SOBRE RIOS', 'RECUPERAR E REALIZAR O ALARGAMENTO DE ESTRADAS DO MUNICÍPIO', ]; $this->info('Arquivo: ' . $arquivo); $this->info('Gestor (structures.id): ' . $gestorId); $this->info('Tipo (project_program_types.id): ' . $tipoId); $this->info('Data início padrão: ' . $dataInicio); $this->info('Modo: ' . ($dryRun ? 'DRY-RUN (simulação)' : 'IMPORTAÇÃO (grava no banco)')); if (!$dryRun && !$this->option('force')) { if (!$this->confirm('Confirma a importação do MAPÃO para o banco? Isso criará/atualizará Programas/Objetivos e incluirá Projetos em modo de edição.')) { $this->info('Operação cancelada.'); return self::SUCCESS; } } try { $items = $parser->parse($arquivo); } catch (\Throwable $e) { $this->error('Falha ao extrair dados do PDF: ' . $e->getMessage()); return self::FAILURE; } if (empty($items)) { $this->warn('Nenhum item candidato a projeto foi encontrado no PDF (após normalização).'); return self::SUCCESS; } $uniquePrograms = collect($items)->pluck('programa')->filter()->unique()->values(); $uniqueObjectives = collect($items)->pluck('objetivo')->filter()->unique()->values(); // Pré-criar objetivos (e manter consistência de acentuação / uppercase). $objetivosByNome = []; foreach ($objetivosNomes as $nome) { $objetivosByNome[$nome] = $dryRun ? null : $this->firstOrCreateObjetivo($nome); } $stats = [ 'parsed' => count($items), 'programas_distintos' => $uniquePrograms->count(), 'objetivos_distintos' => $uniqueObjectives->count(), 'programas_criados' => 0, 'programas_reusados' => 0, 'objetivos_criados' => 0, 'projetos_criados' => 0, ]; if (!$dryRun) { DB::beginTransaction(); } try { if (!$dryRun) { // contabiliza objetivos criados $stats['objetivos_criados'] = Objetivo::withTrashed()->whereIn('nome', $objetivosNomes)->count(); } foreach ($items as $item) { $programId = null; if (!empty($item['programa'])) { if ($dryRun) { $programId = 1; } else { [$programId, $created] = $this->upsertProgramaId((string) $item['programa']); $stats[$created ? 'programas_criados' : 'programas_reusados']++; } } $objetivoId = null; if (!empty($item['objetivo']) && isset($objetivosByNome[$item['objetivo']])) { $objetivoId = $dryRun ? 1 : $objetivosByNome[$item['objetivo']]->id; } $payload = [ 'denominacao' => (string) $item['denominacao'], 'gestor_structure_id' => $gestorId, 'tipo_id' => $tipoId, 'project_program_id' => $programId, 'project_objective_id' => $objetivoId, 'numero_ordem' => $item['numero'], 'codigo' => $item['numero'], 'data_inicio' => $dataInicio, 'data_termino' => null, 'prazo_entrega_dias' => $item['prazo_entrega_dias'], 'andamento' => $this->buildAndamentoText($item['andamento'], $item['prazo_texto']), 'orcamento_previsto' => $item['orcamento_previsto'] ?? 0, 'orcamento_disponivel' => $item['orcamento_disponivel'] ?? 0, 'status_registro' => 'EM_EDICAO', 'identificacao_done' => false, 'cronograma_done' => false, 'areas_done' => false, 'contato_done' => false, 'dados_done' => false, 'investimento_done' => false, 'prioritario' => false, 'ordem_prioridade' => null, 'prioridade_origem' => null, 'prioridade_definida_por_user_id' => null, 'show_metas_relatorio' => true, ]; if ($dryRun) { $stats['projetos_criados']++; continue; } // Evita duplicar importações do mesmo PDF: tenta achar por (codigo ou numero_ordem) + denominacao. $existing = ProjetoPrograma::query() ->where('codigo', $payload['codigo']) ->where('denominacao', $payload['denominacao']) ->first(); if ($existing) { // Mantém o registro “em edição” e atualiza campos que conseguimos extrair. $existing->fill($payload); $existing->save(); } else { ProjetoPrograma::create($payload); $stats['projetos_criados']++; } } if (!$dryRun) { DB::commit(); } } catch (\Throwable $e) { if (!$dryRun) { DB::rollBack(); } $this->error('Falha durante a importação: ' . $e->getMessage()); return self::FAILURE; } $this->info('Itens parseados do PDF: ' . $stats['parsed']); $this->info('Projetos criados/atualizados: ' . $stats['projetos_criados']); $this->info('Programas distintos no PDF: ' . $stats['programas_distintos']); $this->info('Objetivos distintos no PDF: ' . $stats['objetivos_distintos']); $this->info('Programas criados: ' . $stats['programas_criados']); $this->info('Programas reutilizados: ' . $stats['programas_reusados']); if ($dryRun) { $this->line('Amostra (até 10):'); foreach (array_slice($items, 0, 10) as $row) { $this->line('- ' . ($row['programa'] ? ($row['programa'] . ' | ') : '') . $row['denominacao']); } $this->warn('Dry-run concluído (nenhuma alteração foi feita no banco).'); } else { $this->info('Importação concluída.'); } return self::SUCCESS; } private function resolveDefaultGestorId(): string { // Heurística: tenta SUPOP / Superintendência de Políticas Públicas; senão, pega o primeiro por ordem. $id = DB::table('structures') ->where('abbreviation', 'like', '%SUPOP%') ->orWhere('name', 'like', '%Superintend%Pol%t%cas%P%blicas%') ->value('id'); if (!empty($id)) { return (string) $id; } $first = DB::table('structures')->orderBy('order')->value('id'); return (string) ($first ?? ''); } private function firstOrCreateObjetivo(string $nome): Objetivo { $existing = Objetivo::withTrashed()->where('nome', $nome)->first(); if ($existing) { if ($existing->trashed()) { $existing->restore(); } return $existing; } return Objetivo::create(['nome' => $nome]); } /** * @return array{0:int,1:bool} [id, created] */ private function upsertProgramaId(string $nome): array { $nome = trim($nome); $existing = Programa::withTrashed()->where('nome', $nome)->first(); if ($existing) { if ($existing->trashed()) { $existing->restore(); } return [(int) $existing->id, false]; } $programa = Programa::create(['nome' => $nome]); return [(int) $programa->id, true]; } private function buildAndamentoText(?string $andamento, ?string $prazoTexto): ?string { $andamento = $andamento ? trim($andamento) : null; $prazoTexto = $prazoTexto ? trim($prazoTexto) : null; if ($andamento && $prazoTexto) { return $andamento . ' | Prazo: ' . $prazoTexto; } if ($andamento) { return $andamento; } if ($prazoTexto) { return 'Prazo: ' . $prazoTexto; } return null; } }
| ver. 1.4 |
Github
|
.
| PHP 8.3.28 | Generation time: 0.04 |
proxy
|
phpinfo
|
Settings