631 lines
26 KiB
PHP
631 lines
26 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Mobile\ConectaCidadao\ExameImagem;
|
|
|
|
use App\Enums\ExameImagem\Fechamento\Status;
|
|
use App\Enums\ExameImagem\Parametrizacao\ControleJornada\Tipo as ControleJornadaTipo;
|
|
use App\Enums\ExameImagem\Tipo;
|
|
use App\Enums\Parametrizacao\Exame\Tipo as ExameTipo;
|
|
use App\Models\Ambulatorio\AtendimentoSoapSolicitacaoExameItem;
|
|
use App\Models\Cadastro\Feriado\Feriado;
|
|
use App\Models\ExameImagem\Agendamento\Agendamento;
|
|
use App\Models\ExameImagem\Agendamento\AgendamentoExame;
|
|
use App\Services\Service;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Http\Response;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class AgendamentoImagemService extends Service
|
|
{
|
|
public static function elegibilidade()
|
|
{
|
|
$habilitado = DB::table('exame_imagem_parametrizacao_integracao_aplicativo')
|
|
->value('habilita_agendamento_conectasus_cidadao');
|
|
|
|
return ['habilitado' => (bool) $habilitado];
|
|
}
|
|
|
|
public static function prestadores()
|
|
{
|
|
self::validarParametrizacaoHabilitada();
|
|
|
|
$agora = now();
|
|
|
|
return DB::table('exame_imagem_parametrizacao_unidade as parametrizacao')
|
|
->leftJoin('cadastro_unidade as unidade', 'unidade.id', 'parametrizacao.unidade_id')
|
|
->leftJoin('cadastro_infraestrutura as infraestrutura', 'infraestrutura.id', 'parametrizacao.infraestrutura_id')
|
|
->where(function ($q) {
|
|
$q->where('parametrizacao.executante', true)->orWhere('parametrizacao.prestador', true);
|
|
})
|
|
->whereNull('parametrizacao.deleted_at')
|
|
->whereExists(function ($q) use ($agora) {
|
|
$q->select(DB::raw(1))
|
|
->from('exame_imagem_jornada as jornada')
|
|
->whereColumn('jornada.infraestrutura_id', 'parametrizacao.infraestrutura_id')
|
|
->whereNotNull('jornada.vagas_app')
|
|
->where('jornada.vagas_app', '>', 0)
|
|
->where(function ($q2) use ($agora) {
|
|
$q2->whereDate('jornada.data', '>', $agora->toDateString())
|
|
->orWhere(function ($q3) use ($agora) {
|
|
$q3->whereDate('jornada.data', $agora->toDateString())
|
|
->whereTime('jornada.hora_fim', '>', $agora->format('H:i:s'));
|
|
});
|
|
})
|
|
->whereNull('jornada.deleted_at');
|
|
})
|
|
->get([
|
|
'parametrizacao.unidade_id',
|
|
'unidade.nome_fantasia',
|
|
'parametrizacao.infraestrutura_id',
|
|
'infraestrutura.nome as infraestrutura_nome',
|
|
])
|
|
->map(
|
|
fn($param) =>
|
|
[
|
|
'unidade_id' => $param->unidade_id,
|
|
'nome_fantasia' => $param->nome_fantasia,
|
|
'infraestrutura_id' => $param->infraestrutura_id,
|
|
'infraestrutura_nome' => $param->infraestrutura_nome,
|
|
]
|
|
)
|
|
->unique(fn($item) => $item['unidade_id'] . '-' . $item['infraestrutura_id'])
|
|
->sortBy('nome_fantasia')
|
|
->values();
|
|
}
|
|
|
|
public static function exames(): array
|
|
{
|
|
self::validarParametrizacaoHabilitada();
|
|
|
|
$pacienteId = auth('mobile')->user()->id;
|
|
|
|
$statusRealizados = [
|
|
Status::REALIZADO,
|
|
Status::RESULTADO,
|
|
];
|
|
|
|
$exameIdsBloqueadosPorValidade = DB::table('parametrizacao_exame as exame')
|
|
->join('exame_imagem_agendamento_exame as ae', 'ae.exame_id', 'exame.id')
|
|
->join('exame_imagem_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();
|
|
|
|
$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')
|
|
->leftJoin('cadastro_grupo', 'cadastro_grupo.id', 'parametrizacao_exame.grupo_tipo_id')
|
|
->where('parametrizacao_exame.tipo_id', ExameTipo::IMAGEM)
|
|
->whereNull('parametrizacao_exame.regulacao_tipo_id')
|
|
->whereNull('parametrizacao_exame.deleted_at')
|
|
->where('ambulatorio_atendimento_soap_solicitacao_exame_item.descartado_exame_imagem', '!=', true)
|
|
->where('ambulatorio_atendimento_soap_solicitacao_exame_item.agendado_exame_imagem', '!=', true)
|
|
->whereNotIn('parametrizacao_exame.id', $exameIdsBloqueadosPorValidade)
|
|
->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',
|
|
'parametrizacao_exame.codigo',
|
|
'parametrizacao_exame.nome',
|
|
'parametrizacao_exame.observacao',
|
|
'parametrizacao_exame.sexo_id',
|
|
'cadastro_grupo.id as grupo_id',
|
|
'cadastro_cidadao.nome as profissional_nome',
|
|
'profissional.id as profissional_id',
|
|
]
|
|
);
|
|
|
|
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($exame) => [
|
|
'exame_item_id' => $exame->exame_item_id,
|
|
'id' => $exame->id,
|
|
'codigo' => $exame->codigo,
|
|
'nome' => $exame->nome,
|
|
'observacao' => $exame->observacao,
|
|
'sexo_id' => $exame->sexo_id,
|
|
'grupo_id' => $exame->grupo_id,
|
|
])->values()->toArray(),
|
|
])
|
|
->values()
|
|
->toArray();
|
|
}
|
|
|
|
public static function jornadas(): array
|
|
{
|
|
self::validarParametrizacaoHabilitada();
|
|
|
|
request()->validate(
|
|
[
|
|
'infraestrutura_id' => 'required|integer|exists:cadastro_infraestrutura,id',
|
|
'exame_id' => 'required|integer|exists:parametrizacao_exame,id',
|
|
]
|
|
);
|
|
|
|
$infraestruturaId = (int) request()->infraestrutura_id;
|
|
$exameId = (int) request()->exame_id;
|
|
|
|
$grupoId = DB::table('parametrizacao_exame')
|
|
->where('id', $exameId)
|
|
->value('grupo_tipo_id');
|
|
|
|
$hoje = Carbon::today();
|
|
$fim = Carbon::today()->addMonths(3);
|
|
$agora = now();
|
|
|
|
$jornadasRaw = DB::table('exame_imagem_jornada as jornada')
|
|
->where('jornada.infraestrutura_id', $infraestruturaId)
|
|
->when($grupoId, fn($q) => $q->where('jornada.exame_id', $grupoId))
|
|
->whereNotNull('jornada.vagas_app')
|
|
->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'));
|
|
});
|
|
})
|
|
->whereDate('jornada.data', '<=', $fim->toDateString())
|
|
->whereNull('jornada.deleted_at')
|
|
->orderBy('jornada.data')
|
|
->orderBy('jornada.hora_inicial')
|
|
->get(
|
|
[
|
|
'jornada.id',
|
|
'jornada.data',
|
|
'jornada.hora_inicial',
|
|
'jornada.hora_fim',
|
|
'jornada.vagas_app',
|
|
'jornada.exame_id as grupo_id',
|
|
'jornada.controle_jornada_id',
|
|
'jornada.tempo_atendimento',
|
|
]
|
|
);
|
|
|
|
$jornadaIds = $jornadasRaw->pluck('id')->toArray();
|
|
|
|
$statusExcluidos = [
|
|
Status::CANCELADO,
|
|
Status::FALTOU,
|
|
Status::FALTA_MEDICA,
|
|
];
|
|
|
|
$consumoPorJornada = DB::table('exame_imagem_agendamento as ag')
|
|
->join('exame_imagem_agendamento_exame as ag_exame', 'ag_exame.agendamento_id', '=', 'ag.id')
|
|
->whereIn('ag.jornada_id', $jornadaIds)
|
|
->where('ag.app_conectasus_cidadao', true)
|
|
->whereNotIn('ag_exame.status_id', $statusExcluidos)
|
|
->groupBy('ag.jornada_id')
|
|
->select(
|
|
'ag.jornada_id',
|
|
DB::raw('COUNT(DISTINCT ag.id) as visitas'),
|
|
DB::raw('COUNT(ag_exame.id) as exames')
|
|
)
|
|
->get()
|
|
->keyBy('jornada_id');
|
|
|
|
$horariosOcupadosPorJornada = DB::table('exame_imagem_agendamento as ag')
|
|
->join('exame_imagem_agendamento_exame as ag_exame', 'ag_exame.agendamento_id', '=', 'ag.id')
|
|
->whereIn('ag.jornada_id', $jornadaIds)
|
|
->whereNotIn('ag_exame.status_id', $statusExcluidos)
|
|
->select('ag.jornada_id', DB::raw("DATE_FORMAT(ag.hora_exame, '%H:%i') as horario"))
|
|
->distinct()
|
|
->get()
|
|
->groupBy('jornada_id')
|
|
->map(fn($rows) => $rows->pluck('horario')->toArray());
|
|
|
|
$jornadas = $jornadasRaw->map(function ($jornada) use ($consumoPorJornada, $horariosOcupadosPorJornada) {
|
|
$consumo = $consumoPorJornada[$jornada->id] ?? null;
|
|
|
|
$consumido = $jornada->controle_jornada_id == ControleJornadaTipo::EXAME
|
|
? ($consumo->exames ?? 0)
|
|
: ($consumo->visitas ?? 0);
|
|
|
|
$disponivel = max(0, $jornada->vagas_app - $consumido);
|
|
|
|
return [
|
|
'id' => $jornada->id,
|
|
'data' => Carbon::parse($jornada->data)->format('Y-m-d'),
|
|
'hora_inicial' => $jornada->hora_inicial,
|
|
'hora_fim' => $jornada->hora_fim,
|
|
'tempo_atendimento' => $jornada->tempo_atendimento,
|
|
'vagas_app' => $jornada->vagas_app,
|
|
'consumido' => $consumido,
|
|
'disponivel' => $disponivel,
|
|
'controle_jornada_id' => $jornada->controle_jornada_id,
|
|
'horarios' => self::gerarHorariosDisponiveis(
|
|
$jornada->data,
|
|
$jornada->hora_inicial,
|
|
$jornada->hora_fim,
|
|
$jornada->tempo_atendimento,
|
|
$horariosOcupadosPorJornada[$jornada->id] ?? []
|
|
),
|
|
];
|
|
})->values()->toArray();
|
|
|
|
$feriados = Feriado::whereDate('data', '>=', $hoje->toDateString())
|
|
->whereDate('data', '<=', $fim->toDateString())
|
|
->whereNull('deleted_at')
|
|
->orderBy('data')
|
|
->get(['data', 'observacao'])
|
|
->map(
|
|
fn($f) =>
|
|
[
|
|
'data' => Carbon::parse($f->data)->format('Y-m-d'),
|
|
'observacao' => $f->observacao,
|
|
]
|
|
)
|
|
->values()
|
|
->toArray();
|
|
|
|
return [
|
|
'jornadas' => $jornadas,
|
|
'feriados' => $feriados,
|
|
'cota' => self::computarCotaApp($infraestruturaId),
|
|
];
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
public static function agendar(): array
|
|
{
|
|
self::validarParametrizacaoHabilitada();
|
|
|
|
request()->validate(
|
|
[
|
|
'jornada_id' => 'required|integer|exists:exame_imagem_jornada,id',
|
|
'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',
|
|
'gestante' => 'nullable|boolean',
|
|
'nome_responsavel' => 'nullable|string',
|
|
]
|
|
);
|
|
|
|
$paciente = auth('mobile')->user();
|
|
$jornada = DB::table('exame_imagem_jornada')->where('id', request()->jornada_id)->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);
|
|
$dataHoraExame = Carbon::parse($dataJornada . ' ' . request()->horario);
|
|
|
|
if ($dataHoraExame->isPast()) {
|
|
|
|
abort(Response::HTTP_UNPROCESSABLE_ENTITY, 'Não é possível agendar em horário retroativo.');
|
|
}
|
|
|
|
if ($dataHoraExame->lt($horaInicialJornada) || $dataHoraExame->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_imagem_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)
|
|
->where('ae.status_id', Status::AGENDADO)
|
|
->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, count(request()->exames));
|
|
self::verificarCotaApp((int) request()->infraestrutura_id);
|
|
|
|
$solicitanteInfraId = DB::table('cadastro_infraestrutura')
|
|
->where('unidade_id', $paciente->unidade_id)
|
|
->where('principal', true)
|
|
->value('id');
|
|
|
|
$solicitanteUnidadeId = $paciente->unidade_id;
|
|
|
|
$ultimoNumero = DB::table('exame_imagem_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->profissional_id = $jornada->usuario_id;
|
|
$agendamento->data = $jornada->data;
|
|
$agendamento->exame_id = $jornada->exame_id;
|
|
$agendamento->hora_exame = request()->horario;
|
|
$agendamento->unidade_id = $jornada->unidade_id;
|
|
$agendamento->infraestrutura_id = $jornada->infraestrutura_id;
|
|
$agendamento->unidade_solicitante_id = $solicitanteUnidadeId;
|
|
$agendamento->infraestrutura_solicitante_id = $solicitanteInfraId;
|
|
$agendamento->observacao = request()->observacao;
|
|
$agendamento->gestante = request()->gestante ?? false;
|
|
$agendamento->urgente = false;
|
|
$agendamento->nome_responsavel = request()->nome_responsavel;
|
|
$agendamento->retroativo = false;
|
|
$agendamento->app_conectasus_cidadao = true;
|
|
$agendamento->save();
|
|
|
|
foreach (request()->exames as $exameData) {
|
|
|
|
$agendamentoExame = new AgendamentoExame();
|
|
$agendamentoExame->agendamento_id = $agendamento->id;
|
|
$agendamentoExame->paciente_id = $paciente->id;
|
|
$agendamentoExame->exame_id = $exameData['exame_id'];
|
|
$agendamentoExame->status_id = Status::AGENDADO;
|
|
$agendamentoExame->soap_solicitacao_exame_item_id = $exameData['exame_item_id'];
|
|
$agendamentoExame->save();
|
|
|
|
AtendimentoSoapSolicitacaoExameItem::findOrFail($exameData['exame_item_id'])
|
|
->update(['agendado_exame_imagem' => true]);
|
|
}
|
|
|
|
return [
|
|
'agendamento_id' => $agendamento->id,
|
|
'agendamento_numero' => $agendamento->agendamento_numero,
|
|
];
|
|
}
|
|
|
|
private static function validarHorarioDisponivel(object $jornada, string $horario): void
|
|
{
|
|
$statusExcluidos = [
|
|
Status::CANCELADO,
|
|
Status::FALTOU,
|
|
Status::FALTA_MEDICA,
|
|
];
|
|
|
|
$ocupado = DB::table('exame_imagem_agendamento as ag')
|
|
->join('exame_imagem_agendamento_exame as ag_exame', 'ag_exame.agendamento_id', '=', 'ag.id')
|
|
->where('ag.jornada_id', $jornada->id)
|
|
->whereTime('ag.hora_exame', $horario)
|
|
->whereNotIn('ag_exame.status_id', $statusExcluidos)
|
|
->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, int $quantidadeExames): void
|
|
{
|
|
$statusExcluidos = [
|
|
Status::CANCELADO,
|
|
Status::FALTOU,
|
|
Status::FALTA_MEDICA,
|
|
];
|
|
|
|
$query = DB::table('exame_imagem_agendamento as ag')
|
|
->join('exame_imagem_agendamento_exame as ag_exame', 'ag_exame.agendamento_id', '=', 'ag.id')
|
|
->where('ag.jornada_id', $jornada->id)
|
|
->where('ag.app_conectasus_cidadao', true)
|
|
->whereNotIn('ag_exame.status_id', $statusExcluidos);
|
|
|
|
if ($jornada->controle_jornada_id == ControleJornadaTipo::EXAME) {
|
|
|
|
$consumido = $query->count('ag_exame.id');
|
|
$necessario = $quantidadeExames;
|
|
} else {
|
|
|
|
$consumido = $query->distinct()->count('ag.id');
|
|
$necessario = 1;
|
|
}
|
|
|
|
if ($consumido + $necessario > $jornada->vagas_app) {
|
|
|
|
abort(Response::HTTP_UNPROCESSABLE_ENTITY, 'Não há vagas disponíveis para o aplicativo nesta jornada.');
|
|
}
|
|
}
|
|
|
|
private static function verificarCotaApp(int $infraestruturaId): void
|
|
{
|
|
$cota = self::computarCotaApp($infraestruturaId);
|
|
|
|
if ($cota && $cota['bloqueado']) {
|
|
|
|
abort(Response::HTTP_UNPROCESSABLE_ENTITY, 'O limite de agendamentos pelo aplicativo foi atingido para este período.');
|
|
}
|
|
}
|
|
|
|
private static function computarCotaApp(int $infraestruturaId): ?array
|
|
{
|
|
$appConfig = DB::table('exame_imagem_parametrizacao_app_conectasus_cidadao_prestador')
|
|
->where('infraestrutura_id', $infraestruturaId)
|
|
->whereNull('deleted_at')
|
|
->first();
|
|
|
|
if (!$appConfig) {
|
|
|
|
return null;
|
|
}
|
|
|
|
$hoje = now()->toDateString();
|
|
$statusExcluidos = [Status::CANCELADO, Status::FALTOU, Status::FALTA_MEDICA];
|
|
|
|
$cotaQuantidade = null;
|
|
$cotaValor = null;
|
|
|
|
if ($appConfig->percentual_quantitativo) {
|
|
|
|
$prestadorQtd = DB::table('exame_imagem_parametrizacao_cota_prestador')
|
|
->where('infraestrutura_id', $infraestruturaId)
|
|
->where('cota_tipo_id', Tipo::QUANTIDADE)
|
|
->where('inicio', '<=', $hoje)
|
|
->where('fim', '>=', $hoje)
|
|
->whereNull('deleted_at')
|
|
->first();
|
|
|
|
if ($prestadorQtd) {
|
|
|
|
$limite = (int) floor($prestadorQtd->cota_unidade * $appConfig->percentual_quantitativo / 100);
|
|
|
|
$consumido = DB::table('exame_imagem_agendamento as ag')
|
|
->join('exame_imagem_agendamento_exame as ag_exame', 'ag_exame.agendamento_id', '=', 'ag.id')
|
|
->where('ag.infraestrutura_id', $infraestruturaId)
|
|
->where('ag.app_conectasus_cidadao', true)
|
|
->whereDate('ag.data', '>=', $prestadorQtd->inicio)
|
|
->whereDate('ag.data', '<=', $prestadorQtd->fim)
|
|
->whereNotIn('ag_exame.status_id', $statusExcluidos)
|
|
->distinct()
|
|
->count('ag.id');
|
|
|
|
$cotaQuantidade = [
|
|
'percentual_limite' => (float) $appConfig->percentual_quantitativo,
|
|
'limite' => $limite,
|
|
'consumido' => $consumido,
|
|
'percentual_consumido' => $limite > 0 ? round($consumido / $limite * 100, 2) : 0,
|
|
'bloqueado' => $consumido >= $limite,
|
|
'periodo_inicio' => $prestadorQtd->inicio,
|
|
'periodo_fim' => $prestadorQtd->fim,
|
|
];
|
|
}
|
|
}
|
|
|
|
if ($appConfig->percentual_financeiro) {
|
|
|
|
$prestadorValor = DB::table('exame_imagem_parametrizacao_cota_prestador')
|
|
->where('infraestrutura_id', $infraestruturaId)
|
|
->where('cota_tipo_id', Tipo::VALOR)
|
|
->where('inicio', '<=', $hoje)
|
|
->where('fim', '>=', $hoje)
|
|
->whereNull('deleted_at')
|
|
->first();
|
|
|
|
if ($prestadorValor) {
|
|
|
|
$limite = round($prestadorValor->cota_valor * $appConfig->percentual_financeiro / 100, 2);
|
|
|
|
$consumido = DB::table('exame_imagem_agendamento as ag')
|
|
->join('exame_imagem_agendamento_exame as ag_exame', 'ag_exame.agendamento_id', '=', 'ag.id')
|
|
->join('parametrizacao_exame as exame', 'exame.id', '=', 'ag_exame.exame_id')
|
|
->where('ag.infraestrutura_id', $infraestruturaId)
|
|
->where('ag.app_conectasus_cidadao', true)
|
|
->whereDate('ag.data', '>=', $prestadorValor->inicio)
|
|
->whereDate('ag.data', '<=', $prestadorValor->fim)
|
|
->whereNotIn('ag_exame.status_id', $statusExcluidos)
|
|
->sum('exame.valor');
|
|
|
|
$consumido = round((float) $consumido, 2);
|
|
|
|
$cotaValor = [
|
|
'percentual_limite' => (float) $appConfig->percentual_financeiro,
|
|
'limite' => $limite,
|
|
'consumido' => $consumido,
|
|
'percentual_consumido' => $limite > 0 ? round($consumido / $limite * 100, 2) : 0,
|
|
'bloqueado' => $consumido >= $limite,
|
|
'periodo_inicio' => $prestadorValor->inicio,
|
|
'periodo_fim' => $prestadorValor->fim,
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!$cotaQuantidade && !$cotaValor) {
|
|
|
|
return null;
|
|
}
|
|
|
|
$bloqueado = ($cotaQuantidade['bloqueado'] ?? false) || ($cotaValor['bloqueado'] ?? false);
|
|
|
|
return [
|
|
'bloqueado' => $bloqueado,
|
|
'quantidade' => $cotaQuantidade,
|
|
'valor' => $cotaValor,
|
|
];
|
|
}
|
|
|
|
private static function validarParametrizacaoHabilitada(): void
|
|
{
|
|
$habilitado = DB::table('exame_imagem_parametrizacao_integracao_aplicativo')
|
|
->value('habilita_agendamento_conectasus_cidadao');
|
|
|
|
if (!$habilitado) {
|
|
|
|
abort(Response::HTTP_FORBIDDEN, 'O agendamento de exame de imagem pelo ConectaSUS Cidadão não está habilitado.');
|
|
}
|
|
}
|
|
}
|