user(); $dataNascimento = $paciente->cidadao->data_nascimento; $regrasAtuais = $dataNascimento ? self::getRegrasAtuais($dataNascimento) : collect(); $aplicacoes = self::getAplicacoes($paciente); $calendario = self::getCalendarioVacinal($paciente, $regrasAtuais); $alertas = array_values( array_filter( $calendario, fn($v) => in_array( $v['status'], [ 'em_atraso', 'proximo_do_prazo' ] ) ) ); return [ 'paciente' => self::getDadosPaciente($paciente), 'aplicacoes' => $aplicacoes, 'calendario_vacinal' => $calendario, 'alertas' => $alertas, 'mensagem_orientativa' => self::getMensagemOrientativa($calendario), 'mensagem_civp' => Mensagem::CIVP, ]; } private static function getDadosPaciente(Paciente $paciente): array { $cidadao = $paciente->cidadao; $dataNascimento = $cidadao->data_nascimento; $hoje = Carbon::now(); $diff = $dataNascimento->diff($hoje); return [ 'nome' => $cidadao->nome, 'cpf' => $cidadao->cpf, 'cns' => $cidadao->cns, 'nome_mae' => $cidadao->nome_mae, 'sexo' => $cidadao->sexo ? $cidadao->sexo->descricao : null, 'nacionalidade' => $cidadao->nacionalidade ? $cidadao->nacionalidade->descricao : null, 'data_nascimento' => $dataNascimento->format('Y-m-d'), 'idade' => $dataNascimento->diff($hoje)->format('%ya, %mm e %dd'), 'idade_anos' => (int) $diff->y, 'idade_meses' => (int) $diff->m, 'idade_dias' => (int) $diff->d, ]; } private static function getRegrasAtuais(Carbon $dataNascimento): Collection { $hoje = Carbon::now(); $idade = $dataNascimento->diff($hoje); return DB::table('imunizacao_esquema_vacinal_regra as regra') ->join('imunizacao_esquema_vacinal_faixa_etaria as faixa', 'faixa.id', 'regra.faixa_etaria_id') ->join('cadastro_vacina as vacina', 'vacina.id', 'regra.vacina_id') ->join('imunizacao_dose as dose', 'dose.id', 'regra.dose_id') ->join('imunizacao_estrategia as estrategia', 'estrategia.id', 'regra.estrategia_id') ->where('regra.estrategia_id', Estrategia::ROTINA) ->select( [ 'vacina.id as vacina_id', 'vacina.codigo as vacina_codigo', 'vacina.nome as vacina_nome', 'vacina.abreviacao as vacina_abreviacao', 'vacina.sigla as vacina_sigla', 'dose.id as dose_id', 'dose.nome as dose_nome', 'estrategia.nome as estrategia_nome', 'faixa.inicio_ano', 'faixa.inicio_mes', 'faixa.inicio_dia', 'faixa.fim_ano', 'faixa.fim_mes', 'faixa.fim_dia' ] ) ->where( fn($q) => $q ->where( fn($q) => $q ->where('faixa.inicio_ano', '<', $idade->y) ->orWhere( fn($q) => $q ->where('faixa.inicio_ano', '=', $idade->y) ->where('faixa.inicio_mes', '<', $idade->m) ) ->orWhere( fn($q) => $q ->where('faixa.inicio_ano', '=', $idade->y) ->where('faixa.inicio_mes', '=', $idade->m) ->where('faixa.inicio_dia', '<=', $idade->d) ) ) ->where( fn($q) => $q ->where('faixa.fim_ano', '>', $idade->y) ->orWhere( fn($q) => $q ->where('faixa.fim_ano', '=', $idade->y) ->where('faixa.fim_mes', '>', $idade->m) ) ->orWhere( fn($q) => $q ->where('faixa.fim_ano', '=', $idade->y) ->where('faixa.fim_mes', '=', $idade->m) ->where('faixa.fim_dia', '>=', $idade->d) ) ) ) ->get() ->keyBy(fn($r) => "{$r->vacina_id}_{$r->dose_id}"); } private static function getAplicacoes(Paciente $paciente): array { $aplicacoes = DB::table('imunizacao_registro_aplicacao as ira') ->select( [ 'ira.id', 'vacina.id as vacina_id', 'vacina.codigo as vacina_codigo', 'vacina.nome as vacina_nome', 'vacina.abreviacao as vacina_abreviacao', 'vacina.sigla as vacina_sigla', 'dose.id as dose_id', 'dose.nome as dose_nome', 'estrategia_reg.nome as estrategia_nome', 'ira.data_aplicacao', 'iev.lote', 'iev.data_validade_lote', 'produtor.nome as produtor_nome', 'unidade.cnes as unidade_cnes', 'unidade.nome_fantasia as unidade_nome', DB::raw("CASE WHEN infra.principal THEN unidade.nome_fantasia ELSE infra.nome END AS sala_vacinacao_nome"), 'aplicador_cidadao.nome as aplicador_nome', 'mun.nome as municipio_nome', 'est.uf as estado_uf' ] ) ->leftJoin('imunizacao_entrada_vacina as iev', 'iev.id', 'ira.entrada_vacina_id') ->leftJoin('imunizacao_entrada as entrada', 'entrada.id', 'iev.entrada_id') ->leftJoin('imunizacao_sala_vacinacao as sala', 'sala.id', 'entrada.sala_vacinacao_id') ->leftJoin('cadastro_infraestrutura as infra', 'infra.id', 'sala.infraestrutura_id') ->leftJoin('cadastro_unidade as unidade', 'unidade.id', 'infra.unidade_id') ->leftJoin('cadastro_endereco as end_infra', 'end_infra.id', 'infra.endereco_id') ->leftJoin('cadastro_logradouro as logr_infra', 'logr_infra.id', 'end_infra.logradouro_id') ->leftJoin('intranet.cadastro_municipio as mun', 'mun.id', 'logr_infra.municipio_id') ->leftJoin('intranet.cadastro_estado as est', 'est.id', 'mun.estado_id') ->leftJoin('cadastro_vacina as vacina', 'vacina.id', 'iev.vacina_id') ->leftJoin('imunizacao_produtor as produtor', 'produtor.id', 'iev.produtor_id') ->leftJoin('imunizacao_dose as dose', 'dose.id', 'ira.dose_id') ->leftJoin('imunizacao_estrategia as estrategia_reg', 'estrategia_reg.id', 'ira.estrategia_id') ->leftJoin('cadastro_usuario as aplicador', 'aplicador.id', 'ira.aplicador_id') ->leftJoin('cadastro_cidadao as aplicador_cidadao', 'aplicador_cidadao.id', 'aplicador.cidadao_id') ->where('ira.paciente_id', $paciente->id) ->get() ->map( fn($item) => [ 'id' => $item->id, 'tipo' => 'aplicacao', 'vacina' => [ 'id' => $item->vacina_id, 'nome' => $item->vacina_nome, 'abreviacao' => $item->vacina_abreviacao, 'sigla' => $item->vacina_sigla, 'is_covid' => in_array($item->vacina_codigo, self::VACINAS_COVID), ], 'dose' => [ 'id' => $item->dose_id, 'nome' => $item->dose_nome ], 'estrategia' => $item->estrategia_nome, 'data_aplicacao' => $item->data_aplicacao, 'lote' => $item->lote, 'data_validade_lote' => $item->data_validade_lote, 'fabricante' => $item->produtor_nome, 'cnes' => $item->unidade_cnes, 'unidade_saude' => $item->unidade_nome, 'sala_vacinacao' => $item->sala_vacinacao_nome, 'municipio' => $item->municipio_nome, 'uf' => $item->estado_uf, 'profissional' => $item->aplicador_nome ] ); $atualizacoes = DB::table('imunizacao_registro_atualizacao as ira') ->select( [ 'ira.id', 'vacina.id as vacina_id', 'vacina.codigo as vacina_codigo', 'vacina.nome as vacina_nome', 'vacina.abreviacao as vacina_abreviacao', 'vacina.sigla as vacina_sigla', 'dose.id as dose_id', 'dose.nome as dose_nome', 'estrategia_reg.nome as estrategia_nome', 'ira.data_atualizacao as data_aplicacao', 'ira.lote', 'unidade.cnes as unidade_cnes', 'unidade.nome_fantasia as unidade_nome', DB::raw("CASE WHEN infra.principal THEN unidade.nome_fantasia ELSE infra.nome END AS sala_vacinacao_nome"), 'aplicador_cidadao.nome as aplicador_nome', 'mun.nome as municipio_nome', 'est.uf as estado_uf' ] ) ->leftJoin('cadastro_vacina as vacina', 'vacina.id', 'ira.vacina_id') ->leftJoin('imunizacao_dose as dose', 'dose.id', 'ira.dose_id') ->leftJoin('imunizacao_estrategia as estrategia_reg', 'estrategia_reg.id', 'ira.estrategia_id') ->leftJoin('imunizacao_sala_vacinacao as sala', 'sala.id', 'ira.sala_vacinacao_id') ->leftJoin('cadastro_infraestrutura as infra', 'infra.id', 'sala.infraestrutura_id') ->leftJoin('cadastro_unidade as unidade', 'unidade.id', 'infra.unidade_id') ->leftJoin('cadastro_endereco as end_infra', 'end_infra.id', 'infra.endereco_id') ->leftJoin('cadastro_logradouro as logr_infra', 'logr_infra.id', 'end_infra.logradouro_id') ->leftJoin('intranet.cadastro_municipio as mun', 'mun.id', 'logr_infra.municipio_id') ->leftJoin('intranet.cadastro_estado as est', 'est.id', 'mun.estado_id') ->leftJoin('cadastro_usuario as aplicador', 'aplicador.id', 'ira.aplicador_id') ->leftJoin('cadastro_cidadao as aplicador_cidadao', 'aplicador_cidadao.id', 'aplicador.cidadao_id') ->where('ira.paciente_id', $paciente->id) ->get() ->map( fn($item) => [ 'id' => $item->id, 'tipo' => 'atualizacao', 'vacina' => [ 'id' => $item->vacina_id, 'nome' => $item->vacina_nome, 'abreviacao' => $item->vacina_abreviacao, 'sigla' => $item->vacina_sigla, 'is_covid' => in_array($item->vacina_codigo, self::VACINAS_COVID), ], 'dose' => [ 'id' => $item->dose_id, 'nome' => $item->dose_nome ], 'estrategia' => $item->estrategia_nome, 'data_aplicacao' => $item->data_aplicacao, 'lote' => $item->lote, 'data_validade_lote' => null, 'fabricante' => null, 'cnes' => $item->unidade_cnes, 'unidade_saude' => $item->unidade_nome, 'sala_vacinacao' => $item->sala_vacinacao_nome, 'municipio' => $item->municipio_nome, 'uf' => $item->estado_uf, 'profissional' => $item->aplicador_nome, ] ); return $aplicacoes ->merge($atualizacoes) ->sortByDesc('data_aplicacao') ->values() ->toArray(); } private static function getCalendarioVacinal(Paciente $paciente, Collection $regrasAtuais): array { if ($regrasAtuais->isEmpty()) { return []; } $hoje = Carbon::now(); $aplicacoes = DB::table('imunizacao_registro_aplicacao as ira') ->join('imunizacao_entrada_vacina as iev', 'iev.id', 'ira.entrada_vacina_id') ->where('ira.paciente_id', $paciente->id) ->select( [ 'iev.vacina_id', 'ira.dose_id', 'ira.data_aplicacao' ] ) ->get() ->merge( DB::table('imunizacao_registro_atualizacao as ira') ->where('ira.paciente_id', $paciente->id) ->select( [ 'ira.vacina_id', 'ira.dose_id', 'ira.data_atualizacao as data_aplicacao' ] ) ->get() ) ->keyBy(fn($a) => "{$a->vacina_id}_{$a->dose_id}"); $aprazamentos = DB::table('imunizacao_registro_aprazamento') ->where('paciente_id', $paciente->id) ->whereNull('registro_aplicacao_id') ->select( [ 'vacina_id', 'dose_id', 'data_aprazamento' ] ) ->get() ->keyBy(fn($a) => "{$a->vacina_id}_{$a->dose_id}"); return $regrasAtuais->map( function ($regra) use ($aplicacoes, $aprazamentos, $hoje) { $key = "{$regra->vacina_id}_{$regra->dose_id}"; $aplicacao = $aplicacoes->get($key); $aprazamento = $aprazamentos->get($key); $status = self::calcularStatus($aplicacao, $aprazamento, $hoje); return [ 'vacina' => [ 'id' => $regra->vacina_id, 'nome' => $regra->vacina_nome, 'abreviacao' => $regra->vacina_abreviacao, 'sigla' => $regra->vacina_sigla, 'is_covid' => in_array($regra->vacina_codigo, self::VACINAS_COVID), ], 'dose' => [ 'id' => $regra->dose_id, 'nome' => $regra->dose_nome, ], 'faixa_etaria' => self::formatarFaixaEtaria($regra), 'estrategia' => $regra->estrategia_nome, 'data_aprazamento' => $aprazamento ? $aprazamento->data_aprazamento : null, 'data_aplicacao' => $aplicacao ? $aplicacao->data_aplicacao : null, 'status' => $status, 'alerta' => in_array($status, ['em_atraso', 'proximo_do_prazo']), ]; } )->values()->toArray(); } private static function calcularStatus(?object $aplicacao, ?object $aprazamento, Carbon $hoje): string { if ($aprazamento) { $dataAprazamento = Carbon::parse($aprazamento->data_aprazamento)->startOfDay(); $hoje = $hoje->copy()->startOfDay(); if ($dataAprazamento->lt($hoje)) { return 'em_atraso'; } if ($dataAprazamento->lte($hoje->addDays(Prazo::DIAS_PROXIMO_DO_PRAZO))) { return 'proximo_do_prazo'; } return 'em_dia'; } if ($aplicacao) { return 'em_dia'; } return 'sem_registro'; } private static function getMensagemOrientativa(array $calendario): ?string { $statuses = array_column($calendario, 'status'); if (in_array('em_atraso', $statuses)) { return Mensagem::CARTEIRA_EM_ATRASO; } if (in_array('proximo_do_prazo', $statuses)) { return Mensagem::CARTEIRA_PROXIMO_PRAZO; } if (in_array('sem_registro', $statuses)) { return Mensagem::CARTEIRA_SEM_REGISTRO; } return null; } private static function formatarFaixaEtaria(object $regra): string { $inicio = self::formatarIdade($regra->inicio_ano, $regra->inicio_mes, $regra->inicio_dia); $fim = self::formatarIdade($regra->fim_ano, $regra->fim_mes, $regra->fim_dia); return "{$inicio} a {$fim}"; } private static function formatarIdade(int $anos, int $meses, int $dias): string { $partes = []; if ($anos > 0) { $partes[] = $anos . ($anos === 1 ? ' ano' : ' anos'); } if ($meses > 0) { $partes[] = $meses . ($meses === 1 ? ' mês' : ' meses'); } if ($dias > 0) { $partes[] = $dias . ($dias === 1 ? ' dia' : ' dias'); } return implode(' e ', $partes) ?: '0 dias'; } }