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') ->join( 'cadastro_paciente_classificacao as classificacao', 'classificacao.id', 'paciente.classificacao_id' ) ->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, classificacao.descricao as classificacao_descricao, 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($params) { $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($params->paciente_id ?? null, fn ($q, $id) => $q->where('agendamento.paciente_id', $id)) ->when($params->periodo ?? null, fn ($q, $periodo) => $q ->whereBetween('jornada.data', [ Carbon::createFromFormat('d/m/Y', $periodo['start'])->startOfDay(), Carbon::createFromFormat('d/m/Y', $periodo['end'])->endOfDay(), ]) ) ->when(isset($params->inicio) && isset($params->fim), fn ($q) => $q ->whereBetween('agendamento.horario', [$params->inicio, $params->fim]) ) ->when($params->unidade_id ?? null, fn ($q, $id) => $q->where('unidade.id', $id)) ->when($params->infraestrutura_id ?? null, fn ($q, $id) => $q->where('infraestrutura.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)) ->when($params->usuario_id ?? null, fn ($q, $id) => $q->where('usuario.id', $id)) ->when($params->tipo_id ?? null, fn ($q, $id) => $q->where('tipo.id', $id)) ->when($params->status_id ?? null, fn ($q, $id) => $q->where('status.id', $id)) ->select(DB::raw(" agendamento.id, agendamento.regulacao_solicitacao_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) { $isAgendadoSemAtendimento = !$agendamento->has_atendimento && $agendamento->status_id === AgendamentoStatusEnum::AGENDADO; $agendamento->permite_alteracao = $isAgendadoSemAtendimento && is_null($agendamento->regulacao_solicitacao_id); $agendamento->permite_cancelamento_exclusao = $isAgendadoSemAtendimento; unset($agendamento->regulacao_solicitacao_id, $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(); $agendamentos = self::index((object) [ 'paciente_id' => $paciente->id, 'status_id' => AgendamentoStatusEnum::AGENDADO, 'periodo' => [ 'start' => Carbon::now()->subYear()->format('d/m/Y'), 'end' => Carbon::now()->format('d/m/Y'), ] ]); $formFilters = [ 'unidades' => [], 'infraestruturas' => [], 'ocupacoes' => [], 'especialidades' => [], 'usuarios' => [], 'tipos' => [], 'status' => [], ]; $modelFilters = [ '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, ]; if ($agendamentos->isNotEmpty()) { $agendamentosFilters = self::getAgendamentosFilters($paciente, $agendamentos); $formFilters['unidades'] = $agendamentosFilters->form['unidades']; $formFilters['ocupacoes'] = $agendamentosFilters->form['ocupacoes']; $formFilters['usuarios'] = $agendamentosFilters->form['usuarios']; $formFilters['tipos'] = $agendamentosFilters->form['tipos']; $formFilters['status'] = $agendamentosFilters->form['status']; $modelFilters['periodo'] = $agendamentosFilters->model['periodo']; $modelFilters['status_id'] = $agendamentosFilters->model['status_id']; } $cadastroParametrizacao = Parametrizacao::first(); return [ 'additionals' => [ 'cadastro_paciente_vencido' => ($parametrizacao->bloqueia_paciente_temporario ?? false) && PacienteController::isCadastroPacienteVencido($paciente->id), 'cns_valido' => Cns::isValid($paciente->cidadao->cns), 'avisa_cns_provisorio' => self::avisaCnsProvisorio($parametrizacao, $paciente), 'avisa_cns_temporario_invalido' => $cadastroParametrizacao->exibe_alerta_paciente_cns_temporario_invalido ?? false, 'permissoes_atualizacao_cadastro_paciente' => self::getPermissoesAtualizacaoCadastroPaciente(), ], 'form' => array_merge($formFilters, [ '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), ]), 'model' => $modelFilters, 'agendamentos' => $agendamentos, ]; } private static function getAgendamentosFilters($paciente, $agendamentos) { $datasAgendadas = collect(); $agendamentos->each(fn ($agendamento) => $datasAgendadas ->push(Carbon::createFromFormat('Y-m-d', $agendamento->data)) ); $datasAgendadas = $datasAgendadas->sort(); $periodo = [ 'start' => $datasAgendadas->first()->copy()->startOfDay(), 'end' => $datasAgendadas->last()->copy()->endOfDay(), ]; $params = (object) [ 'paciente_id' => $paciente->id, 'periodo' => $periodo, ]; return (object) [ 'form' => [ 'unidades' => self::getBuscaUnidades($params), 'ocupacoes' => self::getBuscaOcupacoes($params), 'usuarios' => self::getBuscaUsuarios($params), 'tipos' => self::getBuscaTipos($params), 'status' => self::getBuscaStatus($params), ], 'model' => [ 'periodo' => [ 'start' => $periodo['start']->format('d/m/Y'), 'end' => $periodo['end']->format('d/m/Y'), ], 'status_id' => AgendamentoStatusEnum::AGENDADO, ], ]; } private static function avisaCnsProvisorio($parametrizacao, $paciente) { return ($parametrizacao->avisa_cns_provisorio ?? false) && 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($paciente), 'form' => [ 'feriados' => self::getFeriados(), 'datas_com_agendamento' => self::getCadastroDatasComAgendamento($params), 'unidades' => self::getCadastroUnidades($params), 'infraestruturas' => [], 'ocupacoes' => [], 'especialidades' => [], 'faltas' => [], 'usuarios' => [], 'datas' => [], 'datas_bloqueadas' => [], 'horarios' => [], 'horarios_com_situacao' => [], 'quantidade_demanda_espontanea' => null, 'tipo_nome' => null, ], 'model' => [ 'unidade_id' => null, 'infraestrutura_id' => null, 'ocupacao_id' => null, 'especialidade_id' => null, 'usuario_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, 'data' => $agendamento->jornada->data->format('d/m/Y'), 'tipo_id' => $agendamento->tipo_id, ]; 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), 'faltas' => self::getFaltas($params), 'usuarios' => self::getCadastroUsuarios($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), 'tipo_nome' => $agendamento->tipo->nome, 'situacao' => self::getCadastroDatasComSituacao($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, '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 [ 'data_atual' => Carbon::today()->format('d/m/Y'), '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) { $agendamentosExameLaboratorial = ExameLaboratorialAgendamento::where('paciente_id', $params->paciente_id) ->whereHas('agendamentoExame', fn ($q) => $q ->where('status_id', ExameLaboratorialAgendamentoStatus::AGENDADO) ) ->get() ->map(fn ($agendamento) => [ 'data' => $agendamento->data->format('d/m/Y'), 'horario' => Carbon::now()->setTimeFromTimeString($agendamento->horario)->format('H:i'), 'unidade_nome_fantasia' => $agendamento->coletaInfraestrutura->unidade->nome_fantasia, 'infraestrutura_nome' => $agendamento->coletaInfraestrutura->nome, ]); $agendamentosExameImagem = ExameImagemAgendamento::where('paciente_id', $params->paciente_id) ->whereHas('agendamentoExame', fn ($q) => $q ->where('status_id', ExameImagemAgendamentoStatus::AGENDADO) ) ->get() ->map(fn ($agendamento) => [ 'data' => $agendamento->data->format('d/m/Y'), 'horario' => Carbon::now()->setTimeFromTimeString($agendamento->hora_exame)->format('H:i'), 'unidade_nome_fantasia' => $agendamento->infraestrutura->unidade->nome_fantasia, 'infraestrutura_nome' => $agendamento->infraestrutura->nome, ]); return [ 'ambulatorio' => self::getAgendamentosPaciente($params->paciente_id), 'exame_laboratorial' => $agendamentosExameLaboratorial, 'exame_imagem' => $agendamentosExameImagem, ]; } private static function getAgendamentosPaciente($pacienteId) { return Agendamento::where('paciente_id', $pacienteId) ->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, ]); } public static function list() { switch (request()->origem) { case 'busca': { return self::getDadosListBusca(); } case 'cadastro': { return self::getDadosListCadastro(); } case 'agendamento-demanda-espontanea': { return self::getDadosListAgendamentoDemandaEspontanea(); } } } 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 ->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 ->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') ->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 ->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 ->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 ->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 ->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(); $agendamento = Agendamento::find($params->agendamento_id ?? null); $paciente = Paciente::setEagerLoads([])->where('id', $params->paciente_id)->first(); $tipo = $agendamento->tipo ?? (isset($params->especialidade_id) ? self::getTipo($params->paciente_id, $params->infraestrutura_id, $params->especialidade_id) : null); $params->paciente_nao_municipe = $paciente->classificacao_id !== Classificacao::MUNICIPE; $params->tipo_id = $tipo->id ?? null; switch (request()->listar) { case 'unidades': { return [ 'unidades' => self::getCadastroUnidades($params), 'infraestruturas' => [], 'ocupacoes' => [], 'especialidades' => [], 'usuarios' => [], 'datas' => [], 'horarios' => [], ]; } case 'infraestruturas': { return [ 'infraestruturas' => self::getCadastroInfraestruturas($params), 'ocupacoes' => [], 'especialidades' => [], 'usuarios' => [], 'datas' => [], 'horarios' => [], ]; } case 'ocupacoes': { return [ 'ocupacoes' => self::getCadastroOcupacoes( $params, $agendamento->jornada->lotacao->ocupacao_id ?? null ), 'especialidades' => [], 'usuarios' => [], 'datas' => [], 'horarios' => [], ]; } case 'especialidades': { return [ 'especialidades' => self::getCadastroEspecialidades( $params, $agendamento->jornada->especialidade_id ?? null ), 'usuarios' => [], 'datas' => [], 'horarios' => [], ]; } case 'usuarios': { return [ 'faltas' => self::getFaltas($params), 'usuarios' => self::getCadastroUsuarios($params), 'datas' => [], 'horarios' => [], ]; } case 'datas': { return [ 'datas' => self::getCadastroDatas($params), 'datas_bloqueadas' => self::getCadastroDatasBloqueadas($params), 'datas_com_agendamento' => self::getCadastroDatasComAgendamento($params), 'situacao' => self::getCadastroDatasComSituacao($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, ), ], 'tipo_nome' => $tipo->nome, ]; } } } 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','is_regulado']); } private static function getFaltas($params) { $parametrizacao = ParametrizacaoInfraestrutura::where('infraestrutura_id', $params->infraestrutura_id) ->first(); $parametrizacaoEspecialidade = $parametrizacao->especialidades() ->where('especialidade_id', $params->especialidade_id) ->first(); if (is_null($parametrizacaoEspecialidade) || is_null($parametrizacaoEspecialidade->avisa_falta_quantidade) ) { return collect(); } $dataAtual = Carbon::today()->endOfDay(); $data = $dataAtual->copy()->subDays($parametrizacaoEspecialidade->avisa_falta_dias)->startOfDay(); $faltas = Agendamento::where('paciente_id', $params->paciente_id) ->where('status_id', AgendamentoStatusEnum::FALTA_DO_PACIENTE) ->whereHas('jornada', fn ($q) => $q ->whereBetween('data', [$data, $dataAtual]) ) ->get() ->map(fn ($agendamento) => [ 'data' => $agendamento->jornada->data->format('d/m/Y'), 'horario' => $agendamento->horario->format('H:i'), 'especialidade' => $agendamento->jornada->especialidade->nome, 'usuario' => $agendamento->jornada->lotacao->usuario->cidadao() ->setEagerLoads([]) ->first(['nome']) ->nome, ]); return $faltas->count() >= $parametrizacaoEspecialidade->avisa_falta_quantidade ? $faltas : collect(); } private static function getCadastroUsuarios($params) { $campoQuantidade = self::getCampoQuantidade($params->tipo_id); 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 ->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) ) ) ) ) ->get(['id', 'cidadao_id']) ->map(fn ($usuario) => [ 'id' => $usuario->id, 'nome' => $usuario->cidadao()->setEagerLoads([])->first(['nome'])->nome, ]) ->sortBy('nome') ->values(); } private static function getCadastroDatas($params) { $campoQuantidade = self::getCampoQuantidade($params->tipo_id); $campoQuantidadeCidadao = self::getCampoQuantidadeConectasusCidadao($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}) + SUM(COALESCE({$campoQuantidadeCidadao}, 0)) 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(); }) ->when( self::getDataMinimaOcorrencia($params->paciente_id, $params->especialidade_id), fn ($collection, $dataMinima) => $collection->reject( fn ($jornada) => $jornada->data->lt($dataMinima) ) ) ->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(function ($query) use ($params) { $query->whereNull('usuario_id') ->orWhere('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); $dataMinima = self::getDataMinimaOcorrencia($params->paciente_id, $params->especialidade_id); if ($dataMinima && $data->lt($dataMinima)) { return $horarios; } 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', 'quantidade_consulta_conectasus_cidadao', 'quantidade_retorno_conectasus_cidadao', '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)} + ($jornada->{self::getCampoQuantidadeConectasusCidadao($tipoId)} ?? 0), '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(); $quantidadeTotal = $jornada->{self::getCampoQuantidade($tipoId)} + ($jornada->{self::getCampoQuantidadeConectasusCidadao($tipoId)} ?? 0); if ($quantidade < $quantidadeTotal) { $data = $jornada->inicio->copy(); self::setHorarioJornadaDinamica( $horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data, $quantidadeTotal ); } } 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, $quantidadeTotal = null) { if ($quantidadeTotal === null) { $quantidadeTotal = $jornada->{self::getCampoQuantidade($tipoId)} + ($jornada->{self::getCampoQuantidadeConectasusCidadao($tipoId)} ?? 0); } $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, $quantidadeTotal ); } 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 < $quantidadeTotal) { $data->addMinutes($jornada->{self::getCampoTempo($tipoId)}); self::setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data, $quantidadeTotal); } } } else { if ($agendamento->tipo_id == $tipoId) { $data->addMinutes($jornada->{self::getCampoTempo($tipoId)}); self::setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data, $quantidadeTotal); } else { $data = $agendamento->horario->copy()->addMinutes($jornada->{self::getCampoTempo($tipoId, true)}); self::setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data, $quantidadeTotal); } } } 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', 'data' ]) ->map(fn ($jornada) => [ 'inicio' => $jornada->inicio->format('H:i'), 'fim' => $jornada->fim->format('H:i'), 'situacao_nome' => $jornada->situacao->nome, ]); } private static function getCadastroDatasComSituacao($params){ return Jornada::whereNotNull('situacao_id') ->whereHas('lotacao', fn ($q) => $q ->where('infraestrutura_id', $params->infraestrutura_id) ->where('usuario_id', $params->usuario_id) ) ->join('ambulatorio_jornada_situacao', 'ambulatorio_jornada_situacao.id', 'ambulatorio_jornada.situacao_id') ->groupBy(['ambulatorio_jornada_situacao.nome', 'ambulatorio_jornada.data']) ->get([ 'ambulatorio_jornada_situacao.nome as situacao_nome', 'ambulatorio_jornada.data' ]) ->map(fn($jornada) =>[ 'data' => $jornada->data->format('d/m/Y'), '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 getDadosListAgendamentoDemandaEspontanea() { $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 'origens': { return [ 'origens' => self::getAgendamentoDemandaEspontaneaOrigens($params), ]; } } } private static function getAgendamentoDemandaEspontaneaOrigens($params) { $origens = collect(); $hasAgendamentos = DB::table('ambulatorio_agendamento AS agendamento') ->join('ambulatorio_jornada AS jornada', 'jornada.id', 'agendamento.jornada_id') ->where('agendamento.paciente_id', $params->paciente_id) ->whereBetween('jornada.data', $params->periodo) ->exists(); if ($hasAgendamentos) { $origens->push((object) ['value' => 'consulta-agendada', 'text' => 'Consulta agendada']); } $hasDemandasEspontaneas = DB::table('ambulatorio_demanda_espontanea AS demanda_espontanea') ->where('demanda_espontanea.paciente_id', $params->paciente_id) ->whereBetween('demanda_espontanea.data', $params->periodo) ->exists(); if ($hasDemandasEspontaneas) { $origens->push((object) ['value' => 'demanda-espontanea', 'text' => 'Demanda espontânea']); } return $origens; } public static function getSugestao($pacienteId, $infraestruturaId, $ocupacaoId, $especialidadeId, $usuarioId) { $agendamento = Agendamento::find(request()->agendamento_id ?? null); $paciente = Paciente::setEagerLoads([])->where('id', $pacienteId)->first(); $tipo = $agendamento->tipo ?? self::getTipo($pacienteId, $infraestruturaId, $especialidadeId); $datasAgendamentosPaciente = self::getAgendamentosPaciente($pacienteId) ->map(fn ($agendamento) => Carbon::createFromFormat('d/m/Y', $agendamento['data'])->startOfDay()); $params = (object) [ 'paciente_id' => $pacienteId, 'paciente_nao_municipe' => $paciente->classificacao_id !== Classificacao::MUNICIPE, 'infraestrutura_id' => $infraestruturaId, 'ocupacao_id' => $ocupacaoId, 'especialidade_id' => $especialidadeId, 'usuario_id' => $usuarioId, 'tipo_id' => $tipo->id, ]; $horarioDisponivel = null; self::getCadastroDatas($params) ->each(function ($data) use (&$horarioDisponivel, $params, $pacienteId, $datasAgendamentosPaciente) { if($data->quantidade_agendada >= $data->quantidade_total){ return true; } if ($datasAgendamentosPaciente->contains($data->data->startOfDay())) { return true; } $params->data = $data->data->format('d/m/Y'); $encontrado = false; self::getCadastroHorarios($params) ->each(function ($horario) use ($data, &$encontrado, &$horarioDisponivel, $pacienteId) { if ($horario->quantidade_agendada < $horario->quantidade_total) { try { self::validateAgendamento($pacienteId, $horario->jornada_id, $horario->horario); $horarioDisponivel = (object) [ 'jornada_id' => $horario->jornada_id, 'horario' => $horario->horario, 'data' => $data->data->format('d/m/Y'), 'dia_semana' => DiaSemana::find($data->dia_semana)->descricao, 'obrigatorio_autenticacao_supervisor' => $horario->obrigatorio_autenticacao_supervisor, ]; $encontrado = true; return false; } catch (AgendamentoConflitanteException | AgendamentoNaoPermitidoJornadaGrupoException $e ) { } } }); if ($encontrado) { return false; } }); if (!is_null($horarioDisponivel)) { $horarioDisponivel->tipo_nome = Str::lower($tipo->nome); } return $horarioDisponivel; } 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, ]; } private static function getTipo($pacienteId, $infraestruturaId, $especialidadeId) { $ultimaData = self::getUltimoDataAgendamento($pacienteId, $infraestruturaId, $especialidadeId); $diasParaRetorno = ParametrizacaoService::getQuantidadeDiasRetorno($infraestruturaId, $especialidadeId); $tipoId = $diasParaRetorno === 0 || is_null($ultimaData) || Carbon::today()->diff($ultimaData)->days > $diasParaRetorno ? AgendamentoTipoEnum::CONSULTA : AgendamentoTipoEnum::RETORNO; return AgendamentoTipo::find($tipoId); } private static function getUltimoDataAgendamento($pacienteId, $infraestruturaId, $especialidadeId) { $ultimaJornada = Jornada::where('especialidade_id', $especialidadeId) ->whereHas('lotacao', fn ($q) => $q ->where('infraestrutura_id', $infraestruturaId) ) ->whereHas('agendamentos', fn ($q) => $q ->where('paciente_id', $pacienteId) ->where('status_id', AgendamentoStatusEnum::REALIZADO) ) ->orderByDesc('data') ->first(['data']); return is_null($ultimaJornada) ? null : $ultimaJornada->data->startOfDay(); } private static function getCampoQuantidade($tipoId) { if ($tipoId === AgendamentoTipoEnum::CONSULTA) { return 'quantidade_consulta'; } else if ($tipoId === AgendamentoTipoEnum::RETORNO) { return 'quantidade_retorno'; } } private static function getCampoQuantidadeConectasusCidadao($tipoId) { if ($tipoId === AgendamentoTipoEnum::CONSULTA) { return 'quantidade_consulta_conectasus_cidadao'; } else if ($tipoId === AgendamentoTipoEnum::RETORNO) { return 'quantidade_retorno_conectasus_cidadao'; } } 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 store() { self::validateStore(); $agendamento = new Agendamento(); $deveIntegrarSafecare = false; DB::transaction(function () use ($agendamento, &$deveIntegrarSafecare) { $jornada = Jornada::findOrFail(request()->jornada_id); self::validateAgendamento( request()->paciente_id, $jornada->id, request()->horario, request()->motivo_agendamento_excedente ); $agendamento->fill([ 'jornada_id' => $jornada->id, 'tipo_id' => self::getTipo( request()->paciente_id, $jornada->lotacao->infraestrutura_id, $jornada->especialidade_id )->id, 'horario' => request()->horario, 'paciente_id' => request()->paciente_id, 'motivo_agendamento_excedente' => request()->motivo_agendamento_excedente, 'observacao' => request()->observacao, 'status_id' => AgendamentoStatusEnum::AGENDADO, 'regulacao_solicitacao_id' => request()->regulacao_solicitacao_id, ]); $agendamento->save(); (new SmsService($agendamento->id))->send(); if (optional(ParametrizacaoIntegracaoAplicativo::first())->habilita_integracao_aplicativo_feridas) { $infraestruturaId = $jornada->lotacao->infraestrutura_id; $ocupacaoCodigo = $jornada->lotacao->ocupacao->codigo ?? ''; $isEnfermagem = substr($ocupacaoCodigo, 0, 4) == '2235' || substr($ocupacaoCodigo, 0, 4) == '3222'; $setorTipo = $isEnfermagem ? SetorTipo::ENFERMAGEM : SetorTipo::CONSULTORIO; $centroCusto = CentroCusto::where('infraestrutura_id', $infraestruturaId) ->whereHas('setor', function ($query) use ($setorTipo) { $query->where('tipo_id', $setorTipo); }) ->first(); if (!$centroCusto) { $setorNome = $isEnfermagem ? 'enfermagem' : 'consultório'; abort( Response::HTTP_UNPROCESSABLE_ENTITY, "Não foi encontrado um centro de custo de {$setorNome} para a unidade da jornada." ); } $opcaoEntrada = OpcaoEntrada::whereHas('modulo', function ($query) { $query->where('identificador', Modulo::AMBULATORIO); }) ->whereHas('centroCusto', function ($query) use ($infraestruturaId) { $query->where('infraestrutura_id', $infraestruturaId) ->whereHas('setor', function ($subQuery) { $subQuery->where('tipo_id', SetorTipo::RECEPCAO); }); }) ->where('prioridade_obrigatoria', 0) ->first(); if (!$opcaoEntrada) { abort( Response::HTTP_UNPROCESSABLE_ENTITY, 'Não há opção de entrada parametrizada para a recepção da unidade da jornada.' ); } $payload = [ 'paciente_id' => request('paciente_id'), 'status_id' => Status::EM_ESPERA, 'opcao_entrada_id' => $opcaoEntrada->id, 'prioridade_id' => null, 'centro_custo_id' => $centroCusto->id, 'data_jornada' => $jornada->data, 'habilita_integracao_aplicativo_feridas' => optional(ParametrizacaoIntegracaoAplicativo::first())->habilita_integracao_aplicativo_feridas, ]; $fila = FilaService::store((object) $payload); $filaId = is_array($fila) ? ($fila['id'] ?? null) : ($fila->id ?? null); $atendimento = new Atendimento(); $atendimento->fill([ 'fila_id' => $filaId, 'paciente_id' => request('paciente_id'), 'agendamento_id' => $agendamento->id, 'demanda_espontanea_id' => null, ]); $atendimento->save(); $deveIntegrarSafecare = true; } }); if ($deveIntegrarSafecare) { DB::afterCommit(fn() => self::integrarSafecare($agendamento)); } $agendamento->refresh(); $agendamento->data = $agendamento->jornada()->first('data')->data->format('d/m/Y'); return $agendamento; } private static function integrarSafecare(Agendamento $agendamento): void { try { app(RegistroPacienteAposAgendamento::class)->integracaoPaciente($agendamento); } catch (Throwable $e) { logger()->error('Falha na integração Safecare', [ 'agendamento_id' => $agendamento->id, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); } } private static function validateStore() { request()->validate([ 'paciente_id' => [ 'required', Rule::exists(Paciente::class, 'id'), ], 'jornada_id' => [ 'required', Rule::exists(Jornada::class, 'id'), ], 'horario' => [ 'required', 'date_format:H:i', ], 'observacao' => [ 'nullable', 'string', 'max:500', ], 'motivo_agendamento_excedente' => [ 'nullable', 'string', 'max:500', ], 'regulacao_solicitacao_id' => [ 'nullable', 'integer', Rule::exists(RegulacaoSolicitacao::class, 'id'), ], ]); } public static function update($id) { self::validateUpdate(); $agendamentoAtual = Agendamento::findOrFail($id); $agendamentoNovo = new Agendamento(); DB::transaction(function () use ($agendamentoAtual, $agendamentoNovo) { if ($agendamentoAtual->status_id !== AgendamentoStatusEnum::AGENDADO) { throw new NaoPodeAlterarStatusAgendamentoException(); } $jornada = Jornada::findOrFail(request()->jornada_id); self::validateAgendamento( $agendamentoAtual->paciente_id, $jornada->id, request()->horario, request()->motivo_agendamento_excedente, $agendamentoAtual ); $agendamentoNovo->fill([ 'agendamento_anterior_id' => $agendamentoAtual->id, 'jornada_id' => $jornada->id, 'tipo_id' => $agendamentoAtual->tipo_id, 'horario' => request()->horario, 'paciente_id' => $agendamentoAtual->paciente_id, 'motivo_agendamento_excedente' => request()->motivo_agendamento_excedente, 'observacao' => request()->observacao, 'status_id' => AgendamentoStatusEnum::AGENDADO, 'regulacao_solicitacao_id' => $agendamentoAtual->regulacao_solicitacao_id, ]); $agendamentoNovo->save(); $agendamentoAtual->update(['status_id' => AgendamentoStatusEnum::REAGENDADO_PELO_PACIENTE]); (new SmsService($agendamentoAtual->id))->cancel(); (new SmsService($agendamentoNovo->id))->send(); }); $agendamentoNovo->refresh(); $agendamentoNovo->data = $agendamentoNovo->jornada()->first('data')->data->format('d/m/Y'); return $agendamentoNovo; } private static function validateUpdate() { request()->validate([ 'jornada_id' => [ 'required', Rule::exists(Jornada::class, 'id'), ], 'horario' => [ 'required', 'date_format:H:i', ], 'observacao' => [ 'nullable', 'string', 'max:500', ], 'motivo_agendamento_excedente' => [ 'nullable', 'string', 'max:500', ] ]); } private static function validateAgendamento( $pacienteId, $jornadaId, $horario, $motivoAgendamentoExcedente = null, $agendamento = null ) { self::validateProcedimentoGrupo($pacienteId, $jornadaId); self::validateConflito($pacienteId, $jornadaId, $horario, $motivoAgendamentoExcedente, $agendamento); } 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, $motivoAgendamentoExcedente = null, $agendamento = null ) { if (!empty($motivoAgendamentoExcedente)) { return; } if (!is_null($agendamento) && $agendamento->jornada_id == $jornadaId && $agendamento->horario->format('H:i') == $horario ) { return; } $paciente = Paciente::findOrFail($pacienteId); $jornada = Jornada::findOrFail($jornadaId); $tipo = $agendamento->tipo ?? self::getTipo( $paciente->id, $jornada->lotacao->infraestrutura_id, $jornada->especialidade_id ); $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' => $tipo->id, ]; $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(); } } public static function getStatusLiberamHorario() { return [ AgendamentoStatusEnum::REAGENDADO_PELO_PACIENTE, AgendamentoStatusEnum::REAGENDADO_PELO_MEDICO, AgendamentoStatusEnum::CANCELADO_PELO_PACIENTE, AgendamentoStatusEnum::CANCELADO_PELO_MEDICO, ]; } private static function getDataMinimaOcorrencia($pacienteId, $especialidadeId) { $especialidade = DB::table('cadastro_especialidade') ->where('id', $especialidadeId) ->first(['limite_ocorrencias_paciente', 'periodo_monitoramento', 'tempo_liberacao']); if (is_null($especialidade) || is_null($especialidade->limite_ocorrencias_paciente) || is_null($especialidade->periodo_monitoramento) ) { return null; } $dataInicio = Carbon::today()->subDays($especialidade->periodo_monitoramento); $baseQuery = fn () => DB::table('ambulatorio_agendamento as agendamento') ->join('ambulatorio_jornada as jornada', 'jornada.id', 'agendamento.jornada_id') ->where('agendamento.paciente_id', $pacienteId) ->where('jornada.especialidade_id', $especialidadeId) ->whereDate('jornada.data', '>=', $dataInicio) ->whereIn('agendamento.status_id', [ AgendamentoStatusEnum::FALTA_DO_PACIENTE, AgendamentoStatusEnum::CANCELADO_PELO_PACIENTE, ]); $ocorrencias = $baseQuery()->count(); if ($ocorrencias < $especialidade->limite_ocorrencias_paciente) { return null; } $tempoLiberacao = $especialidade->tempo_liberacao ?? 0; if ($tempoLiberacao === 0) { return null; } $ultimaOcorrencia = $baseQuery()->max('jornada.data'); if (is_null($ultimaOcorrencia)) { return null; } return Carbon::parse($ultimaOcorrencia)->addDays($tempoLiberacao); } public static function cancel($id, $params) { self::validateCancel($params); $agendamento = Agendamento::findOrFail($id); if ($agendamento->status_id !== AgendamentoStatusEnum::AGENDADO) { throw new NaoPodeAlterarStatusAgendamentoException(); } DB::transaction(function () use ($agendamento, $params) { $agendamento->update([ 'status_id' => AgendamentoStatusEnum::CANCELADO_PELO_PACIENTE, 'motivo_cancelamento' => $params['motivo'], ]); (new SmsService($agendamento->id))->cancel(); if (!is_null($agendamento->regulacao_solicitacao_id) && !($params['is_from_regulacao'] ?? false)) { RegulacaoSolicitacaoService::updateStatus( $agendamento->regulacao_solicitacao_id, RegulacaoStatusTipo::CANCELADO, ['justificativa' => $params['motivo']], ); } }); return $agendamento->fresh(); } private static function validateCancel($params) { Validator::make($params, [ 'motivo' => [ 'required', 'string', 'max:500', ] ])->validate(); } 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'], ); } (new SmsService($agendamento->id))->cancel(); $agendamento->delete(); }); } public static function absent($id, $params = []) { $agendamento = Agendamento::findOrFail($id); DB::transaction(function () use ($agendamento, $params) { $agendamento->update(['status_id' => AgendamentoStatusEnum::FALTA_DO_PACIENTE]); if (!is_null($agendamento->regulacao_solicitacao_id) && !($params['is_from_regulacao'] ?? false)) { RegulacaoSolicitacaoService::updateStatus( $agendamento->regulacao_solicitacao_id, RegulacaoStatusTipo::FALTA ); } }); } public static function undoAbsent($id) { $agendamento = Agendamento::findOrFail($id); if ($agendamento->status_id === AgendamentoStatusEnum::FALTA_DO_PACIENTE) { DB::transaction(function () use ($agendamento) { $agendamento->update(['status_id' => AgendamentoStatusEnum::AGENDADO]); }); } } public static function getPrintData($id) { $agendamento = Agendamento::findOrFail($id); return [ 'isPrintExterno' => false, '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, 'nome_social' => $agendamento->paciente->cidadao->nome_social, '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, ], 'regulacaoMensagemComprovanteAgendamento' => is_null($agendamento->regulacaoSolicitacao) ? null : RegulacaoParametrizacao::first()->mensagem_comprovante_agendamento ?? null, 'regulacaoProtocoloFechamento' => is_null($agendamento->regulacaoSolicitacao) ? null : $agendamento->regulacaoSolicitacao->numero ?? null, 'observacao' => $agendamento->observacao, 'usuarioAgendamento' => [ 'nome' => $agendamento->createdLotacao->usuario->cidadao->nome, 'nome_social' => $agendamento->createdLotacao->usuario->cidadao->nome_social, '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, ], ]; } public static function getPrintDataExterno($id) { $solicitacao = RegulacaoSolicitacao::findOrFail($id); $tipo = $solicitacao->prestadorExterno->destino->tipo->descricao ?? ''; $logradouro = $solicitacao->prestadorExterno->destino->nome_logradouro ?? ''; $numero = $solicitacao->prestadorExterno->destino->numero_logradouro ? $solicitacao->prestadorExterno->destino->numero_logradouro : 'S/N'; $bairro = $solicitacao->prestadorExterno->destino->nome_bairro; $municipio = $solicitacao->prestadorExterno->destino->municipio->nome ?? ''; $uf = $solicitacao->prestadorExterno->destino->municipio->estado->uf ?? ''; $completo = "{$tipo} {$logradouro}, {$numero} - {$bairro}, {$municipio} - {$uf}"; return [ 'isPrintExterno' => true, 'unidade' => [ 'nome_fantasia' => null, ], 'infraestrutura' => [ 'nome' => $solicitacao->prestadorExterno->destino->descricao_destino, 'endereco' => $completo, 'telefone' => MaskUtil::getPhoneMasked($solicitacao->prestadorExterno->destino->numero_telefone_comercial), ], 'paciente' => [ 'nome' => $solicitacao->paciente->cidadao->nome, 'nome_social' => $solicitacao->paciente->cidadao->nome_social, 'prontuario' => $solicitacao->paciente->prontuario, ], 'tipo' => [ 'nome' => 'CONSULTA', ], 'data' => $solicitacao->data_agendada->format('d/m/Y'), 'diaSemana' => DiaSemana::findOrFail($solicitacao->data_agendada->dayOfWeek + 1)->descricao, 'horario' => $solicitacao->hora_agendada->format('H:i'), 'usuario' => [ 'nome' => $solicitacao->lotacaUsuario->usuario->cidadao->nome, ], 'especialidade' => [ 'nome' => $solicitacao->itens()->first()->especialidade->nome, 'mensagem_protocolo_agendamento' => $solicitacao->itens()->first()->especialidade->mensagem_protocolo_agendamento, ], 'regulacaoMensagemComprovanteAgendamento' => RegulacaoParametrizacao::first()->mensagem_comprovante_agendamento ?? null, 'regulacaoProtocoloFechamento' => $solicitacao->numero ?? null, 'observacao' => $solicitacao->observacao, 'usuarioAgendamento' => [ 'nome' => $solicitacao->createdLotacao->usuario->cidadao->nome, 'data_hora' => $solicitacao->created_at->format('d/m/Y \à\s H:i'), 'unidade' => $solicitacao->createdCentroCusto->infraestrutura->unidade->nome_fantasia, 'infraestrutura' => $solicitacao->createdCentroCusto->infraestrutura->nome, 'setor' => $solicitacao->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) { return 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) ) ) ) ->count(); } public static function createAgendamentoDemandaEspontanea($pacienteId) { $agendamentosDemandas = self::getAgendamentosDemandasEspontaneas((object) [ 'paciente_id' => $pacienteId, 'periodo' => [ 'start' => Carbon::now()->subYear()->format('d/m/Y'), 'end' => Carbon::now()->format('d/m/Y'), ], 'origem' => null, ]); $itens = $agendamentosDemandas['itens']; $formFilters = [ 'origens' => [], ]; $modelFilters = [ 'periodo' => ['start' => null, 'end' => null], 'origem' => null ]; if ($itens->isNotEmpty()) { $filters = self::getAgendamentoDemandaEspontaneaFilters($pacienteId, $itens); $formFilters['origens'] = $filters->form['origens']; $modelFilters['periodo'] = $filters->model['periodo']; } return [ 'form' => $formFilters, 'model' => $modelFilters, 'itens' => $itens, 'totalizadores' => $agendamentosDemandas['totalizadores'], ]; } private static function getAgendamentoDemandaEspontaneaFilters($pacienteId, $itens) { $datas = collect(); $itens->each(fn ($agendamento) => $datas ->push(Carbon::createFromFormat('Y-m-d', $agendamento->data)) ); $datas = $datas->sort(); $periodo = [ 'start' => $datas->first()->copy()->startOfDay(), 'end' => $datas->last()->copy()->endOfDay(), ]; $params = (object) [ 'paciente_id' => $pacienteId, 'periodo' => $periodo, ]; return (object) [ 'form' => [ 'origens' => self::getAgendamentoDemandaEspontaneaOrigens($params), ], 'model' => [ 'periodo' => [ 'start' => $periodo['start']->format('d/m/Y'), 'end' => $periodo['end']->format('d/m/Y'), ], ], ]; } public static function getAgendamentosDemandasEspontaneas($params) { $params->periodo = [ Carbon::createFromFormat('d/m/Y', $params->periodo['start'])->startOfDay(), Carbon::createFromFormat('d/m/Y', $params->periodo['end'])->endOfDay(), ]; $getAgendamentosBuilder = fn () => 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') ->where('agendamento.paciente_id', $params->paciente_id) ->whereBetween('jornada.data', $params->periodo) ->select(DB::raw(" 'Consulta agendada' as origem, 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, jornada.data, DATE_FORMAT(agendamento.horario, '%H:%i') as horario, status.id as status_id, status.nome as status ")); $getDemandasEspontaneasBuilder = fn () => DB::table('ambulatorio_demanda_espontanea as demanda_espontanea') ->join('ambulatorio_atendimento as atendimento', 'atendimento.demanda_espontanea_id', 'demanda_espontanea.id') ->join('painel_senha_fila as fila', 'fila.id', 'atendimento.fila_id') ->join('cadastro_lotacao as lotacao', 'lotacao.id', 'demanda_espontanea.created_lotacao_id') ->join('cadastro_infraestrutura as infraestrutura', 'infraestrutura.id', 'lotacao.infraestrutura_id') ->join('cadastro_unidade as unidade', 'unidade.id', 'infraestrutura.unidade_id') ->leftJoin('cadastro_usuario as usuario', 'usuario.id', 'demanda_espontanea.usuario_id') ->leftJoin('cadastro_cidadao as cidadao', 'cidadao.id', 'usuario.cidadao_id') ->leftJoin('sigtap.ocupacao as ocupacao', 'ocupacao.id', 'demanda_espontanea.ocupacao_id') ->leftJoin('cadastro_especialidade as especialidade', 'especialidade.id', 'demanda_espontanea.especialidade_id') ->where('demanda_espontanea.paciente_id', $params->paciente_id) ->whereBetween('demanda_espontanea.data', $params->periodo) ->select(DB::raw(" 'Demanda espontânea' as origem, 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, 'CONSULTA' as tipo, demanda_espontanea.data, DATE_FORMAT(demanda_espontanea.created_at, '%H:%i') as horario, IF(fila.evadido = 1, " . AgendamentoStatusEnum::EVADIDO . ", IF(atendimento.finalizado_em IS NULL, 'em-aberto', " . AgendamentoStatusEnum::REALIZADO . ") ) as status_id, IF(fila.evadido = 1, 'EVADIDO', IF(atendimento.finalizado_em IS NULL, 'EM ABERTO', 'REALIZADO')) as status ")); $builder = null; if ($params->origem === 'consulta-agendada') { $builder = $getAgendamentosBuilder(); } else if ($params->origem === 'demanda-espontanea') { $builder = $getDemandasEspontaneasBuilder(); } else { $builder = $getAgendamentosBuilder()->union($getDemandasEspontaneasBuilder()); } self::setAgendamentosDemandasEspontaneasOrderBy($builder); $itens = $builder->get(); $totalizadores = (object) [ 'agendado' => $itens->where('status_id', AgendamentoStatusEnum::AGENDADO)->count(), 'realizado' => $itens->where('status_id', AgendamentoStatusEnum::REALIZADO)->count(), 'reagendado_pelo_paciente' => $itens->where('status_id', AgendamentoStatusEnum::REAGENDADO_PELO_PACIENTE)->count(), 'reagendado_pelo_medico' => $itens->where('status_id', AgendamentoStatusEnum::REAGENDADO_PELO_MEDICO)->count(), 'cancelado_pelo_paciente' => $itens->where('status_id', AgendamentoStatusEnum::CANCELADO_PELO_PACIENTE)->count(), 'cancelado_pelo_medico' => $itens->where('status_id', AgendamentoStatusEnum::CANCELADO_PELO_MEDICO)->count(), 'falta_paciente' => $itens->where('status_id', AgendamentoStatusEnum::FALTA_DO_PACIENTE)->count(), 'falta_medico' => $itens->where('status_id', AgendamentoStatusEnum::FALTA_DO_MEDICO)->count(), 'em_aberto' => $itens->where('status_id', 'em-aberto')->count(), 'evadido' => $itens->where('status_id', AgendamentoStatusEnum::EVADIDO)->count(), 'geral' => $itens->count(), ]; return compact('itens', 'totalizadores'); } private static function setAgendamentosDemandasEspontaneasOrderBy($builder) { $columns = [ 'origem' => 'origem', 'unidade' => 'unidade', 'infraestrutura' => 'infraestrutura', 'usuario' => 'usuario', 'ocupacao' => 'ocupacao', 'especialidade' => 'especialidade', 'tipo' => 'tipo', 'data' => 'data', 'horario' => 'horario', 'status' => 'status', ]; if (is_null(request()->sort_by)) { $builder->orderByRaw(join(', ', $columns)); return; } $column = $columns[request()->sort_by]; $direction = DataUtil::getBooleanValueFromStringBoolean(request()->sort_desc) ? 'DESC' : 'ASC'; unset($columns[request()->sort_by]); $builder->orderByRaw( "{$column} {$direction}, " . join(', ', $columns) ); } }