join( 'cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_usuario.cidadao_id' ) ->whereNull('cadastro_usuario.deleted_at') ->select(DB::raw(" cadastro_usuario.id, cadastro_cidadao.nome, DATE_FORMAT(cadastro_cidadao.data_nascimento, '%d/%m/%Y') as data_nascimento, CONCAT( SUBSTR(cadastro_cidadao.cpf,1,3), '.', SUBSTR(cadastro_cidadao.cpf,4,3), '.', SUBSTR(cadastro_cidadao.cpf,7,3), '-', SUBSTR(cadastro_cidadao.cpf,10,2) ) AS cpf, cadastro_cidadao.cns ")); return datatables() ->of($usuarios) ->filterColumn('cadastro_cidadao.data_nascimento', function ($query, $keyword) { $query->whereRaw("DATE_FORMAT(cadastro_cidadao.data_nascimento, '%d/%m/%Y') LIKE ?", ["%{$keyword}%"]) ->orWhereRaw( "CONCAT( SUBSTR(cadastro_cidadao.data_nascimento,9,2), SUBSTR(cadastro_cidadao.data_nascimento,6,2), SUBSTR(cadastro_cidadao.data_nascimento,1,4) ) like ?", ["%{$keyword}%"] ); }) ->filterColumn('cadastro_cidadao.cpf', function ($query, $keyword) { $query->whereRaw("cadastro_cidadao.cpf LIKE ?", ["%{$keyword}%"]) ->orWhereRaw( "CONCAT( SUBSTR(cadastro_cidadao.cpf,1,3), '.', SUBSTR(cadastro_cidadao.cpf,4,3), '.', SUBSTR(cadastro_cidadao.cpf,7,3), '-', SUBSTR(cadastro_cidadao.cpf,10,2) ) LIKE ?", ["%{$keyword}%"] ); }) ->addColumn('cns_valido', fn ($usuario) => Cns::isValid($usuario->cns)) ->skipTotalRecords() ->toJson(); } public static function index() { $statusAgendado = AgendamentoStatus::AGENDADO; $jornadas = DB::table('ambulatorio_jornada as jornada') ->join( 'ambulatorio_jornada_tipo as tipo', 'tipo.id', 'jornada.tipo_id' ) ->join( 'cadastro_lotacao as lotacao', 'lotacao.id', 'jornada.lotacao_id' ) ->join( 'sigtap.ocupacao as ocupacao', 'ocupacao.id', 'lotacao.ocupacao_id' ) ->join( 'cadastro_especialidade as especialidade', 'especialidade.id', 'jornada.especialidade_id' ) ->join( 'cadastro_infraestrutura as infraestrutura', 'infraestrutura.id', 'lotacao.infraestrutura_id' ) ->join( 'cadastro_unidade as unidade', 'unidade.id', 'infraestrutura.unidade_id' ) ->join( 'geral_dia_semana as dia_semana', 'dia_semana.id', DB::raw("DAYOFWEEK(jornada.data)") ) ->leftJoin( 'ambulatorio_jornada_situacao as situacao', 'situacao.id', 'jornada.situacao_id' ) ->leftJoin( 'ambulatorio_agendamento as agendamento', 'agendamento.jornada_id', 'jornada.id' ) ->where('lotacao.usuario_id', request()->usuario_id) ->whereBetween('jornada.data', [ Carbon::createFromFormat('d/m/Y', request()->periodo['start'])->format('Y-m-d'), Carbon::createFromFormat('d/m/Y', request()->periodo['end'])->format('Y-m-d') ]) ->when(!is_null(request()->inicio) && !is_null(request()->fim), fn ($q) => $q ->where(fn ($q) => $q ->where(fn ($q) => $q ->where('jornada.inicio', '<=', request()->inicio) ->where('jornada.fim', '>=', request()->inicio) ) ->orWhere(fn ($q) => $q ->where('jornada.inicio', '<=', request()->fim) ->where('jornada.fim', '>=', request()->fim) ) ->orWhere(fn ($q) => $q ->where('jornada.inicio', '>=', request()->inicio) ->where('jornada.inicio', '<=', request()->fim) ) ->orWhere(fn ($q) => $q ->where('jornada.fim', '>=', request()->inicio) ->where('jornada.fim', '<=', request()->fim) ) ) ) ->when(!empty(request()->dias_semana), fn ($q) => $q ->whereRaw("DAYOFWEEK(jornada.data) IN (" . collect(request()->dias_semana)->join(',') . ")") ) ->when(request()->unidade_id, fn ($q, $id) => $q->where('unidade.id', $id)) ->when(request()->infraestrutura_id, fn ($q, $id) => $q->where('infraestrutura.id', $id)) ->when(request()->ocupacao_id, fn ($q, $id) => $q->where('ocupacao.id', $id)) ->when(request()->especialidade_id, fn ($q, $id) => $q->where('especialidade.id', $id)) ->when(request()->tipo_id, fn ($q, $id) => $q->where('tipo.id', $id)) ->when(DataUtil::isStringBoolean(request()->ativa), fn ($q) => $q ->when(DataUtil::isStringTrue(request()->ativa), fn ($q) => $q->whereNull('jornada.situacao_id'), fn ($q) => $q->whereNotNull('jornada.situacao_id') ->when(request()->situacao_id, fn ($q, $id) => $q->where('situacao.id', $id)) ) ) ->when(request()->quantidade_consulta, fn ($q, $quantidade) => $q ->where('jornada.quantidade_consulta', $quantidade)) ->when(request()->quantidade_retorno, fn ($q, $quantidade) => $q ->where('jornada.quantidade_retorno', $quantidade)) ->when(request()->conectasus_cidadao === 'sim', fn ($q) => $q ->where(fn ($q) => $q ->where('especialidade.permite_integracao_conectasus_cidadao', 1) )) ->when(request()->conectasus_cidadao === 'nao', fn ($q) => $q ->where(fn ($q) => $q ->where(fn ($q) => $q ->where('especialidade.permite_integracao_conectasus_cidadao', 0) ) )) ->select(DB::raw(" jornada.id, unidade.nome_fantasia as unidade_nome_fantasia, COALESCE(infraestrutura.nome, unidade.nome_fantasia) as infraestrutura_nome, jornada.lotacao_id, CONCAT(ocupacao.codigo, ' - ', ocupacao.nome) as ocupacao_descricao, especialidade.id as especialidade_id, especialidade.nome as especialidade_nome, jornada.tipo_id, tipo.nome as tipo_nome, jornada.data, dia_semana.descricao as dia_semana, DATE_FORMAT(jornada.inicio, '%H:%i') as inicio, DATE_FORMAT(jornada.fim, '%H:%i') as fim, jornada.situacao_id, situacao.nome as situacao_nome, COALESCE(jornada.quantidade_consulta, 0) as quantidade_consulta, COALESCE(jornada.tempo_consulta, 0) as tempo_consulta, COALESCE(jornada.quantidade_retorno, 0) as quantidade_retorno, COALESCE(jornada.tempo_retorno, 0) as tempo_retorno, COALESCE(jornada.quantidade_consulta_conectasus_cidadao, 0) as quantidade_consulta_conectasus_cidadao, COALESCE(jornada.tempo_consulta_conectasus_cidadao, 0) as tempo_consulta_conectasus_cidadao, COALESCE(jornada.quantidade_retorno_conectasus_cidadao, 0) as quantidade_retorno_conectasus_cidadao, COALESCE(jornada.tempo_retorno_conectasus_cidadao, 0) as tempo_retorno_conectasus_cidadao, jornada.permite_agendamento_somente_supervisor, COUNT(CASE WHEN agendamento.status_id = $statusAgendado THEN agendamento.id END) as total_agendamentos ")) ->addSelect([ 'tem_agendamentos' => function ($query) use($statusAgendado) { $query->select(DB::raw(1)) ->from('ambulatorio_agendamento as agendamento') ->whereColumn('agendamento.jornada_id', 'jornada.id') ->limit(1); } ]) ->groupBy('jornada.id') ->get(); $jornadas->each(function ($jornada) { $jornada->tem_agendamentos = !is_null($jornada->tem_agendamentos); }); return $jornadas; } public static function create() { switch (request()->origem) { case 'busca': { $usuario = Usuario::findOrFail(request()->usuario_id); return [ 'form' => [ 'usuario' => [ 'nome' => $usuario->cidadao->nome, 'data_nascimento' => is_null($usuario->cidadao->data_nascimento) ? null : (new Carbon($usuario->cidadao->data_nascimento))->format('d/m/Y'), 'cns' => MaskUtil::getCnsMasked($usuario->cidadao->cns), 'cpf' => MaskUtil::getCpfMasked($usuario->cidadao->cpf), ], 'busca' => [ 'dias_semana' => self::getDiasSemana(), 'unidades' => [], 'infraestruturas' => [], 'ocupacoes' => [], 'especialidades' => [], 'tipos' => [], 'situacoes' => [], ], 'atribuicao' => [ 'unidades' => self::getCadastroUnidades(['usuario_id' => request()->usuario_id]), 'infraestruturas' => [], 'lotacoes' => [], 'especialidades' => [], 'tipos' => self::getCadastroJornadaTipos(), 'situacoes' => self::getCadastroJornadaSituacoes(), ], ], 'model' => [ 'busca' => [ 'periodo' => [ 'start' => null, 'end' => null, ], 'inicio' => null, 'fim' => null, 'dias_semana' => [], 'unidade_id' => null, 'infraestrutura_id' => null, 'ocupacao_id' => null, 'especialidade_id' => null, 'tipo_id' => null, 'ativa' => null, 'situacao_id' => null, 'quantidade_consulta' => null, 'quantidade_retorno' => null, 'conectasus_cidadao' => null, ], 'atribuicao' => [ 'unidade_id' => null, 'infraestrutura_id' => null, 'lotacao_id' => null, 'especialidade_id' => null, 'tipo_id' => null, 'inicio' => null, 'fim' => null, 'situacao_id' => null, 'quantidade_consulta' => null, 'tempo_consulta' => null, 'quantidade_retorno' => null, 'tempo_retorno' => null, 'quantidade_consulta_conectasus_cidadao' => 0, 'tempo_consulta_conectasus_cidadao' => null, 'quantidade_retorno_conectasus_cidadao' => 0, 'tempo_retorno_conectasus_cidadao' => null, 'permite_agendamento_somente_supervisor' => null, ], ], ]; } case 'cadastro': { return [ 'additionals' => [ 'tem_agendamentos' => false, ], 'form' => [ 'unidades' => self::getCadastroUnidades(['usuario_id' => request()->usuario_id]), 'infraestruturas' => [], 'lotacoes' => [], 'especialidades' => [], 'tipos' => self::getCadastroJornadaTipos(), 'dias_semana' => self::getDiasSemana(), 'situacoes' => self::getCadastroJornadaSituacoes(), 'equipes' => self::getAtencaoBasicaEquipes(['usuario_id' => request()->usuario_id]), ], 'model' => [ 'unidade_id' => null, 'infraestrutura_id' => null, 'lotacao_id' => null, 'especialidade_id' => null, 'tipo_id' => null, 'periodo' => [ 'start' => null, 'end' => null, ], 'inicio' => null, 'fim' => null, 'dias_semana' => [], 'situacao_id' => null, 'quantidade_consulta' => null, 'tempo_consulta' => null, 'quantidade_retorno' => null, 'tempo_retorno' => null, 'quantidade_consulta_conectasus_cidadao' => 0, 'tempo_consulta_conectasus_cidadao' => null, 'quantidade_retorno_conectasus_cidadao' => 0, 'tempo_retorno_conectasus_cidadao' => null, 'permite_agendamento_somente_supervisor' => false, ], ]; } } } public static function edit($id) { $jornada = Jornada::findOrFail($id); return [ 'additionals' => [ 'tem_agendamentos' => $jornada->agendamentos()->whereIn('ambulatorio_agendamento.status_id', [1, 6, 7, 8])->exists(), 'quantidade_agendamentos' => $jornada->agendamentos()->whereIn('ambulatorio_agendamento.status_id', [1, 6, 7, 8])->count(), ], 'form' => [ 'unidades' => self::getCadastroUnidades(['usuario_id' => $jornada->lotacao->usuario_id]), 'infraestruturas' => self::getCadastroInfraestruturas([ 'usuario_id' => $jornada->lotacao->usuario_id, 'unidade_id' => $jornada->lotacao->infraestrutura->unidade_id, ]), 'lotacoes' => self::getCadastroLotacoes([ 'usuario_id' => $jornada->lotacao->usuario_id, 'infraestrutura_id' => $jornada->lotacao->infraestrutura_id, ]), 'especialidades' => self::getCadastroEspecialidades([ 'lotacao_id' => $jornada->lotacao_id, ]), 'tipos' => self::getCadastroJornadaTipos(), 'dias_semana' => self::getDiasSemana(), 'situacoes' => self::getCadastroJornadaSituacoes(), 'equipes' => self::getAtencaoBasicaEquipes(['usuario_id' => $jornada->lotacao->usuario_id]), ], 'model' => [ 'unidade_id' => $jornada->lotacao->infraestrutura->unidade_id, 'infraestrutura_id' => $jornada->lotacao->infraestrutura_id, 'lotacao_id' => $jornada->lotacao_id, 'especialidade_id' => $jornada->especialidade_id, 'tipo_id' => $jornada->tipo_id, 'periodo' => [ 'start' => $jornada->data->format('d/m/Y'), 'end' => $jornada->data->format('d/m/Y'), ], 'inicio' => $jornada->inicio->format('H:i'), 'fim' => $jornada->fim->format('H:i'), 'dia_semana' => $jornada->dia_semana, 'situacao_id' => $jornada->situacao_id, 'quantidade_consulta' => $jornada->quantidade_consulta, 'tempo_consulta' => $jornada->tempo_consulta, 'quantidade_retorno' => $jornada->quantidade_retorno, 'tempo_retorno' => $jornada->tempo_retorno, 'quantidade_consulta_conectasus_cidadao' => $jornada->quantidade_consulta_conectasus_cidadao ?? 0, 'tempo_consulta_conectasus_cidadao' => $jornada->tempo_consulta_conectasus_cidadao, 'quantidade_retorno_conectasus_cidadao' => $jornada->quantidade_retorno_conectasus_cidadao ?? 0, 'tempo_retorno_conectasus_cidadao' => $jornada->tempo_retorno_conectasus_cidadao, 'permite_agendamento_somente_supervisor' => $jornada->permite_agendamento_somente_supervisor, ], ]; } public static function list() { $params = request()->all(); switch (request()->origem) { case 'busca': { switch (request()->listar) { case 'unidades': { return [ 'unidades' => self::getBuscaUnidades($params), 'infraestruturas' => [], 'ocupacoes' => self::getBuscaOcupacoes($params), 'especialidades' => [], 'tipos' => self::getBuscaJornadaTipos($params), 'situacoes' => self::getBuscaJornadaSituacoes($params), ]; } case 'infraestruturas': { return [ 'infraestruturas' => self::getBuscaInfraestruturas($params), 'ocupacoes' => self::getBuscaOcupacoes($params), 'especialidades' => [], 'tipos' => self::getBuscaJornadaTipos($params), 'situacoes' => self::getBuscaJornadaSituacoes($params), ]; } case 'ocupacoes': { return [ 'ocupacoes' => self::getBuscaOcupacoes($params), 'especialidades' => [], 'tipos' => self::getBuscaJornadaTipos($params), 'situacoes' => self::getBuscaJornadaSituacoes($params), ]; } case 'especialidades': { return [ 'especialidades' => self::getBuscaEspecialidades($params), 'tipos' => self::getBuscaJornadaTipos($params), 'situacoes' => self::getBuscaJornadaSituacoes($params), ]; } case 'tipos': { return [ 'tipos' => self::getBuscaJornadaTipos($params), 'situacoes' => self::getBuscaJornadaSituacoes($params), ]; } case 'situacoes': { return [ 'situacoes' => self::getBuscaJornadaSituacoes($params), ]; } } break; } case 'cadastro': { switch (request()->listar) { case 'infraestruturas': { return self::getCadastroInfraestruturas($params); } case 'lotacoes': { return self::getCadastroLotacoes($params); } case 'especialidades': { return self::getCadastroEspecialidades($params); } } break; } } } private static function getAtencaoBasicaEquipes($params) { return DB::table('atencao_basica_parametrizacao_equipe_usuario as equipe_usuario') ->where('equipe_usuario.usuario_id', $params['usuario_id']) ->where('equipe_usuario.ativo', true) ->join('atencao_basica_parametrizacao_equipe as parametrizacao_equipe', 'parametrizacao_equipe.id', 'equipe_usuario.equipe_id') ->join('atencao_basica_parametrizacao_area as parametrizacao_area', 'parametrizacao_area.id', 'parametrizacao_equipe.area_id') ->leftJoin('atencao_basica_parametrizacao_area_tipo as parametrizacao_area_tipo', 'parametrizacao_area_tipo.id', 'parametrizacao_area.tipo_id') ->leftJoin('atencao_basica_parametrizacao_microarea as parametrizacao_microarea', 'parametrizacao_microarea.id', 'parametrizacao_equipe.microarea_id') ->join('cadastro_unidade as unidade', 'unidade.id', 'parametrizacao_equipe.unidade_id') ->join('cadastro_infraestrutura as infraestrutura', 'infraestrutura.id', 'parametrizacao_equipe.infraestrutura_id') ->get([ 'equipe_usuario.equipe_id', 'parametrizacao_area.numero_ine as area_numero_ine', 'parametrizacao_area.descricao as area_descricao', 'parametrizacao_area_tipo.sigla as area_tipo_sigla', 'parametrizacao_area_tipo.descricao as area_tipo_descricao', 'parametrizacao_microarea.descricao as microarea_descricao', 'unidade.nome_fantasia as unidade_nome', 'infraestrutura.nome as infraestrutura_nome', 'parametrizacao_equipe.microarea_id as microarea_id', ]) ->map(fn ($equipe) => [ 'id' => $equipe->equipe_id, 'ine' => $equipe->area_numero_ine, 'tipo' => $equipe->area_tipo_sigla . ' - ' . $equipe->area_tipo_descricao, 'area' => $equipe->area_descricao, 'microarea' => $equipe->microarea_id ? $equipe->microarea_descricao : 'Não informada', 'unidade' => $equipe->unidade_nome, 'infraestrutura' => $equipe->infraestrutura_nome ?? $equipe->unidade_nome, ]); } private static function getBuscaUnidades($params) { return Unidade::whereHas('infraestruturas', fn ($q) => $q ->whereHas('lotacoes', fn ($q) => $q ->where('usuario_id', $params['usuario_id']) ->whereHas('ambulatorioJornadas', fn ($q) => self::setBuscaWhereJornadas($q, $params) ) ) ) ->orderBy('nome_fantasia') ->get(['id', 'nome_fantasia']); } private static function getBuscaInfraestruturas($params) { if (is_null($params['unidade_id'])) { return []; } return Infraestrutura::setEagerLoads([]) ->where('unidade_id', $params['unidade_id']) ->whereHas('lotacoes', fn ($q) => $q ->where('usuario_id', $params['usuario_id']) ->whereHas('ambulatorioJornadas', fn ($q) => self::setBuscaWhereJornadas($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') ->where('lotacao.usuario_id', $params['usuario_id']) ->when($params['infraestrutura_id'], fn ($q, $id) => $q->where('lotacao.infraestrutura_id', $id)) ->when($params['unidade_id'], fn ($q, $id) => $q->where('infraestrutura.unidade_id', $id)) ->whereExists(function ($query) use ($params) { $query->select(DB::raw(1)) ->from('ambulatorio_jornada as jornada') ->whereColumn('jornada.lotacao_id', 'lotacao.id') ->whereBetween('jornada.data', [ Carbon::createFromFormat('d/m/Y', $params['periodo']['start'])->format('Y-m-d'), Carbon::createFromFormat('d/m/Y', $params['periodo']['end'])->format('Y-m-d') ]) ->when(!is_null($params['inicio']) && !is_null($params['fim']), fn ($q) => $q ->where(fn ($q) => $q ->where('jornada.inicio', '<=', $params['inicio']) ->where('jornada.fim', '>=', $params['inicio']) ) ->orWhere(fn ($q) => $q ->where('jornada.inicio', '<=', $params['fim']) ->where('jornada.fim', '>=', $params['fim']) ) ->orWhere(fn ($q) => $q ->where('jornada.inicio', '>=', $params['inicio']) ->where('jornada.inicio', '<=', $params['fim']) ) ->orWhere(fn ($q) => $q ->where('jornada.fim', '>=', $params['inicio']) ->where('jornada.fim', '<=', $params['fim']) ) ) ->when(!empty($params['dias_semana']), fn ($q) => $q ->whereRaw("DAYOFWEEK(jornada.data) IN (" . collect($params['dias_semana'])->join(',') . ")") ); }); }) ->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) => self::setBuscaWhereJornadas($q, $params) ->whereHas('lotacao', fn ($q) => $q ->where('usuario_id', $params['usuario_id']) ->where('ocupacao_id', $params['ocupacao_id']) ->when($params['infraestrutura_id'], fn ($q, $id) => $q->where('infraestrutura_id', $id), fn ($q) => $q ->when($params['unidade_id'], fn ($q, $id) => $q ->whereHas('infraestrutura', fn ($q) => $q ->where('unidade_id', $id) ) ) ) ) ) ->when($params['conectasus_cidadao'] === 'sim', fn ($q) => $q ->where('permite_integracao_conectasus_cidadao', true)) ->when($params['conectasus_cidadao'] === 'nao', fn ($q) => $q ->where(fn ($q) => $q ->where('permite_integracao_conectasus_cidadao', false) ->orWhereNull('permite_integracao_conectasus_cidadao') )) ->orderBy('nome') ->get(['id', 'nome', 'permite_integracao_conectasus_cidadao']); } private static function getBuscaJornadaTipos($params) { return JornadaTipo::whereHas('jornadas', fn ($q) => self::setBuscaWhereJornadas($q, $params) ->when($params['especialidade_id'], fn ($q, $id) => $q->where('especialidade_id', $id)) ->whereHas('lotacao', fn ($q) => $q ->where('usuario_id', $params['usuario_id']) ->when($params['infraestrutura_id'], fn ($q, $id) => $q->where('infraestrutura_id', $id), fn ($q) => $q ->when($params['unidade_id'], fn ($q, $id) => $q ->whereHas('infraestrutura', fn ($q) => $q ->where('unidade_id', $id) ) ) ) ->when($params['ocupacao_id'], fn ($q, $id) => $q->where('ocupacao_id', $id)) ) ) ->orderBy('nome') ->get(['id', 'nome']); } private static function getBuscaJornadaSituacoes($params) { return JornadaSituacao::whereHas('jornadas', fn ($q) => self::setBuscaWhereJornadas($q, $params) ->when($params['especialidade_id'], fn ($q, $id) => $q->where('especialidade_id', $id)) ->whereHas('lotacao', fn ($q) => $q ->where('usuario_id', $params['usuario_id']) ->when($params['infraestrutura_id'], fn ($q, $id) => $q->where('infraestrutura_id', $id), fn ($q) => $q ->when($params['unidade_id'], fn ($q, $id) => $q ->whereHas('infraestrutura', fn ($q) => $q ->where('unidade_id', $id) ) ) ) ->when($params['ocupacao_id'], fn ($q, $id) => $q->where('ocupacao_id', $id)) ->when($params['tipo_id'], fn ($q, $id) => $q->where('tipo_id', $id)) ) ) ->orderBy('nome') ->get(['id', 'nome']); } private static function setBuscaWhereJornadas($query, $params) { return $query->whereBetween('data', [ Carbon::createFromFormat('d/m/Y', $params['periodo']['start'])->format('Y-m-d'), Carbon::createFromFormat('d/m/Y', $params['periodo']['end'])->format('Y-m-d') ]) ->when(!is_null($params['inicio']) && !is_null($params['fim']), fn ($q) => $q ->where(fn ($q) => $q ->where('inicio', '<=', $params['inicio']) ->where('fim', '>=', $params['inicio']) ) ->orWhere(fn ($q) => $q ->where('inicio', '<=', $params['fim']) ->where('fim', '>=', $params['fim']) ) ->orWhere(fn ($q) => $q ->where('inicio', '>=', $params['inicio']) ->where('inicio', '<=', $params['fim']) ) ->orWhere(fn ($q) => $q ->where('fim', '>=', $params['inicio']) ->where('fim', '<=', $params['fim']) ) ) ->when(!empty($params['dias_semana']), fn ($q) => $q ->whereRaw("DAYOFWEEK(ambulatorio_jornada.data) IN (" . collect($params['dias_semana'])->join(',') . ")") ); } private static function getCadastroUnidades($params) { return DB::table('cadastro_unidade as unidade') ->whereNull('unidade.deleted_at') ->whereExists(fn ($q) => $q ->select(DB::raw(1)) ->from('cadastro_infraestrutura as infraestrutura') ->whereColumn('infraestrutura.unidade_id', 'unidade.id') ->where(fn ($q) => self::setCadastroWhereInfraestrutura($q, $params['usuario_id'])) ) ->select( 'unidade.id', 'unidade.nome_fantasia' ) ->orderBy('unidade.nome_fantasia') ->get(); } private static function getCadastroInfraestruturas($params) { return DB::table('cadastro_infraestrutura as infraestrutura') ->join( 'cadastro_unidade as unidade', 'unidade.id', 'infraestrutura.unidade_id' ) ->whereNull('infraestrutura.deleted_at') ->where('infraestrutura.unidade_id', $params['unidade_id']) ->where(fn ($q) => self::setCadastroWhereInfraestrutura($q, $params['usuario_id'])) ->select( 'infraestrutura.id', DB::raw("COALESCE(infraestrutura.nome, unidade.nome_fantasia) as nome") ) ->orderByRaw("COALESCE(infraestrutura.nome, unidade.nome_fantasia)") ->get(); } private static function setCadastroWhereInfraestrutura($query, $usuarioId) { return $query->whereExists(fn ($q) => $q ->select(DB::raw(1)) ->from('ambulatorio_parametrizacao_infraestrutura as parametrizacao_infraestrutura') ->whereColumn('parametrizacao_infraestrutura.infraestrutura_id', 'infraestrutura.id') ->whereExists(fn ($q) => $q ->select(DB::raw(1)) ->from('ambulatorio_parametrizacao_infraestrutura_ocupacao as parametrizacao_ocupacao') ->join( 'cadastro_lotacao as lotacao', 'lotacao.ocupacao_id', 'parametrizacao_ocupacao.ocupacao_id' ) ->whereColumn( 'parametrizacao_ocupacao.parametrizacao_infraestrutura_id', 'parametrizacao_infraestrutura.id' ) ->whereColumn('lotacao.infraestrutura_id', 'infraestrutura.id') ->where('lotacao.usuario_id', $usuarioId) ->where('lotacao.realiza_atendimento', true) ->whereNull('lotacao.deleted_at') ) ->whereExists(fn ($q) => $q ->select(DB::raw(1)) ->from('ambulatorio_parametrizacao_infraestrutura_especialidade as parametrizacao_especialidade') ->whereColumn( 'parametrizacao_especialidade.parametrizacao_infraestrutura_id', 'parametrizacao_infraestrutura.id' ) ) ); } private static function getCadastroLotacoes($params) { return DB::table('cadastro_lotacao as lotacao') ->join( 'sigtap.ocupacao as ocupacao', 'ocupacao.id', 'lotacao.ocupacao_id' ) ->whereNull('lotacao.deleted_at') ->where('lotacao.usuario_id', $params['usuario_id']) ->where('lotacao.infraestrutura_id', $params['infraestrutura_id']) ->where('lotacao.realiza_atendimento', true) ->whereExists(fn ($q) => $q ->select(DB::raw(1)) ->from('ambulatorio_parametrizacao_infraestrutura as parametrizacao_infraestrutura') ->join( 'ambulatorio_parametrizacao_infraestrutura_ocupacao as parametrizacao_ocupacao', 'parametrizacao_ocupacao.parametrizacao_infraestrutura_id', 'parametrizacao_infraestrutura.id' ) ->join( 'ambulatorio_parametrizacao_infraestrutura_especialidade as parametrizacao_especialidade', 'parametrizacao_especialidade.parametrizacao_infraestrutura_id', 'parametrizacao_infraestrutura.id' ) ->join( 'cadastro_especialidade as especialidade', 'especialidade.id', 'parametrizacao_especialidade.especialidade_id' ) ->whereColumn('parametrizacao_infraestrutura.infraestrutura_id', 'lotacao.infraestrutura_id') ->whereColumn('parametrizacao_ocupacao.ocupacao_id', 'lotacao.ocupacao_id') ->whereColumn('especialidade.ocupacao_id', 'lotacao.ocupacao_id') ) ->select( 'lotacao.id', DB::raw("CONCAT(ocupacao.codigo, ' - ', ocupacao.nome) as ocupacao_descricao") ) ->orderByRaw("CONCAT(ocupacao.codigo, ' - ', ocupacao.nome)") ->get(); } private static function getCadastroEspecialidades($params) { $lotacao = Lotacao::where('id', $params['lotacao_id'])->first(['ocupacao_id', 'infraestrutura_id']); return Especialidade::where('ativo', true) ->where('ocupacao_id', $lotacao->ocupacao_id) ->whereHas('ambulatorioParametrizacoesInfraestruturaEspecialidade', fn ($q) => $q ->whereHas('parametrizacaoInfraestrutura', fn ($q) => $q ->where('infraestrutura_id', $lotacao->infraestrutura_id) ) ) ->orderBy('nome') ->get(['id', 'nome', 'permite_integracao_conectasus_cidadao']); } private static function getCadastroJornadaTipos() { return JornadaTipo::orderBy('nome')->get(['id', 'nome']); } private static function getCadastroJornadaSituacoes() { return JornadaSituacao::orderBy('nome')->get(['id', 'nome']); } private static function getDiasSemana() { return DiaSemana::orderBy('id') ->get(['id', 'descricao']) ->map(fn ($diaSemana) => [ 'id' => $diaSemana->id, 'descricao' => $diaSemana->descricao, 'disabled' => true, ]); } public static function store() { self::validateStore(); $jornadasCriadas = collect(); $jornadasConflitantes = collect(); $feriados = collect(); DB::transaction(function() use ($jornadasCriadas, $jornadasConflitantes, $feriados) { $params = self::getStoreParams(); $date = Carbon::createFromFormat('d/m/Y', request()->periodo['start']); $endDate = Carbon::createFromFormat('d/m/Y', request()->periodo['end']); while ($date <= $endDate) { $diaSemana = $date->dayOfWeek + 1; if (collect(request()->dias_semana)->contains($diaSemana)) { $params['fim'] = self::getFim( $params['inicio'], $params['quantidade_consulta'], $params['tempo_consulta'], $params['quantidade_retorno'], $params['tempo_retorno'], $params['quantidade_consulta_conectasus_cidadao'] ?? null, $params['tempo_consulta_conectasus_cidadao'] ?? null, $params['quantidade_retorno_conectasus_cidadao'] ?? null, $params['tempo_retorno_conectasus_cidadao'] ?? null ); $isConflitante = self::isJornadaConflitante([ 'id' => null, 'data' => $date, 'inicio' => $params['inicio'], 'fim' => $params['fim'], 'lotacao_id' => $params['lotacao_id'], ]); if ($isConflitante) { $params['data'] = $date->format('d/m/Y'); $params['dia_semana'] = $diaSemana; $jornadasConflitantes->push($params); } else if (self::isFeriado($date)) { $feriados->push([ 'data' => $date->format('d/m/Y'), 'dia_semana' => $diaSemana ]); } else { $params['data'] = $date->format('Y-m-d'); $jornadasCriadas->push(Jornada::create($params)); } } $date->addDay(); } }); return [ 'jornadas_criadas' => $jornadasCriadas, 'jornadas_conflitantes' => $jornadasConflitantes, 'feriados' => $feriados, ]; } private static function validateStore() { request()->validate([ 'lotacao_id' => [ 'required', 'integer', Rule::exists(Lotacao::class, 'id'), ], 'especialidade_id' => [ 'required', 'integer', Rule::exists(Especialidade::class, 'id'), ], 'tipo_id' => [ 'required', 'integer', Rule::exists(JornadaTipo::class, 'id'), ], 'periodo.start' => [ 'required', 'date_format:d/m/Y', 'before_or_equal:periodo.end' ], 'periodo.end' => [ 'required', 'date_format:d/m/Y', 'after_or_equal:periodo.start' ], 'inicio' => [ 'required', 'date_format:H:i', ], 'dias_semana' => [ 'required', 'array' ], 'dias_semana.*' => [ 'integer', Rule::exists(DiaSemana::class, 'id'), ], 'situacao_id' => [ 'nullable', 'integer', Rule::exists(JornadaSituacao::class, 'id'), ], 'quantidade_consulta' => [ Rule::requiredIf(fn () => is_null(request()->quantidade_retorno)), 'nullable', 'integer', 'max:999' ], 'tempo_consulta' => [ Rule::requiredIf(fn () => !is_null(request()->quantidade_consulta)), 'nullable', 'integer', 'max:999' ], 'quantidade_retorno' => [ Rule::requiredIf(fn () => is_null(request()->quantidade_consulta)), 'nullable', 'integer', 'max:999' ], 'tempo_retorno' => [ Rule::requiredIf(fn () => !is_null(request()->quantidade_retorno)), 'nullable', 'integer', 'max:999' ], 'quantidade_consulta_conectasus_cidadao' => [ 'nullable', 'integer', 'min:0', 'max:999' ], 'tempo_consulta_conectasus_cidadao' => [ Rule::requiredIf(fn () => request()->quantidade_consulta_conectasus_cidadao > 0), 'nullable', 'integer', 'min:1', 'max:999' ], 'quantidade_retorno_conectasus_cidadao' => [ 'nullable', 'integer', 'min:0', 'max:999' ], 'tempo_retorno_conectasus_cidadao' => [ Rule::requiredIf(fn () => request()->quantidade_retorno_conectasus_cidadao > 0), 'nullable', 'integer', 'min:1', 'max:999' ], 'permite_agendamento_somente_supervisor' => [ 'required', 'boolean' ], ]); } private static function getStoreParams() { return request()->except(['periodo', 'dias_semana']); } private static function isFeriado($date) { return Feriado::where('data', $date->format('Y-m-d')) ->whereHas('modulos', function ($query) { $query->where('identificador', Modulo::AMBULATORIO); }) ->exists(); } public static function update($id) { $jornada = Jornada::findOrFail($id); self::validateUpdate($jornada); $params = self::getUpdateParams($jornada, request()->all()); $params['fim'] = self::getFim( $params['inicio'], $params['quantidade_consulta'], $params['tempo_consulta'], $params['quantidade_retorno'], $params['tempo_retorno'], $params['quantidade_consulta_conectasus_cidadao'] ?? null, $params['tempo_consulta_conectasus_cidadao'] ?? null, $params['quantidade_retorno_conectasus_cidadao'] ?? null, $params['tempo_retorno_conectasus_cidadao'] ?? null ); $isConflitante = self::isJornadaConflitante([ 'id' => $jornada->id, 'data' => $jornada->data, 'inicio' => $params['inicio'], 'fim' => $params['fim'], 'lotacao_id' => $params['lotacao_id'], ]); if ($isConflitante) { throw new JornadaConflitanteException(); } $jornada->update($params); return $jornada->fresh(); } private static function validateUpdate($jornada) { $hasAgendamentos = $jornada->agendamentos()->exists(); $hasAgendamentoAndConsulta = $hasAgendamentos && !is_null($jornada->quantidade_consulta); $hasAgendamentoAndRetorno = $hasAgendamentos && !is_null($jornada->quantidade_retorno); if ($hasAgendamentoAndConsulta) { $count = $jornada->agendamentos()->whereIn('status_id', [1, 6, 7, 8])->count(); $quantidade_agendamentos = $count !== 0 ? $count : 1; } $rules = [ 'lotacao_id' => [ 'required', 'integer', Rule::exists(Lotacao::class, 'id'), ], 'especialidade_id' => [ 'required', 'integer', Rule::exists(Especialidade::class, 'id'), ], 'tipo_id' => [ 'required', 'integer', Rule::exists(JornadaTipo::class, 'id'), ], 'inicio' => [ 'required', 'date_format:H:i', ], 'situacao_id' => [ 'nullable', 'integer', Rule::exists(JornadaSituacao::class, 'id'), ], 'quantidade_consulta' => [ Rule::requiredIf(fn () => $hasAgendamentoAndConsulta || is_null(request()->quantidade_retorno)), 'nullable', 'integer', 'min:' . ($hasAgendamentoAndConsulta ? $quantidade_agendamentos : 1), 'max:999' ], 'tempo_consulta' => [ Rule::requiredIf(fn () => !is_null(request()->quantidade_consulta)), 'nullable', 'integer', 'max:999' ], 'quantidade_retorno' => [ Rule::requiredIf(fn () => $hasAgendamentoAndRetorno || is_null(request()->quantidade_consulta) ), 'nullable', 'integer', 'min:' . ($hasAgendamentoAndRetorno ? $jornada->quantidade_retorno : 0), 'max:999' ], 'tempo_retorno' => [ Rule::requiredIf(fn () => !is_null(request()->quantidade_retorno)), 'nullable', 'integer', 'max:999' ], 'quantidade_consulta_conectasus_cidadao' => [ 'nullable', 'integer', 'min:0', 'max:999' ], 'tempo_consulta_conectasus_cidadao' => [ Rule::requiredIf(fn () => request()->quantidade_consulta_conectasus_cidadao > 0), 'nullable', 'integer', 'min:1', 'max:999' ], 'quantidade_retorno_conectasus_cidadao' => [ 'nullable', 'integer', 'min:0', 'max:999' ], 'tempo_retorno_conectasus_cidadao' => [ Rule::requiredIf(fn () => request()->quantidade_retorno_conectasus_cidadao > 0), 'nullable', 'integer', 'min:1', 'max:999' ], 'permite_agendamento_somente_supervisor' => [ 'required', 'boolean' ], ]; request()->validate($rules); } public static function updateAll() { self::validateUpdateAll(); $jornadasAtualizadas = collect(); $jornadasConflitantes = collect(); $jornadasComAgendamento = collect(); DB::transaction(function() use ($jornadasAtualizadas, $jornadasConflitantes, $jornadasComAgendamento) { collect(request()->all()) ->each(function ($params) use ($jornadasAtualizadas, $jornadasConflitantes, $jornadasComAgendamento) { $jornada = Jornada::findOrFail($params['id']); $params = self::getUpdateAllParams($jornada, $params); if ($jornada->agendamentos()->exists()) { $jornadasComAgendamento->push($params); } else { $params['fim'] = self::getFim( $params['inicio'], $params['quantidade_consulta'], $params['tempo_consulta'], $params['quantidade_retorno'], $params['tempo_retorno'], $params['quantidade_consulta_conectasus_cidadao'] ?? null, $params['tempo_consulta_conectasus_cidadao'] ?? null, $params['quantidade_retorno_conectasus_cidadao'] ?? null, $params['tempo_retorno_conectasus_cidadao'] ?? null ); $isConflitante = self::isJornadaConflitante([ 'id' => $jornada->id, 'data' => $jornada->data, 'inicio' => $params['inicio'], 'fim' => $params['fim'], 'lotacao_id' => $params['lotacao_id'], ]); if ($isConflitante) { $jornadasConflitantes->push($params); } else { $jornada->update($params); $jornadasAtualizadas->push($jornada->fresh()); } } }); }); return [ 'jornadas_atualizadas' => $jornadasAtualizadas, 'jornadas_conflitantes' => $jornadasConflitantes, 'jornadas_com_agendamento' => $jornadasComAgendamento, ]; } private static function validateUpdateAll() { $rules = []; collect(request()->all())->each(function ($jornada, $i) use (&$rules) { $rules["{$i}.id"] = [ 'required', 'integer', Rule::exists(Jornada::class, 'id'), ]; $rules["{$i}.lotacao_id"] = [ 'required', 'integer', Rule::exists(Lotacao::class, 'id'), ]; $rules["{$i}.especialidade_id"] = [ 'required', 'integer', Rule::exists(Especialidade::class, 'id'), ]; $rules["{$i}.tipo_id"] = [ 'required', 'integer', Rule::exists(JornadaTipo::class, 'id'), ]; $rules["{$i}.inicio"] = [ 'required', 'date_format:H:i', ]; $rules["{$i}.situacao_id"] = [ 'nullable', 'integer', Rule::exists(JornadaSituacao::class, 'id'), ]; $rules["{$i}.quantidade_consulta"] = [ Rule::requiredIf(fn() => !array_key_exists('total_agendamentos', $jornada) || is_null($jornada['total_agendamentos'])), 'nullable', 'integer', 'max:999' ]; $rules["{$i}.tempo_consulta"] = [ Rule::requiredIf(fn () => !is_null($jornada['quantidade_consulta'])), 'nullable', 'integer', 'max:999' ]; $rules["{$i}.quantidade_retorno"] = [ Rule::requiredIf(fn () => is_null($jornada['quantidade_consulta'])), 'nullable', 'integer', 'max:999' ]; $rules["{$i}.tempo_retorno"] = [ Rule::requiredIf(fn () => !is_null($jornada['quantidade_retorno'])), 'nullable', 'integer', 'max:999' ]; $rules["{$i}.quantidade_consulta_conectasus_cidadao"] = [ 'nullable', 'integer', 'min:0', 'max:999' ]; $rules["{$i}.tempo_consulta_conectasus_cidadao"] = [ Rule::requiredIf(fn () => ($jornada['quantidade_consulta_conectasus_cidadao'] ?? 0) > 0), 'nullable', 'integer', 'min:1', 'max:999' ]; $rules["{$i}.quantidade_retorno_conectasus_cidadao"] = [ 'nullable', 'integer', 'min:0', 'max:999' ]; $rules["{$i}.tempo_retorno_conectasus_cidadao"] = [ Rule::requiredIf(fn () => ($jornada['quantidade_retorno_conectasus_cidadao'] ?? 0) > 0), 'nullable', 'integer', 'min:1', 'max:999' ]; $rules["{$i}.permite_agendamento_somente_supervisor"] = [ 'required', 'boolean' ]; }); request()->validate($rules); } private static function getUpdateParams($jornada, $params) { if ($jornada->agendamentos()->exists()) { $params['lotacao_id'] = $jornada->lotacao_id == $params['lotacao_id'] ? $jornada->lotacao_id : $params['lotacao_id']; $params['especialidade_id'] = $jornada->especialidade_id == $params['especialidade_id'] ? $jornada->especialidade_id : $params['especialidade_id']; $params['tipo_id'] = $jornada->tipo_id == $params['tipo_id'] ? $jornada->tipo_id : $params['tipo_id']; $params['inicio'] = $jornada->inicio->format('H:i') == $params['inicio'] ? $jornada->inicio->format('H:i') : $params['inicio']; $params['situacao_id'] = $jornada->situacao_id == $params['situacao_id'] ? $jornada->situacao_id : $params['situacao_id']; $params['tempo_consulta'] = $jornada->tempo_consulta == $params['tempo_consulta'] ? $jornada->tempo_consulta : $params['tempo_consulta']; $params['tempo_retorno'] = $jornada->tempo_retorno == $params['tempo_retorno'] ? $jornada->tempo_retorno : $params['tempo_retorno']; $params['permite_agendamento_somente_supervisor'] = $jornada->permite_agendamento_somente_supervisor == $params['permite_agendamento_somente_supervisor'] ? $jornada->permite_agendamento_somente_supervisor : $params['permite_agendamento_somente_supervisor']; return $params; } return $params; } private static function getUpdateAllParams($jornada, $params) { if ($jornada->agendamentos()->exists()) { $params['lotacao_id'] = $jornada->lotacao_id; $params['especialidade_id'] = $jornada->especialidade_id; $params['tipo_id'] = $jornada->tipo_id; $params['inicio'] = $jornada->inicio->format('H:i'); $params['tempo_consulta'] = $jornada->tempo_consulta; $params['tempo_retorno'] = $jornada->tempo_retorno; $params['permite_agendamento_somente_supervisor'] = $jornada->permite_agendamento_somente_supervisor; return $params; } return $params; } private static function isJornadaConflitante($jornada) { return Jornada::when($jornada['id'], fn ($q, $id) => $q->where('id', '<>', $id)) ->whereNull('situacao_id') ->where('data', $jornada['data']->format('Y-m-d')) ->whereHas('lotacao', fn ($q) => $q ->where('usuario_id', Lotacao::findOrFail($jornada['lotacao_id'])->usuario_id) ) ->where(fn ($q) => $q ->where(fn ($q) => $q ->where('inicio', '<=', $jornada['inicio']) ->where('fim', '>=', $jornada['inicio']) ) ->orWhere(fn ($q) => $q ->where('inicio', '<=', $jornada['fim']) ->where('fim', '>=', $jornada['fim']) ) ->orWhere(fn ($q) => $q ->where('inicio', '>=', $jornada['inicio']) ->where('inicio', '<=', $jornada['fim']) ) ->orWhere(fn ($q) => $q ->where('fim', '>=', $jornada['inicio']) ->where('fim', '<=', $jornada['fim']) ) ) ->exists(); } private static function getFim($inicio, $quantidadeConsulta, $tempoConsulta, $quantidadeRetorno, $tempoRetorno, $quantidadeConsultaCidadao = null, $tempoConsultaCidadao = null, $quantidadeRetornoCidadao = null, $tempoRetornoCidadao = null) { $quantidadeConsulta = $quantidadeConsulta ?? 0; $tempoConsulta = $tempoConsulta ?? 0; $quantidadeRetorno = $quantidadeRetorno ?? 0; $tempoRetorno = $tempoRetorno ?? 0; $quantidadeConsultaCidadao = $quantidadeConsultaCidadao ?? 0; $tempoConsultaCidadao = $tempoConsultaCidadao ?? 0; $quantidadeRetornoCidadao = $quantidadeRetornoCidadao ?? 0; $tempoRetornoCidadao = $tempoRetornoCidadao ?? 0; $tempoTotalConsulta = $quantidadeConsulta * $tempoConsulta; $tempoTotalRetorno = $quantidadeRetorno * $tempoRetorno; $tempoTotalConsultaCidadao = $quantidadeConsultaCidadao * $tempoConsultaCidadao; $tempoTotalRetornoCidadao = $quantidadeRetornoCidadao * $tempoRetornoCidadao; $inicio = Carbon::now()->setTimeFromTimeString("{$inicio}:00"); $fim = $inicio->copy()->addMinutes($tempoTotalConsulta + $tempoTotalRetorno + $tempoTotalConsultaCidadao + $tempoTotalRetornoCidadao); if (!$inicio->isSameDay($fim)) { throw new FimExcedeuDataJornadaException(); } return $fim->format('H:i'); } public static function destroy($id) { $jornada = Jornada::findOrFail($id); if ($jornada->agendamentos()->exists()) { throw new PossuiAgendamentoException(); } $jornada->delete(); } public static function destroyAll() { $idsExcluidos = collect(); $idsComAgendamento = collect(); collect(request()->ids)->each(function ($id) use ($idsExcluidos, $idsComAgendamento) { $jornada = Jornada::findOrFail($id); if ($jornada->agendamentos()->exists()) { $idsComAgendamento->push($jornada->id); } else { $jornada->delete(); $idsExcluidos->push($jornada->id); } }); return [ 'jornadas_ids_excluidos' => $idsExcluidos, 'jornadas_ids_com_agendamento' => $idsComAgendamento, ]; } }