Files
rkm-conectasus-ci-sandbox/api/app/Services/Ambulatorio/AgendamentoRetroativoService.php
Antonio Lopes dos Santos afec302c3e
All checks were successful
build-api-image / build (push) Successful in 51s
init commit
2026-08-04 16:52:02 -03:00

1828 lines
73 KiB
PHP

<?php
namespace App\Services\Ambulatorio;
use App\Enums\Administracao\Modulo;
use App\Enums\Ambulatorio\AgendamentoStatus as AgendamentoStatusEnum;
use App\Enums\Ambulatorio\AgendamentoTipo as AgendamentoTipoEnum;
use App\Enums\Ambulatorio\JornadaTipo;
use App\Enums\Cadastro\SujeitoAtencao\Classificacao;
use App\Enums\Cadastro\SujeitoAtencao\Subclassificacao;
use App\Enums\Regulacao\StatusTipo as RegulacaoStatusTipo;
use App\Exceptions\Ambulatorio\AgendamentoConflitanteException;
use App\Exceptions\Ambulatorio\AgendamentoNaoPermitidoJornadaGrupoException;
use App\Exceptions\Ambulatorio\NaoPodeExcluirAgendamentoException;
use App\Http\Controllers\Cadastro\SujeitoAtencao\PacienteController;
use App\Models\Ambulatorio\Agendamento;
use App\Models\Ambulatorio\AgendamentoStatus;
use App\Models\Ambulatorio\AgendamentoTipo;
use App\Models\Ambulatorio\DemandaEspontanea;
use App\Models\Ambulatorio\Jornada;
use App\Models\Ambulatorio\JornadaBloqueio;
use App\Models\Ambulatorio\ParametrizacaoAgendamento;
use App\Models\Ambulatorio\ParametrizacaoInfraestruturaEspecialidade;
use App\Models\Cadastro\Especialidade;
use App\Models\Cadastro\Estabelecimento\Infraestrutura;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Feriado\Feriado;
use App\Models\Cadastro\Parametrizacao\Parametrizacao;
use App\Models\Cadastro\SujeitoAtencao\Paciente;
use App\Models\Cadastro\SujeitoAtencao\Usuario;
use App\Models\Geral\DiaSemana;
use App\Models\Sigtap\Procedimento;
use App\Rules\Cns;
use App\Services\Ambulatorio\SupervisorService;
use App\Services\Integracao\CnsService;
use App\Services\Regulacao\SolicitacaoService as RegulacaoSolicitacaoService;
use App\Services\Service;
use App\Services\Sigtap\ProcedimentoValidationService;
use App\Utils\DataUtil;
use App\Utils\MaskUtil;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
class AgendamentoRetroativoService extends Service
{
public static function datatable()
{
$parametrizacao = Parametrizacao::first();
$quantidadeDias = $parametrizacao->cadastro_paciente_desatualizado_quantidade_dias ?? 0;
$provisorioBloqueado = $parametrizacao->cadastro_paciente_provisorio_bloqueado ?? false;
$provisorioQuantidadeDias = $parametrizacao->cadastro_paciente_provisorio_quantidade_dias ?? 0;
$pacientes = DB::table('cadastro_paciente as paciente')
->leftJoin(
'cadastro_cidadao as cidadao',
'cidadao.id',
'paciente.cidadao_id'
)
->leftJoin(
'cadastro_domicilio as domicilio',
'domicilio.id',
'cidadao.domicilio_id'
)
->leftJoin(
'cadastro_endereco as endereco',
'endereco.id',
'domicilio.endereco_id'
)
->leftJoin(
'cadastro_logradouro as logradouro',
'logradouro.id',
'endereco.logradouro_id'
)
->leftJoin(
'intranet.cadastro_municipio as municipio',
'municipio.id',
'logradouro.municipio_id'
)
->leftJoin(
'intranet.cadastro_estado as estado',
'estado.id',
'municipio.estado_id'
)
->leftJoin('cadastro_obito as obito', function ($join) {
$join->on('obito.cidadao_id', '=', 'cidadao.id')
->whereNull('obito.deleted_at');
})
->whereNull('paciente.deleted_at')
->whereNull('paciente.sequencial_desconhecido_em')
->whereNull('obito.id')
->select(DB::raw("
paciente.id,
paciente.classificacao_id,
cidadao.nome,
cidadao.nome_social,
cidadao.preferencia_nome_id,
DATE_FORMAT(cidadao.data_nascimento, '%d/%m/%Y') as data_nascimento,
cidadao.nome_mae,
LPAD(paciente.prontuario, 7, '0') as prontuario,
CONCAT(
SUBSTR(cidadao.cpf, 1, 3),
'.',
SUBSTR(cidadao.cpf, 4, 3),
'.',
SUBSTR(cidadao.cpf, 7, 3),
'-',
SUBSTR(cidadao.cpf, 10, 2)
) as cpf,
CONCAT(
SUBSTR(cidadao.cns, 1, 3),
' ',
SUBSTR(cidadao.cns, 4, 4),
' ',
SUBSTR(cidadao.cns, 8, 4),
' ',
SUBSTR(cidadao.cns, 12, 4)
) as cns,
CONCAT(municipio.nome, ' / ', estado.uf) as municipio_uf,
IF(paciente.validade_fim IS NULL,
'INDETERMINADO',
DATE_FORMAT(paciente.validade_fim, '%d/%m/%Y')
) as validade_fim,
CASE
WHEN paciente.updated_at IS NULL AND cidadao.updated_at IS NULL THEN 1
WHEN paciente.updated_at IS NOT NULL AND (cidadao.updated_at IS NULL OR paciente.updated_at > cidadao.updated_at) THEN
CASE
WHEN " . ($quantidadeDias > 0
? "DATE_ADD(paciente.updated_at, INTERVAL " . $quantidadeDias . " DAY) < NOW()"
: "false") . "
THEN DATEDIFF(NOW(), DATE_ADD(paciente.updated_at, INTERVAL " . $quantidadeDias . " DAY))
ELSE 0
END
WHEN cidadao.updated_at IS NOT NULL AND (paciente.updated_at IS NULL OR cidadao.updated_at > paciente.updated_at) THEN
CASE
WHEN " . ($quantidadeDias > 0
? "DATE_ADD(cidadao.updated_at, INTERVAL " . $quantidadeDias . " DAY) < NOW()"
: "false") . "
THEN DATEDIFF(NOW(), DATE_ADD(cidadao.updated_at, INTERVAL " . $quantidadeDias . " DAY))
ELSE 0
END
ELSE 0
END as dias_cadastro_desatualizado
"));
if (!DataUtil::isStringTrue(request()->with_paciente_bloqueado)) {
$pacientes->where(function ($query) {
$query
->where('paciente.bloqueado', false)
->orWhereNull('paciente.bloqueado');
});
}
if (!DataUtil::isStringTrue(request()->with_paciente_provisorio) && $provisorioBloqueado) {
$pacientes->where(function ($query) use ($provisorioQuantidadeDias) {
$query->where('paciente.subclassificacao_id', '!=', Subclassificacao::TEMPORARIO)
->orWhere(function ($query) use ($provisorioQuantidadeDias) {
$query->where('paciente.subclassificacao_id', Subclassificacao::TEMPORARIO)
->where(function ($query) use ($provisorioQuantidadeDias) {
$query->where(function ($query) {
$query->whereNull('paciente.validade_inicio')
->orWhereDate('paciente.validade_inicio', '<=', Carbon::now()->format('Y-m-d'));
});
$query->where(function ($query) use ($provisorioQuantidadeDias) {
$query->whereNull('paciente.validade_fim')
->orWhere(function ($query) use ($provisorioQuantidadeDias) {
if (!is_null($provisorioQuantidadeDias) && $provisorioQuantidadeDias > 0) {
$query->whereDate('paciente.validade_fim', '>=', Carbon::now()->format('Y-m-d'))
->orWhereDate('paciente.validade_fim', '>=', Carbon::now()->subDays($provisorioQuantidadeDias)->format('Y-m-d'));
} else {
$query->whereDate('paciente.validade_fim', '>=', Carbon::now()->format('Y-m-d'));
}
});
});
});
})
->orWhereNull('paciente.subclassificacao_id');
});
}
return $pacientes;
}
public static function index()
{
$agendamentos = DB::table('ambulatorio_agendamento as agendamento')
->join(
'ambulatorio_agendamento_status as status',
'status.id',
'agendamento.status_id'
)
->join(
'ambulatorio_agendamento_tipo as tipo',
'tipo.id',
'agendamento.tipo_id'
)
->join(
'ambulatorio_jornada as jornada',
'jornada.id',
'agendamento.jornada_id'
)
->join(
'cadastro_lotacao as lotacao',
'lotacao.id',
'jornada.lotacao_id'
)
->join(
'cadastro_infraestrutura as infraestrutura',
'infraestrutura.id',
'lotacao.infraestrutura_id'
)
->join(
'cadastro_unidade as unidade',
'unidade.id',
'infraestrutura.unidade_id'
)
->join(
'cadastro_usuario as usuario',
'usuario.id',
'lotacao.usuario_id'
)
->join(
'cadastro_cidadao as cidadao',
'cidadao.id',
'usuario.cidadao_id'
)
->join(
'sigtap.ocupacao as ocupacao',
'ocupacao.id',
'lotacao.ocupacao_id'
)
->join(
'cadastro_especialidade as especialidade',
'especialidade.id',
'jornada.especialidade_id'
)
->join(
'cadastro_lotacao as lotacao_agendamento',
'lotacao_agendamento.id',
'agendamento.created_lotacao_id'
)
->join(
'cadastro_usuario as usuario_agendamento',
'usuario_agendamento.id',
'lotacao_agendamento.usuario_id'
)
->join(
'cadastro_cidadao as cidadao_agendamento',
'cidadao_agendamento.id',
'usuario_agendamento.cidadao_id'
)
->when(request()->paciente_id, fn ($q, $id) => $q->where('agendamento.paciente_id', $id))
->whereDate('jornada.data', '<', Carbon::today())
->when(request()->periodo, fn ($q, $periodo) => $q
->whereBetween('jornada.data', [
Carbon::createFromFormat('d/m/Y', $periodo['start'])->startOfDay(),
Carbon::createFromFormat('d/m/Y', $periodo['end'])->endOfDay(),
])
)
->when(request()->inicio && request()->fim, fn ($q) => $q
->whereBetween('agendamento.horario', [request()->inicio, request()->fim])
)
->when(request()->unidade_id, fn ($q, $id) => $q->where('unidade.id', $id))
->when(request()->infraestrutura_id, fn ($q, $id) => $q->where('infraestrutura.id', $id))
->when(request()->ocupacao_id, fn ($q, $id) => $q->where('ocupacao.id', $id))
->when(request()->especialidade_id, fn ($q, $id) => $q->where('especialidade.id', $id))
->when(request()->usuario_id, fn ($q, $id) => $q->where('usuario.id', $id))
->when(request()->tipo_id, fn ($q, $id) => $q->where('tipo.id', $id))
->when(request()->status_id, fn ($q, $id) => $q->where('status.id', $id))
->select(DB::raw("
agendamento.id,
jornada.data,
DATE_FORMAT(agendamento.horario, '%H:%i') as horario,
unidade.nome_fantasia as unidade,
COALESCE(infraestrutura.nome, unidade.nome_fantasia) as infraestrutura,
cidadao.nome as usuario,
CONCAT(ocupacao.codigo, ' - ', ocupacao.nome) as ocupacao,
especialidade.nome as especialidade,
tipo.nome as tipo,
status.id as status_id,
status.nome as status,
cidadao_agendamento.nome as usuario_agendamento,
DATE_FORMAT(agendamento.created_at, '%d/%m/%Y às %H:%i') as data_hora_agendamento
"))
->addSelect([
'has_atendimento' => function ($query) {
$query->select(DB::raw(1))
->from('ambulatorio_atendimento as atendimento')
->whereColumn('atendimento.agendamento_id', 'agendamento.id')
->limit(1);
}
])
->get();
$agendamentos->each(function ($agendamento) {
$agendamento->permite_exclusao = !$agendamento->has_atendimento
&& $agendamento->status_id === AgendamentoStatusEnum::AGENDADO;
unset($agendamento->status_id, $agendamento->has_atendimento);
});
return $agendamentos;
}
public static function create($pacienteId)
{
$paciente = Paciente::findOrFail($pacienteId);
switch (request()->origem) {
case 'busca': {
return self::getDadosCreateBusca($paciente);
}
case 'cadastro': {
return self::getDadosCreateCadastro($paciente);
}
}
}
private static function getDadosCreateBusca($paciente)
{
$municipioResidencia = $paciente->cidadao->domicilio->endereco->logradouro->municipio ?? null;
$parametrizacao = ParametrizacaoAgendamento::first();
$cadastroParametrizacao = Parametrizacao::first();
return [
'additionals' => [
'data_ontem' => Carbon::yesterday()->format('d/m/Y'),
'avisa_cns_provisorio' => self::avisaCnsProvisorio($parametrizacao, $paciente),
'cadastro_paciente_vencido' => ($parametrizacao->bloqueia_paciente_temporario ?? false)
&& PacienteController::isCadastroPacienteVencido($paciente->id),
'cns_valido' => Cns::isValid($paciente->cidadao->cns),
'avisa_cns_temporario_invalido' => $cadastroParametrizacao->exibe_alerta_paciente_cns_temporario_invalido ?? false,
'permissoes_atualizacao_cadastro_paciente' => self::getPermissoesAtualizacaoCadastroPaciente(),
],
'form' => [
'paciente' => [
'cidadao_id' => $paciente->cidadao->id,
'nome' => $paciente->cidadao->nome,
'nome_social' => $paciente->cidadao->nome_social,
'preferencia_nome_id' => $paciente->cidadao->preferencia_nome_id,
'data_nascimento' => is_null($paciente->cidadao->data_nascimento)
? null
: (new Carbon($paciente->cidadao->data_nascimento))->format('d/m/Y'),
'idade' => $paciente->cidadao->idade_formatada,
'nome_mae' => $paciente->cidadao->nome_mae,
'prontuario' => $paciente->prontuario,
'cpf' => MaskUtil::getCpfMasked($paciente->cidadao->cpf),
'cns' => MaskUtil::getCnsMasked($paciente->cidadao->cns),
'municipio_uf' => is_null($municipioResidencia)
? null
: "{$municipioResidencia->nome} / {$municipioResidencia->estado->uf}",
'telefone' => MaskUtil::getPhoneMasked($paciente->cidadao->telefone_principal->numero ?? null),
'unidade_referencia' => $paciente->unidade->nome_fantasia ?? null,
'classificacao_id' => $paciente->classificacao_id,
'subclassificacao_id' => $paciente->subclassificacao_id,
'classificacao' => $paciente->classificacao->descricao ?? null,
'validade_fim' => is_null($paciente->validade_fim)
? 'INDETERMINADO'
: (new Carbon($paciente->validade_fim))->format('d/m/Y')
],
'especialidades_permitem_nao_municipe' => self::getEspecialidadesPermitemNaoMunicipe($paciente->id),
'unidades' => [],
'infraestruturas' => [],
'ocupacoes' => [],
'especialidades' => [],
'usuarios' => [],
'tipos' => [],
'status' => [],
],
'model' => [
'periodo' => [
'start' => null,
'end' => null,
],
'inicio' => null,
'fim' => null,
'unidade_id' => null,
'infraestrutura_id' => null,
'ocupacao_id' => null,
'especialidade_id' => null,
'usuario_id' => null,
'tipo_id' => null,
'status_id' => null,
]
];
}
private static function avisaCnsProvisorio($parametrizacao, $paciente)
{
return $parametrizacao->avisa_cns_provisorio
&& Str::startsWith($paciente->cidadao->cns, [5, 7, 8, 9]);
}
private static function getEspecialidadesPermitemNaoMunicipe($pacienteId)
{
return Especialidade::where('permite_agendamento_nao_municipe', true)
->where(fn ($q) => self::setCadastroWhereEspecialidadePaciente($q, $pacienteId))
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereNull('situacao_id')
->whereDate('data', '<', Carbon::now())
)
->orderBy('nome')
->get(['id', 'nome']);
}
private static function getDadosCreateCadastro($paciente)
{
$params = (object) [
'paciente_id' => $paciente->id,
'paciente_nao_municipe' => $paciente->classificacao_id !== Classificacao::MUNICIPE,
];
return [
'additionals' => self::getAdditionalsCadastro(),
'form' => [
'feriados' => self::getFeriados(),
'datas_com_agendamento' => self::getCadastroDatasComAgendamento($params),
'unidades' => self::getCadastroUnidades($params),
'infraestruturas' => [],
'ocupacoes' => [],
'especialidades' => [],
'usuarios' => [],
'tipos' => [],
'datas' => [],
'datas_bloqueadas' => [],
'horarios' => [],
'horarios_com_situacao' => [],
'quantidade_demanda_espontanea' => null,
],
'model' => [
'unidade_id' => null,
'infraestrutura_id' => null,
'ocupacao_id' => null,
'especialidade_id' => null,
'usuario_id' => null,
'tipo_id' => null,
'demanda_espontanea_observa_vaga_atendimento' => null,
'data' => null,
'jornada_id' => null,
'horario' => null,
'observacao' => null,
'motivo_agendamento_excedente' => null,
],
];
}
public static function edit($id)
{
$agendamento = Agendamento::findOrFail($id);
$params = (object) [
'paciente_id' => $agendamento->paciente_id,
'paciente_nao_municipe' => $agendamento->paciente->classificacao_id !== Classificacao::MUNICIPE,
'unidade_id' => $agendamento->jornada->lotacao->infraestrutura->unidade_id,
'infraestrutura_id' => $agendamento->jornada->lotacao->infraestrutura_id,
'ocupacao_id' => $agendamento->jornada->lotacao->ocupacao_id,
'especialidade_id' => $agendamento->jornada->especialidade_id,
'usuario_id' => $agendamento->jornada->lotacao->usuario_id,
'tipo_id' => $agendamento->tipo_id,
'data' => $agendamento->jornada->data->format('d/m/Y'),
];
return [
'additionals' => self::getAdditionalsCadastro(),
'form' => [
'feriados' => self::getFeriados(),
'datas_com_agendamento' => self::getCadastroDatasComAgendamento($params),
'unidades' => self::getCadastroUnidades($params),
'infraestruturas' => self::getCadastroInfraestruturas($params),
'ocupacoes' => self::getCadastroOcupacoes($params, $agendamento->jornada->lotacao->ocupacao_id),
'especialidades' => self::getCadastroEspecialidades($params, $agendamento->jornada->especialidade_id),
'usuarios' => self::getCadastroUsuarios($params),
'tipos' => self::getCadastroTipos($params),
'datas' => self::getCadastroDatas($params),
'datas_bloqueadas' => self::getCadastroDatasBloqueadas($params),
'horarios' => self::getCadastroHorarios($params),
'horarios_com_situacao' => self::getCadastroHorariosComSituacao($params),
'quantidade_demanda_espontanea' => self::getQuantidadeDemandaEspontanea($params),
],
'model' => [
'unidade_id' => $agendamento->jornada->lotacao->infraestrutura->unidade_id,
'infraestrutura_id' => $agendamento->jornada->lotacao->infraestrutura_id,
'ocupacao_id' => $agendamento->jornada->lotacao->ocupacao_id,
'especialidade_id' => $agendamento->jornada->especialidade_id,
'usuario_id' => $agendamento->jornada->lotacao->usuario_id,
'tipo_id' => $agendamento->tipo_id,
'demanda_espontanea_observa_vaga_atendimento' => self::getDemandaEspontaneaObservaVagaAtendimentoAgendamento($agendamento),
'data' => $agendamento->jornada->data->format('d/m/Y'),
'jornada_id' => $agendamento->jornada->id,
'horario' => $agendamento->horario->format('H:i'),
'observacao' => $agendamento->observacao,
'motivo_agendamento_excedente' => $agendamento->motivo_agendamento_excedente,
],
];
}
private static function getAdditionalsCadastro()
{
return [
'obriga_motivo_agendamento_excedente' => ParametrizacaoAgendamento::first()
->obriga_motivo_agendamento_excedente ?? false,
];
}
private static function getFeriados()
{
return Feriado::whereHas('modulos', fn ($q) => $q
->where('identificador', Modulo::AMBULATORIO)
)
->orderBy('data')
->get()
->map(fn ($feriado) => (object) [
'data' => (new Carbon($feriado->data))->format('d/m/Y'),
'tipo_descricao' => $feriado->tipo->descricao,
'observacao' => $feriado->observacao,
]);
}
private static function getCadastroDatasComAgendamento($params)
{
$agendamentosAmbulatorio = Agendamento::where('paciente_id', $params->paciente_id)
->where('status_id', AgendamentoStatusEnum::AGENDADO)
->get()
->map(fn ($agendamento) => [
'id' => $agendamento->id,
'data' => $agendamento->jornada->data->format('d/m/Y'),
'horario' => $agendamento->horario->format('H:i'),
'tipo_nome' => Str::lower($agendamento->tipo->nome),
'unidade_nome_fantasia' => $agendamento->jornada->lotacao->infraestrutura->unidade->nome_fantasia,
'infraestrutura_nome' => $agendamento->jornada->lotacao->infraestrutura->nome,
'especialidade_id' => $agendamento->jornada->especialidade_id,
'especialidade_nome' => $agendamento->jornada->especialidade->nome,
]);
return [
'ambulatorio' => $agendamentosAmbulatorio,
];
}
public static function list()
{
switch (request()->origem) {
case 'busca': {
return self::getDadosListBusca();
}
case 'cadastro': {
return self::getDadosListCadastro();
}
}
}
private static function getDadosListBusca()
{
$params = (object) request()->all();
$params->periodo = [
Carbon::createFromFormat('d/m/Y', $params->periodo['start'])->startOfDay(),
Carbon::createFromFormat('d/m/Y', $params->periodo['end'])->endOfDay(),
];
switch (request()->listar) {
case 'unidades': {
return [
'unidades' => self::getBuscaUnidades($params),
'infraestruturas' => [],
'ocupacoes' => self::getBuscaOcupacoes($params),
'especialidades' => [],
'usuarios' => self::getBuscaUsuarios($params),
'tipos' => self::getBuscaTipos($params),
'status' => self::getBuscaStatus($params),
];
}
case 'infraestruturas': {
return [
'infraestruturas' => self::getBuscaInfraestruturas($params),
'ocupacoes' => self::getBuscaOcupacoes($params),
'especialidades' => [],
'usuarios' => self::getBuscaUsuarios($params),
'tipos' => self::getBuscaTipos($params),
'status' => self::getBuscaStatus($params),
];
return self::getBuscaInfraestruturas($params);
}
case 'ocupacoes': {
return [
'ocupacoes' => self::getBuscaOcupacoes($params),
'especialidades' => [],
'usuarios' => self::getBuscaUsuarios($params),
'tipos' => self::getBuscaTipos($params),
'status' => self::getBuscaStatus($params),
];
}
case 'especialidades': {
return [
'especialidades' => self::getBuscaEspecialidades($params),
'usuarios' => self::getBuscaUsuarios($params),
'tipos' => self::getBuscaTipos($params),
'status' => self::getBuscaStatus($params),
];
}
case 'usuarios': {
return [
'usuarios' => self::getBuscaUsuarios($params),
'tipos' => self::getBuscaTipos($params),
'status' => self::getBuscaStatus($params),
];
}
case 'tipos': {
return [
'tipos' => self::getBuscaTipos($params),
'status' => self::getBuscaStatus($params),
];
}
case 'status': {
return [
'status' => self::getBuscaStatus($params),
];
}
}
}
private static function getBuscaUnidades($params)
{
return Unidade::whereHas('infraestruturas', fn ($q) => $q
->whereHas('lotacoes', fn ($q) => $q
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereDate('data', '<', Carbon::today())
->whereBetween('data', $params->periodo)
->whereHas('agendamentos', fn ($q) =>
self::setBuscaWhereAgendamento($q, $params)
)
)
)
)
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']);
}
private static function getBuscaInfraestruturas($params)
{
return Infraestrutura::setEagerLoads([])
->where('unidade_id', $params->unidade_id)
->whereHas('lotacoes', fn ($q) => $q
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereDate('data', '<', Carbon::today())
->whereBetween('data', $params->periodo)
->whereHas('agendamentos', fn ($q) =>
self::setBuscaWhereAgendamento($q, $params)
)
)
)
->get(['id', 'nome', 'principal', 'unidade_id'])
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome
])
->sortBy('nome')
->values();
}
private static function getBuscaOcupacoes($params)
{
return DB::table('sigtap.ocupacao as ocupacao')
->whereExists(function ($query) use ($params) {
$query->select(DB::raw(1))
->from('cadastro_lotacao as lotacao')
->join(
'cadastro_infraestrutura as infraestrutura',
'infraestrutura.id',
'lotacao.infraestrutura_id'
)
->whereColumn('lotacao.ocupacao_id', 'ocupacao.id')
->when($params->infraestrutura_id ?? null,
fn ($q, $id) => $q->where('lotacao.infraestrutura_id', $id),
fn ($q) => $q->when($params->unidade_id ?? null, fn ($q, $id) => $q
->where('infraestrutura.unidade_id', $id)
)
)
->whereExists(function ($query) use ($params) {
$query->select(DB::raw(1))
->from('ambulatorio_agendamento as agendamento')
->join(
'ambulatorio_jornada as jornada',
'jornada.id',
'agendamento.jornada_id'
)
->whereColumn('jornada.lotacao_id', 'lotacao.id')
->whereDate('jornada.data', '<', Carbon::today())
->whereBetween('jornada.data', $params->periodo)
->where(fn ($q) => self::setBuscaWhereAgendamento($q, $params, 'agendamento'));
});
})
->select(DB::raw("
ocupacao.id,
CONCAT(ocupacao.codigo, ' - ', ocupacao.nome) as descricao
"))
->orderByRaw("CONCAT(ocupacao.codigo, ' - ', ocupacao.nome)")
->get();
}
private static function getBuscaEspecialidades($params)
{
return Especialidade::whereHas('ambulatorioJornadas', fn ($q) => $q
->whereDate('data', '<', Carbon::today())
->whereBetween('data', $params->periodo)
->whereHas('lotacao', fn ($q) => $q
->when($params->infraestrutura_id ?? null,
fn ($q, $id) => $q->where('infraestrutura_id', $id),
fn ($q) => $q->when($params->unidade_id ?? null, fn ($q, $id) => $q
->whereHas('infraestrutura', fn ($q) => $q->where('unidade_id', $id))
)
)
->where('ocupacao_id', $params->ocupacao_id)
)
->whereHas('agendamentos', fn ($q) =>
self::setBuscaWhereAgendamento($q, $params)
)
)
->orderBy('nome')
->get(['id', 'nome']);
}
private static function getBuscaUsuarios($params)
{
return Usuario::setEagerLoads([])
->whereHas('lotacoes', fn ($q) => $q
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereDate('data', '<', Carbon::today())
->whereBetween('data', $params->periodo)
->whereHas('agendamentos', fn ($q) =>
self::setBuscaWhereAgendamento($q, $params)
)
->when($params->especialidade_id ?? null, fn ($q, $id) => $q->where('especialidade_id', $id))
)
->when($params->infraestrutura_id ?? null,
fn ($q, $id) => $q->where('infraestrutura_id', $id),
fn ($q) => $q->when($params->unidade_id ?? null, fn ($q, $id) => $q
->whereHas('infraestrutura', fn ($q) => $q->where('unidade_id', $id))
)
)
->when($params->ocupacao_id ?? null, fn ($q, $id) => $q->where('ocupacao_id', $id))
)
->get(['id', 'cidadao_id'])
->map(fn ($usuario) => [
'id' => $usuario->id,
'nome' => $usuario->cidadao()->setEagerLoads([])->first(['nome'])->nome,
])
->sortBy('nome')
->values();
}
private static function getBuscaTipos($params)
{
return AgendamentoTipo::whereHas('agendamentos', fn ($q) =>
self::setBuscaWhereAgendamento($q, $params)
->whereHas('jornada', fn ($q) => $q
->whereDate('data', '<', Carbon::today())
->whereBetween('data', $params->periodo)
->whereHas('lotacao', fn ($q) => $q
->when($params->infraestrutura_id ?? null,
fn ($q, $id) => $q->where('infraestrutura_id', $id),
fn ($q) => $q->when($params->unidade_id ?? null, fn ($q, $id) => $q
->whereHas('infraestrutura', fn ($q) => $q->where('unidade_id', $id))
)
)
->when($params->usuario_id ?? null, fn ($q, $id) => $q->where('usuario_id', $id))
->when($params->ocupacao_id ?? null, fn ($q, $id) => $q->where('ocupacao_id', $id))
)
->when($params->especialidade_id ?? null, fn ($q, $id) => $q->where('especialidade_id', $id))
)
)
->orderBy('nome')
->get(['id', 'nome']);
}
private static function getBuscaStatus($params)
{
return AgendamentoStatus::whereHas('agendamentos', fn ($q) =>
self::setBuscaWhereAgendamento($q, $params)
->when($params->tipo_id ?? null, fn ($q, $id) => $q->where('tipo_id', $id))
->whereHas('jornada', fn ($q) => $q
->whereDate('data', '<', Carbon::today())
->whereBetween('data', $params->periodo)
->whereHas('lotacao', fn ($q) => $q
->when($params->infraestrutura_id ?? null,
fn ($q, $id) => $q->where('infraestrutura_id', $id),
fn ($q) => $q->when($params->unidade_id ?? null, fn ($q, $id) => $q
->whereHas('infraestrutura', fn ($q) => $q->where('unidade_id', $id))
)
)
->when($params->usuario_id ?? null, fn ($q, $id) => $q->where('usuario_id', $id))
->when($params->ocupacao_id ?? null, fn ($q, $id) => $q->where('ocupacao_id', $id))
)
->when($params->especialidade_id ?? null, fn ($q, $id) => $q->where('especialidade_id', $id))
)
)
->orderBy('nome')
->get(['id', 'nome']);
}
private static function setBuscaWhereAgendamento($query, $params, $tableAlias = '')
{
if (!empty($tableAlias)) {
$tableAlias .= '.';
}
return $query->where("{$tableAlias}paciente_id", $params->paciente_id)
->when(!is_null($params->inicio ?? null) && !is_null($params->fim ?? null), fn ($q) => $q
->whereBetween("{$tableAlias}horario", [$params->inicio, $params->fim])
);
}
private static function getDadosListCadastro()
{
$params = (object) request()->all();
$paciente = Paciente::setEagerLoads([])->where('id', $params->paciente_id)->first();
$params->paciente_nao_municipe = $paciente->classificacao_id !== Classificacao::MUNICIPE;
switch (request()->listar) {
case 'unidades': {
return [
'unidades' => self::getCadastroUnidades($params),
'infraestruturas' => [],
'ocupacoes' => [],
'especialidades' => [],
'usuarios' => [],
'tipos' => [],
'datas' => [],
'horarios' => [],
];
}
case 'infraestruturas': {
return [
'infraestruturas' => self::getCadastroInfraestruturas($params),
'ocupacoes' => [],
'especialidades' => [],
'usuarios' => [],
'tipos' => [],
'datas' => [],
'horarios' => [],
];
}
case 'ocupacoes': {
return [
'ocupacoes' => self::getCadastroOcupacoes($params),
'especialidades' => [],
'usuarios' => [],
'tipos' => [],
'datas' => [],
'horarios' => [],
];
}
case 'especialidades': {
return [
'especialidades' => self::getCadastroEspecialidades($params),
'usuarios' => [],
'tipos' => [],
'datas' => [],
'horarios' => [],
];
}
case 'usuarios': {
return [
'usuarios' => self::getCadastroUsuarios($params),
'tipos' => [],
'datas' => [],
'horarios' => [],
];
}
case 'tipos': {
return [
'tipos' => self::getCadastroTipos($params),
'datas' => [],
'horarios' => [],
];
}
case 'datas': {
return [
'datas' => self::getCadastroDatas($params),
'datas_bloqueadas' => self::getCadastroDatasBloqueadas($params),
'datas_com_agendamento' => self::getCadastroDatasComAgendamento($params),
'horarios' => [],
];
}
case 'horarios': {
return [
'horarios' => self::getCadastroHorarios($params),
'horarios_com_situacao' => self::getCadastroHorariosComSituacao($params),
'quantidade_demanda_espontanea' => self::getQuantidadeDemandaEspontanea($params),
'model' => [
'demanda_espontanea_observa_vaga_atendimento' => self::getDemandaEspontaneaObservaVagaAtendimento(
$params->infraestrutura_id,
$params->especialidade_id,
),
],
];
}
}
}
private static function getCadastroUnidades($params)
{
$infraestruturaLogada = self::getCurrentCentroCusto()->infraestrutura;
return Unidade::whereHas('infraestruturas', fn ($q) => $q
->where(fn ($q) => $q
->where('id', $infraestruturaLogada->id)
->orWhereHas('ambulatorioParametrizacaoJornadaInfraestrutura', fn ($q) => $q
->whereHas('infraestruturasAgendadoras', fn ($q) => $q
->where('infraestrutura_id', $infraestruturaLogada->id)
)
)
)
->whereHas('lotacoes', fn ($q) => $q
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereNull('situacao_id')
->whereDate('data', '<', Carbon::now())
->whereHas('especialidade', fn ($q) =>
self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
)
)
)
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']);
}
private static function getCadastroInfraestruturas($params)
{
$infraestruturaLogada = self::getCurrentCentroCusto()->infraestrutura;
return Infraestrutura::setEagerLoads([])
->where('unidade_id', $params->unidade_id)
->where(fn ($q) => $q
->where('id', $infraestruturaLogada->id)
->orWhereHas('ambulatorioParametrizacaoJornadaInfraestrutura', fn ($q) => $q
->whereHas('infraestruturasAgendadoras', fn ($q) => $q
->where('infraestrutura_id', $infraestruturaLogada->id)
)
)
)
->whereHas('lotacoes', fn ($q) => $q
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereNull('situacao_id')
->whereDate('data', '<', Carbon::now())
->whereHas('especialidade', fn ($q) =>
self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
)
)
->get(['id', 'nome', 'principal', 'unidade_id'])
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome
])
->sortBy('nome')
->values();
}
private static function getCadastroOcupacoes($params, $ocupacaoId = null)
{
return DB::table('sigtap.ocupacao as ocupacao')
->when($ocupacaoId, fn ($q, $id) => $q->where('id', $id))
->whereExists(function ($query) use ($params) {
$query->select(DB::raw(1))
->from('cadastro_lotacao as lotacao')
->whereColumn('lotacao.ocupacao_id', 'ocupacao.id')
->where('lotacao.infraestrutura_id', $params->infraestrutura_id)
->whereExists(function ($query) use ($params) {
$query->select(DB::raw(1))
->from('ambulatorio_jornada as jornada')
->join(
'cadastro_especialidade as especialidade',
'especialidade.id',
'jornada.especialidade_id'
)
->whereColumn('jornada.lotacao_id', 'lotacao.id')
->whereNull('jornada.situacao_id')
->whereDate('jornada.data', '<', Carbon::now())
->where(fn ($query) => self::setCadastroWhereEspecialidadePaciente(
$query,
$params->paciente_id,
'especialidade'
))
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('especialidade.permite_agendamento_nao_municipe', true)
);
});
})
->orderByRaw("CONCAT(ocupacao.codigo, ' - ', ocupacao.nome)")
->select(DB::raw("
ocupacao.id,
CONCAT(ocupacao.codigo, ' - ', ocupacao.nome) as descricao
"))
->get();
}
private static function getCadastroEspecialidades($params, $especialidadeId = null)
{
return Especialidade::when($especialidadeId, fn ($q, $id) => $q->where('id', $id))
->where(fn ($q) => self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id))
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereNull('situacao_id')
->whereDate('data', '<', Carbon::now())
->whereHas('lotacao', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->where('ocupacao_id', $params->ocupacao_id)
)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
->orderBy('nome')
->get(['id', 'nome', 'tratamento', 'permite_agendamento_mesmo_dia']);
}
private static function getCadastroUsuarios($params)
{
return Usuario::setEagerLoads([])
->whereHas('lotacoes', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->where('ocupacao_id', $params->ocupacao_id)
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereNull('situacao_id')
->whereDate('data', '<', Carbon::now())
->where('especialidade_id', $params->especialidade_id)
->whereHas('especialidade', fn ($q) =>
self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
)
)
->get(['id', 'cidadao_id'])
->map(fn ($usuario) => [
'id' => $usuario->id,
'nome' => $usuario->cidadao()->setEagerLoads([])->first(['nome'])->nome,
])
->sortBy('nome')
->values();
}
private static function getCadastroTipos($params)
{
$tipos = collect();
$hasJornada = function ($campoQuantidade) use ($params) {
return Jornada::whereNotNull($campoQuantidade)
->whereNull('situacao_id')
->whereDate('data', '<', Carbon::now())
->where('especialidade_id', $params->especialidade_id)
->whereHas('especialidade', fn ($q) =>
self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
->whereHas('lotacao', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->where('ocupacao_id', $params->ocupacao_id)
->where('usuario_id', $params->usuario_id)
)
->exists();
};
if ($hasJornada('quantidade_consulta')) {
$tipos->push(AgendamentoTipo::find(AgendamentoTipoEnum::CONSULTA));
}
if ($hasJornada('quantidade_retorno')) {
$tipos->push(AgendamentoTipo::find(AgendamentoTipoEnum::RETORNO));
}
return $tipos;
}
private static function getCadastroDatas($params)
{
$campoQuantidade = self::getCampoQuantidade($params->tipo_id);
$feriados = self::getFeriados()->map(fn ($f) => Carbon::createFromFormat('d/m/Y', $f->data)->setTime(0, 0));
$jornadasAgrupadas = Jornada::whereNotNull($campoQuantidade)
->whereNull('situacao_id')
->whereDate('data', '<', Carbon::now())
->whereHas('lotacao', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->where('ocupacao_id', $params->ocupacao_id)
->where('usuario_id', $params->usuario_id)
)
->where('especialidade_id', $params->especialidade_id)
->whereHas('especialidade', fn ($q) =>
self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
->groupBy('data')
->select(
'data',
DB::raw("SUM({$campoQuantidade}) as quantidade_total")
)
->get()
->reject(function ($jornadasAgrupadas) use ($feriados) {
return $feriados->contains($jornadasAgrupadas->data);
})
->reject(function ($jornadasAgrupadas) use ($params) {
return JornadaBloqueio::where('infraestrutura_id', $params->infraestrutura_id)
->where('especialidade_id', $params->especialidade_id)
->whereDate('inicio', '<=', $jornadasAgrupadas->data)
->whereDate('fim', '>=', $jornadasAgrupadas->data)
->where(function ($query) use ($params) {
$query->whereNull('usuario_id')
->orWhere('usuario_id', $params->usuario_id);
})
->exists();
})
->values();
$agendados = Agendamento::where('tipo_id', $params->tipo_id)
->whereNotIn('status_id', self::getStatusLiberamHorario())
->whereHas('jornada', fn ($q) => $q
->whereDate('data', '<', Carbon::now())
->whereHas('lotacao', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->where('ocupacao_id', $params->ocupacao_id)
->where('usuario_id', $params->usuario_id)
)
->where('especialidade_id', $params->especialidade_id)
->whereHas('especialidade', fn ($q) =>
self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
)
->get()
->map(fn ($agendamento) => [
'data' => $agendamento->jornada->data->format('d/m/Y'),
]);
$demandas = DemandaEspontanea::whereHas('jornada', fn ($q) => $q
->whereDate('data', '<', Carbon::now())
->whereHas('lotacao', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->where('ocupacao_id', $params->ocupacao_id)
->where('usuario_id', $params->usuario_id)
)
->where('especialidade_id', $params->especialidade_id)
->whereHas('especialidade', fn ($q) =>
self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
)
->get()
->map(fn ($demanda) => [
'data' => $demanda->jornada->data->format('d/m/Y'),
]);
$contagens = [];
foreach ($agendados as $agendamento) {
$data = $agendamento['data'];
$contagens[$data] = isset($contagens[$data]) ? $contagens[$data] + 1 : 1;
}
foreach ($demandas as $demanda) {
$data = $demanda['data'];
$contagens[$data] = isset($contagens[$data]) ? $contagens[$data] + 1 : 1;
}
foreach ($jornadasAgrupadas as &$jornada) {
$data = $jornada['data']->format('d/m/Y');
$jornada['quantidade_agendada'] = $contagens[$data] ?? 0;
}
return $jornadasAgrupadas;
}
private static function getCadastroDatasBloqueadas($params)
{
$datas = collect();
JornadaBloqueio::where('infraestrutura_id', $params->infraestrutura_id)
->where('especialidade_id', $params->especialidade_id)
->where(fn ($q) => $q
->whereDate('inicio', '<', Carbon::today())
->orWhereDate('fim', '<', Carbon::today())
)
->where('usuario_id', $params->usuario_id)
->get(['inicio', 'fim'])
->each(function ($parametrizacao) use ($datas) {
$dataAtual = Carbon::today();
$data = $parametrizacao->inicio;
while ($data <= $parametrizacao->fim) {
if ($data < $dataAtual) {
$datas->push($data->format('d/m/Y'));
}
$data->addDay();
}
});
return $datas;
}
private static function getCadastroHorarios($params)
{
$horarios = collect();
$data = Carbon::createFromFormat('d/m/Y', $params->data)->startOfDay();
Jornada::whereDate('data', $data)
->whereNotNull(self::getCampoQuantidade($params->tipo_id))
->whereNull('situacao_id')
->whereHas('lotacao', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->where('ocupacao_id', $params->ocupacao_id)
->where('usuario_id', $params->usuario_id)
)
->where('especialidade_id', $params->especialidade_id)
->whereHas('especialidade', fn ($q) =>
self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
->get([
'id',
'inicio',
'tipo_id',
'quantidade_consulta',
'quantidade_retorno',
'tempo_consulta',
'tempo_retorno',
'permite_agendamento_somente_supervisor',
])
->each(function ($jornada) use ($horarios, $data, $params) {
$jornada->inicio = $data->copy()->setTimeFromTimeString($jornada->inicio);
if ($jornada->tipo_id === JornadaTipo::FIXA) {
self::setHorarioJornadaFixa($horarios, $jornada, $params->tipo_id);
}
else if ($jornada->tipo_id === JornadaTipo::DINAMICA) {
self::setHorariosJornadaDinamica($horarios, $jornada, $params->tipo_id);
}
});
return $horarios->sortBy('horario')->values();
}
private static function setHorarioJornadaFixa($horarios, $jornada, $tipoId)
{
$horarios->push((object) [
'jornada_id' => $jornada->id,
'horario' => $jornada->inicio->format('H:i'),
'quantidade_agendada' => Agendamento::where('jornada_id', $jornada->id)
->where('tipo_id', $tipoId)
->whereTime('horario', $jornada->inicio)
->whereNotIn('status_id', self::getStatusLiberamHorario())
->count(),
'quantidade_total' => $jornada->{self::getCampoQuantidade($tipoId)},
'obrigatorio_autenticacao_supervisor' => $jornada->permite_agendamento_somente_supervisor
&& !SupervisorService::isUsuarioLogadoSupervisor(),
]);
}
private static function setHorariosJornadaDinamica($horarios, $jornada, $tipoId)
{
$agendamentos = self::getAgendamentos($jornada->id);
$agendamentos->each(fn ($a) => $a->horario = $jornada->inicio->copy()->setTimeFromTimeString($a->horario));
$agendamentos->where('tipo_id', $tipoId)
->each(fn ($agendamento) => $horarios->push((object) [
'jornada_id' => $jornada->id,
'horario' => $agendamento->horario->format('H:i'),
'quantidade_agendada' => $agendamento->quantidade_agendada,
'quantidade_total' => 1,
'obrigatorio_autenticacao_supervisor' => $jornada->permite_agendamento_somente_supervisor
&& !SupervisorService::isUsuarioLogadoSupervisor(),
]));
$quantidade = $agendamentos->where('tipo_id', $tipoId)->count();
if ($quantidade < $jornada->{self::getCampoQuantidade($tipoId)}) {
$data = $jornada->inicio->copy();
self::setHorarioJornadaDinamica(
$horarios,
$agendamentos,
$jornada,
$tipoId,
$quantidade,
$data
);
}
}
private static function getAgendamentos($jornadaId)
{
return Agendamento::where('jornada_id', $jornadaId)
->whereNotIn('status_id', self::getStatusLiberamHorario())
->groupBy([
'tipo_id',
'horario',
])
->orderBy('horario')
->select(
'tipo_id',
'horario',
DB::raw("COUNT(id) as quantidade_agendada")
)
->get();
}
private static function setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data)
{
$agendamento = $agendamentos->where('horario', $data)->first();
if (is_null($agendamento)) {
$final = $data->copy()->addMinutes($jornada->{self::getCampoTempo($tipoId)});
$agendamento = $agendamentos
->where('horario', '>', $data)
->where('horario', '<', $final)
->first();
if ($agendamento) {
self::setHorarioJornadaDinamica(
$horarios,
$agendamentos,
$jornada,
$tipoId,
$quantidade,
$agendamento->horario
);
}
else {
$horarios->push((object) [
'jornada_id' => $jornada->id,
'horario' => $data->format('H:i'),
'quantidade_agendada' => 0,
'quantidade_total' => 1,
'obrigatorio_autenticacao_supervisor' => $jornada->permite_agendamento_somente_supervisor
&& !SupervisorService::isUsuarioLogadoSupervisor(),
]);
if (++$quantidade < $jornada->{self::getCampoQuantidade($tipoId)}) {
$data->addMinutes($jornada->{self::getCampoTempo($tipoId)});
self::setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data);
}
}
}
else {
if ($agendamento->tipo_id == $tipoId) {
$data->addMinutes($jornada->{self::getCampoTempo($tipoId)});
self::setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data);
}
else {
$data = $agendamento->horario->copy()->addMinutes($jornada->{self::getCampoTempo($tipoId, true)});
self::setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data);
}
}
}
private static function getCadastroHorariosComSituacao($params)
{
return Jornada::whereDate('data', Carbon::createFromFormat('d/m/Y', $params->data))
->whereNotNull(self::getCampoQuantidade($params->tipo_id))
->whereNotNull('situacao_id')
->whereHas('lotacao', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->where('ocupacao_id', $params->ocupacao_id)
->where('usuario_id', $params->usuario_id)
)
->where('especialidade_id', $params->especialidade_id)
->whereHas('especialidade', fn ($q) =>
self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
->orderBy('inicio')
->get([
'situacao_id',
'inicio',
'fim',
])
->map(fn ($jornada) => [
'inicio' => $jornada->inicio->format('H:i'),
'fim' => $jornada->fim->format('H:i'),
'situacao_nome' => $jornada->situacao->nome,
]);
}
private static function setCadastroWhereEspecialidadePaciente($query, $pacienteId, $tableAlias = '')
{
if (!empty($tableAlias)) {
$tableAlias .= '.';
}
$paciente = Paciente::find($pacienteId);
$idade = $paciente->cidadao->idade;
return $query->where(fn ($q) => $q
->when($idade, fn ($q) => $q
->where(fn ($q) => $q
->whereNull("{$tableAlias}idade_minima")
->orWhere("{$tableAlias}idade_minima", '<=', $idade['anos'])
)
->where(fn ($q) => $q
->whereNull("{$tableAlias}idade_maxima")
->orWhere("{$tableAlias}idade_maxima", '>=', $idade['anos'])
)
)
->where(fn ($q) => $q
->whereNull("{$tableAlias}sexo_id")
->orWhere("{$tableAlias}sexo_id", $paciente->cidadao->sexo_id)
)
);
}
private static function getCampoQuantidade($tipoId)
{
if ($tipoId == AgendamentoTipoEnum::CONSULTA) {
return 'quantidade_consulta';
}
else if ($tipoId == AgendamentoTipoEnum::RETORNO) {
return 'quantidade_retorno';
}
}
private static function getCampoTempo($tipoId, $inverso = false)
{
if ($tipoId == AgendamentoTipoEnum::CONSULTA) {
return $inverso ? 'tempo_retorno' : 'tempo_consulta';
}
else if ($tipoId == AgendamentoTipoEnum::RETORNO) {
return $inverso ? 'tempo_consulta' : 'tempo_retorno';
}
}
private static function getDemandaEspontaneaObservaVagaAtendimento($infraestruturaId, $especialidadeId)
{
if (is_null($infraestruturaId) || is_null($especialidadeId)) {
return false;
}
$parametrizacao = ParametrizacaoInfraestruturaEspecialidade::whereHas('parametrizacaoInfraestrutura', fn ($q) => $q
->where('infraestrutura_id', $infraestruturaId)
)
->where('especialidade_id', $especialidadeId)
->first(['demanda_espontanea_observa_vaga_atendimento']);
return $parametrizacao->demanda_espontanea_observa_vaga_atendimento ?? false;
}
private static function getDemandaEspontaneaObservaVagaAtendimentoAgendamento($agendamento)
{
return self::getDemandaEspontaneaObservaVagaAtendimento(
$agendamento->jornada->lotacao->infraestrutura_id,
$agendamento->jornada->especialidade_id,
);
}
public static function unidadePaciente($pacienteId, $infraestruturaId)
{
$possuiJornadaUnidadePaciente = false;
$parametrizacao = ParametrizacaoAgendamento::first();
if ($parametrizacao->avisa_paciente_outra_unidade) {
$paciente = Paciente::findOrFail($pacienteId);
$unidadeId = Infraestrutura::findOrFail($infraestruturaId)->unidade_id;
if ($unidadeId !== $paciente->unidade_id) {
$possuiJornadaUnidadePaciente = Unidade::where('id', $paciente->unidade_id)->exists();
}
}
return [
'unidade_com_jornada' => $possuiJornadaUnidadePaciente,
'unidade' => $paciente->unidade->nome_fantasia ?? null,
];
}
public static function store()
{
self::validateStore();
$agendamento = new Agendamento();
DB::transaction(function () use ($agendamento) {
$jornada = Jornada::findOrFail(request()->jornada_id);
self::validateProcedimentoGrupo(request()->paciente_id, $jornada->id);
self::validateConflito(
request()->paciente_id,
$jornada->id,
request()->horario,
request()->tipo_id,
request()->motivo_agendamento_excedente
);
$agendamento->fill([
'jornada_id' => $jornada->id,
'tipo_id' => request()->tipo_id,
'horario' => request()->horario,
'paciente_id' => request()->paciente_id,
'motivo_agendamento_excedente' => request()->motivo_agendamento_excedente,
'observacao' => request()->observacao,
'status_id' => AgendamentoStatusEnum::AGENDADO,
]);
$agendamento->save();
});
return $agendamento->fresh();
}
private static function validateStore()
{
request()->validate([
'paciente_id' => [
'required',
Rule::exists(Paciente::class, 'id'),
],
'jornada_id' => [
'required',
Rule::exists(Jornada::class, 'id'),
],
'tipo_id' => [
'required',
Rule::exists(AgendamentoTipo::class, 'id'),
],
'horario' => [
'required',
'date_format:H:i',
],
'observacao' => [
'nullable',
'string',
'max:500',
],
'motivo_agendamento_excedente' => [
'nullable',
'string',
'max:500',
],
]);
}
private static function validateProcedimentoGrupo($pacienteId, $jornadaId)
{
$especialidade = Jornada::findOrFail($jornadaId)->especialidade()
->first(['procedimento_grupo_codigo']);
if (is_null($especialidade->procedimento_grupo_codigo)) {
return;
}
$paciente = Paciente::findOrFail($pacienteId);
$procedimento = Procedimento::where('codigo', $especialidade->procedimento_grupo_codigo)
->orderByDesc('competencia_id')
->first();
$validator = new ProcedimentoValidationService($procedimento);
if (!$validator->isSexoValid($paciente->cidadao->sexo)
|| !$validator->isIdadeValid($paciente->cidadao->idade['anos'])
) {
throw new AgendamentoNaoPermitidoJornadaGrupoException();
}
}
private static function validateConflito(
$pacienteId,
$jornadaId,
$horario,
$agendamentoTipoId = null,
$motivoAgendamentoExcedente = null
) {
if (!empty($motivoAgendamentoExcedente)) {
return;
}
$paciente = Paciente::findOrFail($pacienteId);
$jornada = Jornada::findOrFail($jornadaId);
$params = (object) [
'paciente_id' => $paciente->id,
'paciente_nao_municipe' => $paciente->classificacao_id !== Classificacao::MUNICIPE,
'unidade_id' => $jornada->lotacao->infraestrutura->unidade_id,
'infraestrutura_id' => $jornada->lotacao->infraestrutura_id,
'ocupacao_id' => $jornada->lotacao->ocupacao_id,
'especialidade_id' => $jornada->especialidade_id,
'usuario_id' => $jornada->lotacao->usuario_id,
'data' => $jornada->data->format('d/m/Y'),
'tipo_id' => $agendamentoTipoId,
];
$horarioJornada = self::getCadastroHorarios($params)->where('horario', $horario)->first();
$agendamento = Agendamento::where('jornada_id', $jornadaId)
->where('horario', $horario)
->whereNotIn('status_id', self::getStatusLiberamHorario())
->first();
if (!is_null($agendamento)) {
if ($jornada->tipo_id === JornadaTipo::FIXA
&& $horarioJornada->quantidade_agendada < $horarioJornada->quantidade_total
) {
return;
}
throw new AgendamentoConflitanteException();
}
}
private static function getStatusLiberamHorario()
{
return [
AgendamentoStatusEnum::REAGENDADO_PELO_PACIENTE,
AgendamentoStatusEnum::REAGENDADO_PELO_MEDICO,
AgendamentoStatusEnum::CANCELADO_PELO_PACIENTE,
AgendamentoStatusEnum::CANCELADO_PELO_MEDICO,
];
}
public static function destroy($id)
{
$agendamento = Agendamento::findOrFail($id);
if ($agendamento->status_id !== AgendamentoStatusEnum::AGENDADO) {
throw new NaoPodeExcluirAgendamentoException();
}
DB::transaction(function () use ($agendamento) {
if (!is_null($agendamento->regulacao_solicitacao_id)) {
RegulacaoSolicitacaoService::updateStatus(
$agendamento->regulacao_solicitacao_id,
RegulacaoStatusTipo::CANCELADO,
['justificativa' => 'Cancelado automaticamente pela funcionalidade Agendamento retroativo'],
);
}
$agendamento->delete();
});
}
public static function getPrintData($id)
{
$agendamento = Agendamento::findOrFail($id);
return [
'unidade' => [
'nome_fantasia' => $agendamento->jornada->lotacao->infraestrutura->unidade->nome_fantasia
],
'infraestrutura' => [
'nome' => $agendamento->jornada->lotacao->infraestrutura->nome,
'endereco' => $agendamento->jornada->lotacao->infraestrutura->endereco->completo,
'telefone' => MaskUtil::getPhoneMasked($agendamento->jornada->lotacao->infraestrutura->telefone),
],
'paciente' => [
'nome' => $agendamento->paciente->cidadao->nome,
'prontuario' => $agendamento->paciente->prontuario,
],
'tipo' => [
'nome' => $agendamento->tipo->nome,
],
'data' => $agendamento->jornada->data->format('d/m/Y'),
'diaSemana' => DiaSemana::findOrFail($agendamento->jornada->dia_semana)->descricao,
'horario' => $agendamento->horario->format('H:i'),
'usuario' => [
'nome' => $agendamento->jornada->lotacao->usuario->cidadao->nome,
],
'especialidade' => [
'nome' => $agendamento->jornada->especialidade->nome,
'mensagem_protocolo_agendamento' => $agendamento->jornada->especialidade->mensagem_protocolo_agendamento,
],
'observacao' => $agendamento->observacao,
'usuarioAgendamento' => [
'nome' => $agendamento->createdLotacao->usuario->cidadao->nome,
'data_hora' => $agendamento->created_at->format('d/m/Y \à\s H:i'),
'unidade' => $agendamento->createdCentroCusto->infraestrutura->unidade->nome_fantasia,
'infraestrutura' => $agendamento->createdCentroCusto->infraestrutura->nome,
'setor' => $agendamento->createdCentroCusto->setor->nome,
],
];
}
private static function getPermissoesAtualizacaoCadastroPaciente()
{
$parametrizacao = CnsService::getParametrizacao();
if (!is_null($parametrizacao)) {
$lotacao = self::getCurrentLotacao();
return DB::table('cadastro_parametrizacao_permissao_usuario')
->select([
'municipe',
'provisorio',
'outro_municipio',
])
->where('infraestrutura_id', $lotacao->infraestrutura_id)
->where('usuario_id', $lotacao->usuario_id)
->get()
->first();
}
return null;
}
private static function getQuantidadeDemandaEspontanea($params)
{
if (empty($params->data)) {
return 0;
}
$data = Carbon::createFromFormat('d/m/Y', $params->data)->startOfDay();
return DemandaEspontanea::whereHas('jornada', fn ($q) =>
$q->whereDate('data', $data)
->whereHas('lotacao', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->where('ocupacao_id', $params->ocupacao_id)
->where('usuario_id', $params->usuario_id)
)
->where('especialidade_id', $params->especialidade_id)
->whereHas('especialidade', fn ($q) =>
self::setCadastroWhereEspecialidadePaciente($q, $params->paciente_id)
->when($params->paciente_nao_municipe, fn ($q) => $q
->where('permite_agendamento_nao_municipe', true)
)
)
)
->count();
}
}