init commit
All checks were successful
build-api-image / build (push) Successful in 51s

This commit is contained in:
Antonio Lopes dos Santos
2026-08-04 16:52:02 -03:00
commit afec302c3e
11594 changed files with 1636728 additions and 0 deletions

View File

@@ -0,0 +1,456 @@
<?php
namespace App\Services\Mobile\ConectaCidadao\CarteiraVacinacao;
use App\Enums\Cadastro\Vacina as VacinaEnum;
use App\Enums\Imunizacao\Estrategia;
use App\Enums\Mobile\ConectaCidadao\CarteiraVacinacao\Mensagem;
use App\Enums\Mobile\ConectaCidadao\CarteiraVacinacao\Prazo;
use App\Models\Cadastro\SujeitoAtencao\Paciente;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class CarteiraVacinacaoService extends Service
{
private const VACINAS_COVID = [
VacinaEnum::COVID_19_ASTRAZENECA_FIOCRUZ,
VacinaEnum::COVID_19_SINOVAC_BUTANTAN,
VacinaEnum::COVID_19_PFIZER,
VacinaEnum::COVID_19_JANSSEN,
VacinaEnum::COVID_19_ASTRAZENECA,
VacinaEnum::COVID_19_GAMALEYA,
VacinaEnum::COVID_19_BHARAT,
VacinaEnum::COVID_19_MODERNA_SPIKEVAX,
VacinaEnum::COVID_19_SINOVAC_CORONAVAC,
VacinaEnum::COVID_19_PFIZER_COMIRNATY_PEDIATRICA,
VacinaEnum::COVID_19_PFIZER_COMIRNATY_PEDIATRICA_MENOR_DE_5_ANOS,
VacinaEnum::COVID_19_PFIZER_COMIRNATYBIVALENTE,
];
public static function vacinas(): array
{
$paciente = auth('mobile')->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';
}
}