first(); return [ 'agendamento' => [ 'habilitado' => (bool) ($parametrizacao->habilita_agendamento_conectasus_cidadao ?? false), ], 'visualizacao_laudo' => [ 'habilitada' => (bool) ($parametrizacao->habilita_visualizacao_laudo_conectasus_cidadao ?? false), ], ]; } public static function unidadesColeta(): array { self::validarParametrizacaoHabilitada(); $pacienteUnidadeId = auth('mobile')->user()->unidade_id; $agora = now(); return DB::table('cadastro_infraestrutura as infra_coleta') ->join('cadastro_unidade as unidade_coleta', 'unidade_coleta.id', 'infra_coleta.unidade_id') ->join('exame_laboratorial_parametrizacao_unidade as param_unidade', function ($join) { $join->on('param_unidade.infraestrutura_id', 'infra_coleta.id') ->where('param_unidade.unidade_coleta', true) ->whereNull('param_unidade.deleted_at'); }) ->join('exame_laboratorial_parametrizacao_unidade_solicitante as sol', function ($join) { $join->on('sol.infraestrutura_id', 'infra_coleta.id') ->whereNull('sol.deleted_at'); }) ->join('cadastro_infraestrutura as infra_sol', 'infra_sol.id', 'sol.unidade_solicitante_infraestrutura_id') ->where('infra_sol.unidade_id', $pacienteUnidadeId) ->whereNull('infra_coleta.deleted_at') ->whereExists(function ($q) use ($agora) { $q->select(DB::raw(1)) ->from('exame_laboratorial_jornada as jornada_coleta') ->whereColumn('jornada_coleta.infraestrutura_id', 'infra_coleta.id') ->where('jornada_coleta.vagas_app', '>', 0) ->where(function ($q2) use ($agora) { $q2->whereDate('jornada_coleta.data', '>', $agora->toDateString()) ->orWhere(function ($q3) use ($agora) { $q3->whereDate('jornada_coleta.data', $agora->toDateString()) ->whereTime('jornada_coleta.hora_fim', '>', $agora->format('H:i:s')); }); }) ->whereNull('jornada_coleta.deleted_at'); }) ->orderBy('unidade_coleta.nome_fantasia') ->orderBy('infra_coleta.nome') ->get( [ 'infra_coleta.id as infraestrutura_id', 'unidade_coleta.id as unidade_id', 'unidade_coleta.nome_fantasia', DB::raw( "CASE WHEN infra_coleta.nome IS NOT NULL THEN infra_coleta.nome ELSE unidade_coleta.nome_fantasia END AS infraestrutura_nome" ), 'sol.unidade_solicitante_infraestrutura_id', ] ) ->unique('infraestrutura_id') ->map( fn($item) => [ 'infraestrutura_id' => $item->infraestrutura_id, 'unidade_id' => $item->unidade_id, 'nome_fantasia' => $item->nome_fantasia, 'infraestrutura_nome' => $item->infraestrutura_nome, 'unidade_solicitante_infraestrutura_id' => $item->unidade_solicitante_infraestrutura_id, ] ) ->values() ->toArray(); } public static function exames(): array { self::validarParametrizacaoHabilitada(); $pacienteId = auth('mobile')->user()->id; $statusAtivos = [ StatusAgendamento::AGENDADO, StatusAgendamento::PENDENTE_ASSINATURA, StatusAgendamento::NOVA_COLETA, StatusAgendamento::PENDENTE_ENTREGA, ]; $statusRealizados = [ StatusAgendamento::REALIZADO, StatusAgendamento::ASSINADO, StatusAgendamento::ENTREGUE, ]; $exameIdsAtivos = DB::table('exame_laboratorial_agendamento_exame') ->where('paciente_id', $pacienteId) ->whereIn('status_id', $statusAtivos) ->pluck('exame_id') ->unique() ->toArray(); $exameIdsBloqueadosPorValidade = DB::table('parametrizacao_exame as exame') ->join('exame_laboratorial_agendamento_exame as ae', 'ae.exame_id', 'exame.id') ->join('exame_laboratorial_agendamento as ag', 'ag.id', 'ae.agendamento_id') ->where('ae.paciente_id', $pacienteId) ->whereIn('ae.status_id', $statusRealizados) ->whereNotNull('exame.validade') ->where('exame.validade', '>', 0) ->where(fn($q) => $q->where('exame.permite_repeticao', false)->orWhereNull('exame.permite_repeticao')) ->whereRaw('ag.data >= DATE_SUB(CURDATE(), INTERVAL exame.validade DAY)') ->pluck('exame.id') ->unique() ->toArray(); $exameIdsBloqueados = array_unique(array_merge($exameIdsAtivos, $exameIdsBloqueadosPorValidade)); $pedidosBloqueados = DB::table('ambulatorio_atendimento_soap_solicitacao_exame_item') ->where(function ($q) use ($exameIdsBloqueados) { $q->where('agendado_exame_laboratorial', true); if (!empty($exameIdsBloqueados)) { $q->orWhereIn('exame_id', $exameIdsBloqueados); } }) ->pluck('solicitacao_exame_id') ->unique() ->toArray(); $rows = DB::table('ambulatorio_atendimento_soap_solicitacao_exame_item') ->join('ambulatorio_atendimento_soap_solicitacao_exame', 'ambulatorio_atendimento_soap_solicitacao_exame.id', '=', 'ambulatorio_atendimento_soap_solicitacao_exame_item.solicitacao_exame_id') ->join('parametrizacao_exame', 'parametrizacao_exame.id', '=', 'ambulatorio_atendimento_soap_solicitacao_exame_item.exame_id') ->join('ambulatorio_atendimento_soap', 'ambulatorio_atendimento_soap.id', '=', 'ambulatorio_atendimento_soap_solicitacao_exame.soap_id') ->join('ambulatorio_atendimento', 'ambulatorio_atendimento.id', '=', 'ambulatorio_atendimento_soap.atendimento_id') ->join('painel_senha_fila', 'painel_senha_fila.id', '=', 'ambulatorio_atendimento.fila_id') ->join('cadastro_lotacao', 'cadastro_lotacao.id', 'ambulatorio_atendimento_soap_solicitacao_exame.created_lotacao_id') ->join('cadastro_usuario as profissional', 'profissional.id', 'cadastro_lotacao.usuario_id') ->join('cadastro_cidadao', 'cadastro_cidadao.id', 'profissional.cidadao_id') ->where('parametrizacao_exame.tipo_id', Tipo::LABORATORIAL) ->whereNull('parametrizacao_exame.regulacao_tipo_id') ->whereNull('parametrizacao_exame.deleted_at') ->where('ambulatorio_atendimento_soap_solicitacao_exame_item.descartado_exame_laboratorial', '!=', true) ->whereNotIn('ambulatorio_atendimento_soap_solicitacao_exame_item.solicitacao_exame_id', $pedidosBloqueados) ->where('painel_senha_fila.paciente_id', $pacienteId) ->where('ambulatorio_atendimento_soap.is_rascunho', false) ->orderBy('ambulatorio_atendimento_soap_solicitacao_exame.id') ->orderBy('parametrizacao_exame.nome') ->get([ 'ambulatorio_atendimento_soap_solicitacao_exame.id as solicitacao_id', 'ambulatorio_atendimento_soap_solicitacao_exame.created_at as data_solicitacao', 'ambulatorio_atendimento_soap_solicitacao_exame_item.id as exame_item_id', 'parametrizacao_exame.id as exame_id', 'parametrizacao_exame.codigo', 'parametrizacao_exame.nome', 'parametrizacao_exame.sigla_exame', 'parametrizacao_exame.prazo_entrega', 'parametrizacao_exame.observacao', 'parametrizacao_exame.sexo_id', 'profissional.id as profissional_id', 'cadastro_cidadao.nome as profissional_nome', ]); return $rows ->groupBy('solicitacao_id') ->map(fn($group) => [ 'solicitacao_id' => $group->first()->solicitacao_id, 'data_solicitacao' => Carbon::parse($group->first()->data_solicitacao)->format('Y-m-d'), 'profissional_id' => $group->first()->profissional_id, 'profissional_nome' => $group->first()->profissional_nome, 'exames' => $group->map(fn($row) => [ 'exame_item_id' => $row->exame_item_id, 'id' => $row->exame_id, 'codigo' => $row->codigo, 'nome' => $row->nome, 'sigla_exame' => $row->sigla_exame, 'prazo_entrega' => $row->prazo_entrega, 'observacao' => $row->observacao, 'sexo_id' => $row->sexo_id, ])->values()->toArray(), ]) ->values() ->toArray(); } public static function jornadas(): array { self::validarParametrizacaoHabilitada(); request()->validate([ 'coleta_infraestrutura_id' => 'required|integer|exists:cadastro_infraestrutura,id', 'unidade_solicitante_infraestrutura_id' => 'required|integer|exists:cadastro_infraestrutura,id', 'exame_ids' => 'nullable|array', 'exame_ids.*' => 'integer|exists:parametrizacao_exame,id', ]); $coletaInfraId = (int) request()->coleta_infraestrutura_id; $unidadeSolInfraId = (int) request()->unidade_solicitante_infraestrutura_id; $exameIds = request()->exame_ids ?? []; $statusPermitidos = [ StatusAgendamento::AGENDADO, StatusAgendamento::REALIZADO, StatusAgendamento::PENDENTE_ASSINATURA, StatusAgendamento::ASSINADO, StatusAgendamento::NOVA_COLETA, StatusAgendamento::PENDENTE_ENTREGA, StatusAgendamento::ENTREGUE, ]; $agora = now(); $jornadasRaw = DB::table('exame_laboratorial_jornada as jornada') ->where('jornada.infraestrutura_id', $coletaInfraId) ->where('jornada.vagas_app', '>', 0) ->where(function ($q) use ($agora) { $q->whereDate('jornada.data', '>', $agora->toDateString()) ->orWhere(function ($q2) use ($agora) { $q2->whereDate('jornada.data', $agora->toDateString()) ->whereTime('jornada.hora_fim', '>', $agora->format('H:i:s')); }); }) ->whereNull('jornada.deleted_at') ->orderBy('jornada.data') ->orderBy('jornada.hora_inicial') ->get([ 'jornada.id', 'jornada.data', 'jornada.hora_inicial', 'jornada.hora_fim', 'jornada.tempo_atendimento', 'jornada.vagas_app', 'jornada.laboratorio_prestador_infraestrutura_id', ]); $jornadaIds = $jornadasRaw->pluck('id')->toArray(); $consumoPorJornada = DB::table('exame_laboratorial_agendamento as ag') ->join('exame_laboratorial_agendamento_exame as ag_exame', 'ag_exame.agendamento_id', '=', 'ag.id') ->whereIn('ag.jornada_id', $jornadaIds) ->where('ag.app_conectasus_cidadao', true) ->whereIn('ag_exame.status_id', $statusPermitidos) ->groupBy('ag.jornada_id') ->select('ag.jornada_id', DB::raw('COUNT(DISTINCT ag.id) as visitas')) ->get() ->keyBy('jornada_id'); $horariosOcupadosPorJornada = DB::table('exame_laboratorial_agendamento as ag') ->join('exame_laboratorial_agendamento_exame as ag_exame', 'ag_exame.agendamento_id', '=', 'ag.id') ->whereIn('ag.jornada_id', $jornadaIds) ->whereIn('ag_exame.status_id', $statusPermitidos) ->select('ag.jornada_id', DB::raw("DATE_FORMAT(ag.horario, '%H:%i') as horario")) ->distinct() ->get() ->groupBy('jornada_id') ->map(fn($rows) => $rows->pluck('horario')->toArray()); $jornadas = $jornadasRaw->map(function ($jornada) use ($consumoPorJornada, $horariosOcupadosPorJornada) { $consumido = $consumoPorJornada[$jornada->id]->visitas ?? 0; return [ 'jornada_id' => $jornada->id, 'data' => Carbon::parse($jornada->data)->format('Y-m-d'), 'hora_inicial' => Carbon::parse($jornada->hora_inicial)->format('H:i'), 'hora_fim' => Carbon::parse($jornada->hora_fim)->format('H:i'), 'tempo_atendimento' => $jornada->tempo_atendimento, 'vagas_app' => $jornada->vagas_app, 'vagas_app_disponiveis' => max(0, $jornada->vagas_app - $consumido), 'laboratorio_prestador_infraestrutura_id' => $jornada->laboratorio_prestador_infraestrutura_id, 'horarios' => self::gerarHorariosDisponiveis( $jornada->data, $jornada->hora_inicial, $jornada->hora_fim, $jornada->tempo_atendimento, $horariosOcupadosPorJornada[$jornada->id] ?? [] ), ]; })->values()->toArray(); $feriados = Feriado::orderBy('data') ->get() ->map( fn($feriado) => [ 'data' => (new Carbon($feriado->data))->format('Y-m-d'), 'tipo_id' => $feriado->tipo_id, 'tipo_nome' => $feriado->tipo->descricao, 'observacao' => $feriado->observacao, ] ) ->values() ->toArray(); return [ 'jornadas' => $jornadas, 'feriados' => $feriados, 'cotas' => self::computarCotasApp($coletaInfraId, $unidadeSolInfraId, $exameIds), ]; } private static function gerarHorariosDisponiveis( string $data, string $horaInicial, string $horaFim, ?int $tempoAtendimento, array $horariosOcupados ): array { if (!$tempoAtendimento || $tempoAtendimento <= 0) { return []; } $dataStr = Carbon::parse($data)->format('Y-m-d'); $horarioAtual = Carbon::parse($dataStr . ' ' . $horaInicial); $fim = Carbon::parse($dataStr . ' ' . $horaFim); $horarios = []; while ($horarioAtual->lt($fim)) { if ($horarioAtual->isPast()) { $horarioAtual->addMinutes($tempoAtendimento); continue; } $horarioStr = $horarioAtual->format('H:i'); if (!in_array($horarioStr, $horariosOcupados)) { $horarios[] = [ 'horario' => $horarioStr, 'data_hora' => $dataStr . 'T' . $horarioStr . ':00', ]; } $horarioAtual->addMinutes($tempoAtendimento); } return $horarios; } private static function computarCotasApp(int $coletaInfraId, int $unidadeSolInfraId, array $exameIds): array { $hoje = now()->toDateString(); $cotaLaboratorio = null; $labInfraIds = DB::table('exame_laboratorial_jornada') ->where('infraestrutura_id', $coletaInfraId) ->whereNotNull('laboratorio_prestador_infraestrutura_id') ->whereNull('deleted_at') ->distinct() ->pluck('laboratorio_prestador_infraestrutura_id'); foreach ($labInfraIds as $labInfraId) { $cota = DB::table('exame_laboratorial_parametrizacao_cota') ->where('infraestrutura_id', $labInfraId) ->where('unidade_tipo_id', TipoUnidade::LABORATORIO) ->where('cota_tipo_id', TipoCota::QUANTIDADE) ->where('inicio', '<=', $hoje) ->where('fim', '>=', $hoje) ->whereNull('deleted_at') ->first(); $appLab = DB::table('exame_laboratorial_param_app_conectasus_cidadao_laboratorio') ->where('infraestrutura_id', $labInfraId) ->whereNull('deleted_at') ->first(); if (!$cota || !$appLab || $appLab->percentual_quantitativo <= 0) { continue; } $limite = (int) round($cota->cota_quantidade * $appLab->percentual_quantitativo / 100); $consumido = DB::table('exame_laboratorial_agendamento') ->where('laboratorio_infraestrutura_id', $labInfraId) ->where('app_conectasus_cidadao', true) ->where('data', '>=', $cota->inicio) ->where('data', '<=', $cota->fim) ->count(); $cotaLaboratorio = [ 'infraestrutura_id' => $labInfraId, 'percentual_limite' => (float) $appLab->percentual_quantitativo, 'limite_vagas' => $limite, 'consumido' => $consumido, 'percentual_consumido' => $limite > 0 ? round($consumido / $limite * 100, 2) : 0, 'bloqueado' => $consumido >= $limite, ]; break; } $cotasExames = []; foreach ($exameIds as $exameId) { $periodo = DB::table('exame_laboratorial_parametrizacao_cota_exame_periodo') ->where('infraestrutura_id', $coletaInfraId) ->where('exame_id', $exameId) ->where('cota_tipo_id', TipoCota::QUANTIDADE) ->where('inicio', '<=', $hoje) ->where('fim', '>=', $hoje) ->whereNull('deleted_at') ->first(); if (!$periodo) { continue; } $appExame = DB::table('exame_laboratorial_parametrizacao_app_conectasus_cidadao_exame') ->where('cota_exame_periodo_id', $periodo->id) ->whereNull('deleted_at') ->first(); if (!$appExame || $appExame->percentual_quantitativo <= 0) { continue; } $limite = (int) round($periodo->cota_quantidade * $appExame->percentual_quantitativo / 100); $consumido = DB::table('exame_laboratorial_agendamento_exame as ae') ->join('exame_laboratorial_agendamento as ag', 'ag.id', '=', 'ae.agendamento_id') ->where('ae.exame_id', $exameId) ->where('ag.app_conectasus_cidadao', true) ->where('ag.coleta_infraestrutura_id', $coletaInfraId) ->where('ag.data', '>=', $periodo->inicio) ->where('ag.data', '<=', $periodo->fim) ->count(); $cotasExames[] = [ 'exame_id' => (int) $exameId, 'percentual_limite' => (float) $appExame->percentual_quantitativo, 'limite_vagas' => $limite, 'consumido' => $consumido, 'percentual_consumido' => $limite > 0 ? round($consumido / $limite * 100, 2) : 0, 'bloqueado' => $consumido >= $limite, ]; } $cotaUnidadeSolicitante = null; $appSol = DB::table('exame_laboratorial_param_app_conectasus_cidadao_unidade_sol') ->where('infraestrutura_id', $unidadeSolInfraId) ->whereNull('deleted_at') ->first(); if ($appSol && $appSol->percentual_quantitativo > 0) { $cotaSol = DB::table('exame_laboratorial_parametrizacao_cota_unidade_solicitante as sol') ->join('exame_laboratorial_parametrizacao_cota as cota', 'cota.id', '=', 'sol.cota_id') ->where('sol.infraestrutura_solicitante_id', $unidadeSolInfraId) ->where('cota.cota_tipo_id', TipoCota::QUANTIDADE) ->where('cota.inicio', '<=', $hoje) ->where('cota.fim', '>=', $hoje) ->whereNull('cota.deleted_at') ->whereNull('sol.deleted_at') ->first(['sol.cota_quantidade', 'cota.inicio', 'cota.fim']); if ($cotaSol) { $limite = (int) round($cotaSol->cota_quantidade * $appSol->percentual_quantitativo / 100); $consumido = DB::table('exame_laboratorial_agendamento') ->where('infraestrutura_id', $unidadeSolInfraId) ->where('app_conectasus_cidadao', true) ->where('data', '>=', $cotaSol->inicio) ->where('data', '<=', $cotaSol->fim) ->count(); $cotaUnidadeSolicitante = [ 'infraestrutura_id' => $unidadeSolInfraId, 'percentual_limite' => (float) $appSol->percentual_quantitativo, 'limite_vagas' => $limite, 'consumido' => $consumido, 'percentual_consumido' => $limite > 0 ? round($consumido / $limite * 100, 2) : 0, 'bloqueado' => $consumido >= $limite, ]; } } return [ 'laboratorio' => $cotaLaboratorio, 'exames' => $cotasExames, 'unidade_solicitante' => $cotaUnidadeSolicitante, ]; } public static function agendar(): array { self::validarParametrizacaoHabilitada(); request()->validate([ 'jornada_id' => 'required|integer|exists:exame_laboratorial_jornada,id', 'coleta_infraestrutura_id' => 'required|integer|exists:cadastro_infraestrutura,id', 'unidade_solicitante_infraestrutura_id' => 'required|integer|exists:cadastro_infraestrutura,id', 'horario' => 'required|date_format:H:i', 'exames' => 'required|array|min:1', 'exames.*.exame_item_id' => 'required|integer|exists:ambulatorio_atendimento_soap_solicitacao_exame_item,id', 'exames.*.exame_id' => 'required|integer|exists:parametrizacao_exame,id', 'exames.*.profissional_id' => 'required|integer|exists:cadastro_usuario,id', 'observacao' => 'nullable|string', ]); $paciente = auth('mobile')->user(); $jornada = DB::table('exame_laboratorial_jornada') ->where('id', request()->jornada_id) ->whereNull('deleted_at') ->first(); if (!$jornada) { abort(Response::HTTP_NOT_FOUND, 'Jornada não encontrada.'); } $dataJornada = Carbon::parse($jornada->data)->format('Y-m-d'); $horaInicialJornada = Carbon::parse($dataJornada . ' ' . $jornada->hora_inicial); $horaFimJornada = Carbon::parse($dataJornada . ' ' . $jornada->hora_fim); $dataHoraAgendamento = Carbon::parse($dataJornada . ' ' . request()->horario); if ($dataHoraAgendamento->isPast()) { abort(Response::HTTP_UNPROCESSABLE_ENTITY, 'Não é possível agendar em horário retroativo.'); } if ($dataHoraAgendamento->lt($horaInicialJornada) || $dataHoraAgendamento->gte($horaFimJornada)) { abort(Response::HTTP_UNPROCESSABLE_ENTITY, 'O horário informado está fora do intervalo da jornada.'); } self::validarHorarioDisponivel($jornada, request()->horario); $exameIds = collect(request()->exames)->pluck('exame_id')->toArray(); $examesAtivos = DB::table('exame_laboratorial_agendamento_exame as ae') ->leftJoin('parametrizacao_exame as exame', 'exame.id', 'ae.exame_id') ->where('ae.paciente_id', $paciente->id) ->whereIn('ae.exame_id', $exameIds) ->whereIn('ae.status_id', [ StatusAgendamento::AGENDADO, StatusAgendamento::PENDENTE_ASSINATURA, StatusAgendamento::NOVA_COLETA, StatusAgendamento::PENDENTE_ENTREGA, ]) ->get(['ae.exame_id', 'exame.nome as exame_nome']); if ($examesAtivos->isNotEmpty()) { $nomes = $examesAtivos->map(fn($ae) => $ae->exame_nome ?? "Exame #{$ae->exame_id}")->unique()->values(); abort(response()->json([ 'message' => 'Um ou mais exames do pedido já possuem agendamento ativo.', 'exames' => $nomes, ], Response::HTTP_UNPROCESSABLE_ENTITY)); } self::verificarVagasApp($jornada); $coletaUnidadeId = DB::table('cadastro_infraestrutura') ->where('id', request()->coleta_infraestrutura_id) ->value('unidade_id'); $solicitanteUnidadeId = DB::table('cadastro_infraestrutura') ->where('id', request()->unidade_solicitante_infraestrutura_id) ->value('unidade_id'); $labInfraId = $jornada->laboratorio_prestador_infraestrutura_id; $labUnidadeId = $labInfraId ? DB::table('cadastro_infraestrutura')->where('id', $labInfraId)->value('unidade_id') : null; $ultimoNumero = DB::table('exame_laboratorial_agendamento') ->orderByDesc('agendamento_numero') ->value('agendamento_numero'); $agendamentoNumero = $ultimoNumero ? $ultimoNumero + 1 : 1; $agendamento = new Agendamento(); $agendamento->agendamento_numero = $agendamentoNumero; $agendamento->paciente_id = $paciente->id; $agendamento->jornada_id = $jornada->id; $agendamento->medico_id = request()->exames[0]['profissional_id']; $agendamento->data = $jornada->data; $agendamento->horario = request()->horario; $agendamento->unidade_id = $solicitanteUnidadeId; $agendamento->infraestrutura_id = (int) request()->unidade_solicitante_infraestrutura_id; $agendamento->coleta_unidade_id = $coletaUnidadeId; $agendamento->coleta_infraestrutura_id = (int) request()->coleta_infraestrutura_id; $agendamento->laboratorio_unidade_id = $labUnidadeId; $agendamento->laboratorio_infraestrutura_id = $labInfraId; $agendamento->observacao = request()->observacao; $agendamento->app_conectasus_cidadao = true; $agendamento->web_service_laboratorio_cliente_pedido_status_id = PedidoStatus::AGUARDANDO_PROCESSAMENTO; $agendamento->save(); foreach (request()->exames as $exameData) { $exame = new AgendamentoExame(); $exame->agendamento_id = $agendamento->id; $exame->paciente_id = $paciente->id; $exame->exame_id = $exameData['exame_id']; $exame->status_id = StatusAgendamento::AGENDADO; $exame->soap_solicitacao_exame_item_id = $exameData['exame_item_id']; $exame->quantidade = 1; $exame->save(); AtendimentoSoapSolicitacaoExameItem::findOrFail($exameData['exame_item_id']) ->update(['agendado_exame_laboratorial' => true]); AgendamentoExameHistoricoService::store($exame, $agendamento, Acao::INSERCAO); } return [ 'agendamento_id' => $agendamento->id, 'agendamento_numero' => $agendamento->agendamento_numero, ]; } private static function validarHorarioDisponivel(object $jornada, string $horario): void { $statusPermitidos = [ StatusAgendamento::AGENDADO, StatusAgendamento::REALIZADO, StatusAgendamento::PENDENTE_ASSINATURA, StatusAgendamento::ASSINADO, StatusAgendamento::NOVA_COLETA, StatusAgendamento::PENDENTE_ENTREGA, StatusAgendamento::ENTREGUE, ]; $ocupado = DB::table('exame_laboratorial_agendamento as ag') ->join('exame_laboratorial_agendamento_exame as ag_exame', 'ag_exame.agendamento_id', '=', 'ag.id') ->where('ag.jornada_id', $jornada->id) ->whereTime('ag.horario', $horario) ->whereIn('ag_exame.status_id', $statusPermitidos) ->exists(); if ($ocupado) { abort(Response::HTTP_UNPROCESSABLE_ENTITY, 'Este horário não está mais disponível. Selecione outro horário.'); } } private static function verificarVagasApp(object $jornada): void { $statusPermitidos = [ StatusAgendamento::AGENDADO, StatusAgendamento::REALIZADO, StatusAgendamento::PENDENTE_ASSINATURA, StatusAgendamento::ASSINADO, StatusAgendamento::NOVA_COLETA, StatusAgendamento::PENDENTE_ENTREGA, StatusAgendamento::ENTREGUE, ]; $agendamentosApp = DB::table('exame_laboratorial_agendamento as ag') ->join('exame_laboratorial_agendamento_exame as ag_exame', 'ag_exame.agendamento_id', '=', 'ag.id') ->where('ag.jornada_id', $jornada->id) ->where('ag.app_conectasus_cidadao', true) ->whereIn('ag_exame.status_id', $statusPermitidos) ->distinct() ->count('ag.id'); if ($agendamentosApp >= $jornada->vagas_app) { abort(Response::HTTP_UNPROCESSABLE_ENTITY, 'Não há vagas disponíveis para o aplicativo nesta jornada.'); } } private static function validarParametrizacaoHabilitada(): void { $habilitado = DB::table('exame_laboratorial_parametrizacao_integracao_aplicativo') ->value('habilita_agendamento_conectasus_cidadao'); if (!$habilitado) { abort(Response::HTTP_FORBIDDEN, 'O agendamento de exames laboratoriais não está habilitado para o aplicativo.'); } } }