Files
Antonio Lopes dos Santos afec302c3e
All checks were successful
build-api-image / build (push) Successful in 51s
init commit
2026-08-04 16:52:02 -03:00

709 lines
30 KiB
PHP

<?php
namespace App\Services\Mobile\ConectaCidadao\ExameLaboratorial;
use App\Enums\ExameLaboratorial\Acao;
use App\Enums\ExameLaboratorial\StatusAgendamento;
use App\Enums\ExameLaboratorial\TipoCota;
use App\Enums\ExameLaboratorial\TipoUnidade;
use App\Enums\Parametrizacao\Exame\Tipo;
use App\Enums\WebService\Laboratorio\Cliente\PedidoStatus;
use App\Models\Ambulatorio\AtendimentoSoapSolicitacaoExameItem;
use App\Models\Cadastro\Feriado\Feriado;
use App\Models\ExameLaboratorial\AgendamentoExame\Agendamento;
use App\Models\ExameLaboratorial\AgendamentoExame\AgendamentoExame;
use App\Services\ExameLaboratorial\AgendamentoExameHistoricoService;
use App\Services\Service;
use Carbon\Carbon;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
class AgendamentoExameService extends Service
{
public static function elegibilidade(): array
{
$parametrizacao = DB::table('exame_laboratorial_parametrizacao_integracao_aplicativo')->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.');
}
}
}