select([ 'painel_senha_fila.id', 'painel_senha_opcao_entrada.id AS opcao_entrada_id', 'painel_senha_opcao_entrada.nome AS opcao_entrada_nome', 'painel_senha_opcao_entrada_destino.id AS opcao_entrada_destino_id', 'painel_senha_status.id AS status_id', 'painel_senha_status.nome AS status_nome', 'painel_senha_prioridade.id AS prioridade_id', 'painel_senha_prioridade.nome AS prioridade_nome', 'cadastro_paciente.id AS paciente_id', 'cadastro_cidadao.nome AS paciente_nome', DB::raw("DATE_FORMAT(cadastro_cidadao.data_nascimento, '%d/%m/%Y') AS paciente_data_nascimento"), DB::raw("LPAD(cadastro_paciente.prontuario, 6, '0') AS paciente_prontuario"), DB::raw("CONCAT(painel_senha_opcao_entrada.sigla, painel_senha_fila.senha) AS senha"), DB::raw("DATE_FORMAT(painel_senha_fila.created_at, '%H:%i') AS horario_chegada"), 'painel_senha_fila.emitido_em', ]) ->addSelect([ 'chamadas' => function ($query) { $query->select(DB::raw("COALESCE(COUNT(painel_senha_chamada.id), 0)")) ->from('painel_senha_chamada') ->whereColumn('painel_senha_chamada.fila_id', 'painel_senha_fila.id') ->whereColumn('painel_senha_chamada.status_id', 'painel_senha_fila.status_id'); }, ]) ->join('painel_senha_opcao_entrada', 'painel_senha_opcao_entrada.id', 'painel_senha_fila.opcao_entrada_id') ->join('painel_senha_status', 'painel_senha_status.id', 'painel_senha_fila.status_id') ->leftJoin('painel_senha_prioridade', 'painel_senha_prioridade.id', 'painel_senha_fila.prioridade_id') ->leftJoin('cadastro_paciente', 'cadastro_paciente.id', 'painel_senha_fila.paciente_id') ->leftJoin('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_paciente.cidadao_id') ->leftJoin('painel_senha_opcao_entrada AS painel_senha_opcao_entrada_destino', 'painel_senha_opcao_entrada_destino.id', 'painel_senha_fila.opcao_entrada_destino_id') ->whereNull('painel_senha_fila.deleted_at') ->where('painel_senha_fila.evadido', false) ->where('painel_senha_fila.finalizado', false) ->where(fn ($q) => $q ->where(fn ($q) => $q ->whereNull('painel_senha_fila.opcao_entrada_destino_id') ->where('painel_senha_opcao_entrada.modulo_id', ModuloService::getId(Modulo::FARMACIA)) ->where(fn ($q) => $q ->where('painel_senha_opcao_entrada.centro_custo_id', $centroCusto->id) ->orWhereExists(fn ($q) => $q->select(DB::raw(1)) ->from('painel_senha_centro_custo_compartilhado') ->where('painel_senha_centro_custo_compartilhado.centro_custo_id', $centroCusto->id) ->whereColumn('painel_senha_centro_custo_compartilhado.opcao_entrada_id', 'painel_senha_opcao_entrada.id') ) ) ) ->orWhere(fn ($q) => $q ->whereNotNull('painel_senha_fila.opcao_entrada_destino_id') ->where('painel_senha_opcao_entrada_destino.modulo_id', ModuloService::getId(Modulo::FARMACIA)) ->where(fn ($q) => $q ->where('painel_senha_opcao_entrada_destino.centro_custo_id', $centroCusto->id) ->orWhereExists(fn ($q) => $q->select(DB::raw(1)) ->from('painel_senha_centro_custo_compartilhado') ->where('painel_senha_centro_custo_compartilhado.centro_custo_id', $centroCusto->id) ->whereColumn('painel_senha_centro_custo_compartilhado.opcao_entrada_id', 'painel_senha_opcao_entrada_destino.id') ) ) ) ) ->orderByDesc('painel_senha_prioridade.grau') ->orderBy('painel_senha_fila.atualizado_em') ->get() ->map(function($query) { $query->tempo_espera = self::getTempoEspera($query->id); $query->paciente_idade = isset($query->paciente_data_nascimento) ? AgeService::getFormattedAge(Carbon::createFromFormat('d/m/Y', $query->paciente_data_nascimento)) : null; return $query; }); } public static function create() { return [ 'form' => [ 'opcoes_entrada' => self::getOpcoesEntrada(), 'prioridades' => self::getPrioridades(), ], 'model' => [ 'paciente_id' => null, 'opcao_entrada_id' => null, 'prioridade_id' => null, ], ]; } public static function createEncaminhamento($filaId) { $fila = Fila::findOrFail($filaId); return [ 'form' => [ 'modulos_encaminhamento' => self::getModulosEncaminhamento($fila), 'centros_custo_encaminhamento' => [], 'opcoes_entrada_encaminhamento' => [], 'prioridades' => Prioridade::orderBy('nome')->get(['id', 'nome']), ], 'model' => [ 'modulo_encaminhamento_id' => null, 'centro_custo_encaminhamento_id' => null, 'opcao_entrada_encaminhamento_id' => null, 'prioridade_id' => $fila->prioridade_id ?? null, ], ]; } public static function listEncaminhamento() { $params = (object) request()->all(); switch (request()->listar) { case 'centros-custo-encaminhamento': { return [ 'centros_custo_encaminhamento' => self::getCentrosCustoEncaminhamento($params), 'opcoes_entrada_encaminhamento' => [], ]; } case 'opcoes-entrada-encaminhamento': { return [ 'opcoes_entrada_encaminhamento' => self::getOpcoesEntradaEncaminhamento($params), ]; } } } private static function getModulosEncaminhamento($fila) { return DB::table('administracao_modulo AS modulo') ->whereExists(fn ($q) => $q ->selectRaw(1) ->from('painel_senha_opcao_entrada AS opcao_entrada') ->join( 'painel_senha_opcao_entrada_destino AS opcao_entrada_destino', 'opcao_entrada_destino.opcao_entrada_destino_id', 'opcao_entrada.id' ) ->whereColumn('opcao_entrada.modulo_id', 'modulo.id') ->where('opcao_entrada_destino.opcao_entrada_origem_id', $fila->opcaoEntradaAtual->id) ) ->select( 'modulo.id', 'modulo.nome' ) ->orderBy('modulo.nome') ->get(); } private static function getCentrosCustoEncaminhamento($params) { return DB::table('cadastro_centro_custo AS centro_custo') ->join('cadastro_setor AS setor', 'setor.id', 'centro_custo.setor_id') ->whereExists(fn ($q) => $q ->selectRaw(1) ->from('painel_senha_opcao_entrada AS opcao_entrada') ->join( 'painel_senha_opcao_entrada_destino AS opcao_entrada_destino', 'opcao_entrada_destino.opcao_entrada_destino_id', 'opcao_entrada.id' ) ->whereColumn('opcao_entrada.centro_custo_id', 'centro_custo.id') ->where('opcao_entrada_destino.opcao_entrada_origem_id', $params->opcao_entrada_origem_id) ->where('opcao_entrada.modulo_id', $params->modulo_id) ) ->select( 'centro_custo.id', 'setor.nome AS setor_nome' ) ->orderBy('setor.nome') ->get(); } private static function getOpcoesEntradaEncaminhamento($params) { return DB::table('painel_senha_opcao_entrada AS opcao_entrada') ->join( 'painel_senha_opcao_entrada_destino AS opcao_entrada_destino', 'opcao_entrada_destino.opcao_entrada_destino_id', 'opcao_entrada.id' ) ->where('opcao_entrada_destino.opcao_entrada_origem_id', $params->opcao_entrada_origem_id) ->where('opcao_entrada.modulo_id', $params->modulo_id) ->where('opcao_entrada.centro_custo_id', $params->centro_custo_id) ->select( 'opcao_entrada.id', 'opcao_entrada.nome', 'opcao_entrada.prioridade_obrigatoria' ) ->orderBy('opcao_entrada.nome') ->get(); } public static function store() { self::validateStore(); $centroCusto = self::getCurrentCentroCusto(); $senha = ( Fila::where('opcao_entrada_id', request()->opcao_entrada_id) ->whereRaw('emitido_em = CURRENT_DATE') ->max('senha') ?? 0 ) + 1; $fila = Fila::create([ 'paciente_id' => request()->paciente_id, 'centro_custo_id' => $centroCusto->id, 'opcao_entrada_id' => request()->opcao_entrada_id, 'prioridade_id' => request()->prioridade_id, 'status_id' => Status::EM_ESPERA, 'senha' => $senha, ]); self::dispatch($fila->opcaoEntradaAtual->id, $fila->centro_custo_id); return [$fila, Response::HTTP_CREATED]; } public static function edit($id) { $fila = Fila::findOrFail($id); return [ 'form' => [ 'opcoes_entrada' => self::getOpcoesEntrada(), 'prioridades' => self::getPrioridades(), ], 'model' => [ 'id' => $fila->id, 'paciente' => $fila->paciente ? [ 'id' => $fila->paciente->id, 'nome' => $fila->paciente->cidadao->nome, 'cns' => $fila->paciente->cidadao->cns, ] : null, 'opcao_entrada_id' => $fila->opcao_entrada_id, 'prioridade_id' => $fila->prioridade_id, ], ]; } public static function update($id) { self::validateUpdate(); $fila = Fila::findOrFail($id); $fila->update([ 'paciente_id' => request()->paciente_id, 'prioridade_id' => request()->prioridade_id, ]); self::dispatch($fila->opcaoEntradaAtual->id, $fila->centro_custo_id); return $fila->fresh(); } public static function list() { return [ 'form' => [ 'tempos_espera' => self::getTemposEspera(), 'opcoes_entrada' => self::getOpcoesEntrada(), 'prioridades' => self::getPrioridades(), 'status' => self::getStatus(), 'salas' => self::getSalas(), 'telas' => self::getTelas(), ], 'model' => [ 'tempo_espera_id' => null, 'opcao_entrada_id' => null, 'prioridade_id' => null, 'status_id' => Status::EM_ESPERA, 'fila' => self::index(), ], ]; } public static function autocompletePaciente() { return DB::table('cadastro_paciente') ->select([ 'cadastro_paciente.id', 'cadastro_cidadao.nome', 'cadastro_cidadao.cns', ]) ->join('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_paciente.cidadao_id'); } public static function evade($id) { $fila = Fila::findOrFail($id); self::validateEvade(); $fila->update([ 'evadido' => true, 'motivo_evasao' => request()->motivo, 'motivo_cancelamento_evasao' => null, 'finalizado' => true, ]); self::dispatch($fila->opcaoEntradaAtual->id, $fila->centro_custo_id); } public static function answer($id) { $fila = Fila::findOrFail($id); $fila->update(['status_id' => Status::EM_ATENDIMENTO]); self::dispatch($fila->opcaoEntradaAtual->id, $fila->centro_custo_id); } public static function sendBack($id) { $fila = Fila::findOrFail($id); $fila->update(['status_id' => Status::EM_ESPERA]); self::dispatch($fila->opcaoEntradaAtual->id, $fila->centro_custo_id); } public static function forward($id) { $fila = Fila::findOrFail($id); self::validateForward(); $opcaoEntradaFrom = $fila->opcaoEntradaAtual; $centroCustoFrom = CentroCusto::findOrFail($fila->centro_custo_id); $opcaoEntradaTo = OpcaoEntrada::findOrFail(request()->opcao_entrada_encaminhamento_id); $centroCustoTo = $opcaoEntradaTo->centroCusto; $fila->update([ 'centro_custo_id' => $centroCustoTo->id, 'opcao_entrada_destino_id' => $opcaoEntradaTo->id, 'prioridade_id' => request()->prioridade_id, 'status_id' => Status::EM_ESPERA, ]); self::dispatch($opcaoEntradaFrom->id, $centroCustoFrom->id); if ($opcaoEntradaTo->modulo_id === ModuloService::getId(Modulo::PAINEL_SENHA)) { PainelSenhaFilaAtendimentoService::dispatch($opcaoEntradaTo->id, $centroCustoTo->id); } else if ($opcaoEntradaTo->modulo_id === ModuloService::getId(Modulo::FARMACIA)) { self::dispatch($opcaoEntradaTo->id, $centroCustoTo->id); } else if ($opcaoEntradaTo->modulo_id === ModuloService::getId(Modulo::IMUNIZACAO)) { ImunizacaoFilaAtendimentoService::dispatch($opcaoEntradaTo->id, $centroCustoTo->id); } } public static function finalize($id) { $fila = Fila::findOrFail($id); $fila->update(['finalizado' => true]); self::dispatch($fila->opcaoEntradaAtual->id, $fila->centro_custo_id); } public static function dispatch($opcaoEntradaId, $centroCustoId) { $centroCusto = CentroCusto::findOrFail($centroCustoId); FilaEvent::dispatch( $centroCusto->setor->tipo_id, $centroCusto->id, Modulo::FARMACIA, self::index($centroCusto) ); CentroCustoCompartilhado::where('opcao_entrada_id', $opcaoEntradaId) ->get() ->each(function ($item) { $centroCusto = CentroCusto::findOrFail($item->centro_custo_id); FilaEvent::dispatch( $centroCusto->setor->tipo_id, $centroCusto->id, Modulo::FARMACIA, self::index($centroCusto) ); }); CentroCustoCompartilhado::where('centro_custo_id', $centroCustoId) ->get() ->each(function ($item) { $centroCusto = OpcaoEntrada::findOrFail($item->opcao_entrada_id)->centroCusto; FilaEvent::dispatch( $centroCusto->setor->tipo_id, $centroCusto->id, Modulo::FARMACIA, self::index($centroCusto) ); }); } private static function validateStore() { request()->validate([ 'paciente_id' => [ 'nullable', 'integer', Rule::exists(Paciente::class, 'id'), ], 'opcao_entrada_id' => [ 'required', 'integer', Rule::exists(OpcaoEntrada::class, 'id'), ], 'prioridade_id' => [ 'nullable', Rule::requiredIf(fn () => OpcaoEntrada::find(request()->opcao_entrada_id) ->prioridade_obrigatoria ?? false ), Rule::exists(Prioridade::class, 'id'), ], ]); } private static function validateUpdate() { request()->validate([ 'paciente_id' => [ 'required', 'integer', Rule::exists(Paciente::class, 'id'), ], 'prioridade_id' => [ 'nullable', Rule::requiredIf(fn () => OpcaoEntrada::find(request()->opcao_entrada_id) ->prioridade_obrigatoria ?? false ), Rule::exists(Prioridade::class, 'id'), ], ]); } private static function validateForward() { request()->validate([ 'opcao_entrada_encaminhamento_id' => [ 'required', 'integer', Rule::exists(OpcaoEntrada::class, 'id'), ], 'prioridade_id' => [ 'nullable', Rule::requiredIf(fn () => OpcaoEntrada::find(request()->opcao_entrada_encaminhamento_id) ->prioridade_obrigatoria ?? false ), Rule::exists(Prioridade::class, 'id'), ], ]); } private static function validateEvade() { request()->validate([ 'motivo' => [ 'nullable', 'string', 'max:500', ], ]); } private static function getTempoEspera($filaId) { $tempoEsperaTotal = DB::table('painel_senha_fila_historico') ->select( 'painel_senha_fila_historico.created_at', 'painel_senha_status.id AS status_id' ) ->join('painel_senha_status', 'painel_senha_status.id', 'painel_senha_fila_historico.status_id') ->where('painel_senha_fila_historico.fila_id', $filaId) ->distinct() ->get() ->reduce(function ($count, $query) use ($filaId) { if ($query->status_id === Status::EM_ESPERA) { $proximo = DB::table('painel_senha_fila_historico') ->where('fila_id', $filaId) ->where('created_at', '>', $query->created_at) ->select('created_at') ->first(); return $count + Carbon::create($query->created_at)->diffInMinutes($proximo->created_at ?? Carbon::now()); } return $count; }, 1); $centroCustoLogado = self::getCurrentCentroCusto(); $tempoEspera = DB::table('painel_senha_tempo_espera') ->select( 'id', 'cor' ) ->whereNull('deleted_at') ->where('tempo', '<=', $tempoEsperaTotal) ->where('infraestrutura_id', $centroCustoLogado->infraestrutura_id) ->orderByDesc('tempo') ->first(); if (is_null($tempoEspera)) { $tempoEspera = DB::table('painel_senha_tempo_espera') ->select( 'id', 'cor' ) ->whereNull('deleted_at') ->where('tempo', '>=', $tempoEsperaTotal) ->where('infraestrutura_id', $centroCustoLogado->infraestrutura_id) ->orderBy('tempo') ->first(); } $tempoEsperaTotal = Carbon::now()->subMinutes($tempoEsperaTotal)->diff(Carbon::now()); return [ 'id' => $tempoEspera->id ?? null, 'cor' => $tempoEspera->cor ?? null, 'total' => [ 'dias' => (int) $tempoEsperaTotal->format('%d') > 0 ? (int) $tempoEsperaTotal->format('%d') : null, 'horas' => (int) $tempoEsperaTotal->format('%h') ?? null, 'minutos' => (int) $tempoEsperaTotal->format('%i') ?? null, ], ]; } private static function getTemposEspera() { return DB::table('painel_senha_tempo_espera') ->select([ 'painel_senha_tempo_espera.id', DB::raw("CONCAT(painel_senha_tempo_espera.tempo, ' MINUTO(S)') AS minutos"), ]) ->whereNull('painel_senha_tempo_espera.deleted_at') ->whereExists(fn ($q) => $q->select(DB::raw(1)) ->from('cadastro_infraestrutura') ->whereNull('cadastro_infraestrutura.deleted_at') ->whereExists(fn ($q) => $q->select(DB::raw(1)) ->from('cadastro_centro_custo') ->whereNull('cadastro_centro_custo.deleted_at') ->where('cadastro_centro_custo.id', self::getCurrentCentroCusto()->id) ->whereColumn('cadastro_centro_custo.infraestrutura_id', 'cadastro_infraestrutura.id') ) ->whereColumn('cadastro_infraestrutura.id', 'painel_senha_tempo_espera.infraestrutura_id') ) ->orderBy('painel_senha_tempo_espera.tempo') ->get(); } private static function getOpcoesEntrada() { $centroCusto = self::getCurrentCentroCusto(); return DB::table('painel_senha_opcao_entrada') ->select([ 'painel_senha_opcao_entrada.id', 'painel_senha_opcao_entrada.nome', 'painel_senha_opcao_entrada.prioridade_obrigatoria', ]) ->whereNull('painel_senha_opcao_entrada.deleted_at') ->where('painel_senha_opcao_entrada.modulo_id', ModuloService::getId(Modulo::FARMACIA)) ->where(fn ($q) => $q->where('painel_senha_opcao_entrada.centro_custo_id', $centroCusto->id) ->orWhereExists(fn ($q) => $q->select(DB::raw(1)) ->from('painel_senha_centro_custo_compartilhado') ->where('painel_senha_centro_custo_compartilhado.centro_custo_id', $centroCusto->id) ->whereColumn('painel_senha_centro_custo_compartilhado.opcao_entrada_id', 'painel_senha_opcao_entrada.id') ) ) ->orderBy('painel_senha_opcao_entrada.nome') ->get(); } private static function getPrioridades() { return DB::table('painel_senha_prioridade') ->select([ 'painel_senha_prioridade.id', 'painel_senha_prioridade.nome', ]) ->orderBy('painel_senha_prioridade.nome') ->get(); } private static function getStatus() { return DB::table('painel_senha_status') ->select([ 'id', 'nome', ]) ->orderBy('painel_senha_status.nome') ->get(); } private static function getSalas() { return DB::table('cadastro_sala') ->select([ 'cadastro_sala.id', 'cadastro_sala.nome', ]) ->whereNull('cadastro_sala.deleted_at') ->where('centro_custo_id', self::getCurrentCentroCusto()->id) ->orderBy('cadastro_sala.nome') ->get(); } private static function getTelas() { return DB::table('painel_senha_tela') ->select([ 'painel_senha_tela.id', 'painel_senha_tela.nome', ]) ->whereNull('painel_senha_tela.deleted_at') ->whereExists(fn ($q) => $q->select(DB::raw(1)) ->from('painel_senha_opcao_chamada') ->whereNull('painel_senha_opcao_chamada.deleted_at') ->where('painel_senha_opcao_chamada.centro_custo_id', self::getCurrentCentroCusto()->id) ->whereColumn('painel_senha_opcao_chamada.tela_id', 'painel_senha_tela.id') ) ->orderBy('painel_senha_tela.nome') ->get(); } }