init commit
All checks were successful
build-api-image / build (push) Successful in 51s

This commit is contained in:
Antonio Lopes dos Santos
2026-08-04 16:52:02 -03:00
commit afec302c3e
11594 changed files with 1636728 additions and 0 deletions

View File

@@ -0,0 +1,976 @@
<?php
namespace App\Services\Ambulatorio;
use App\Enums\Administracao\Modulo;
use App\Enums\Ambulatorio\AgendamentoStatus;
use App\Enums\Ambulatorio\AgendamentoTipo;
use App\Enums\Ambulatorio\JornadaTipo;
use App\Models\Ambulatorio\Agendamento;
use App\Models\Ambulatorio\Jornada;
use App\Models\Cadastro\Especialidade;
use App\Models\Cadastro\Estabelecimento\Infraestrutura;
use App\Models\Cadastro\Estabelecimento\Unidade;
use App\Models\Cadastro\Feriado\Feriado;
use App\Models\Cadastro\SujeitoAtencao\Usuario;
use App\Models\Geral\DiaSemana;
use App\Models\Sigtap\Procedimento;
use App\Services\Regulacao\SolicitacaoService as RegulacaoSolicitacaoService;
use App\Services\Service;
use App\Services\Sigtap\ProcedimentoValidationService;
use App\Utils\MaskUtil;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
class GerenciamentoMedicoService extends Service
{
public static function datatable()
{
$usuarios = DB::table('cadastro_usuario')
->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}%"]
);
})
->skipTotalRecords()
->toJson();
}
public static function edit($usuarioId)
{
$usuario = Usuario::findOrFail($usuarioId);
return [
'form' => self::getFormData($usuario),
'model' => self::getModelData(),
];
}
private static function getFormData($usuario)
{
return [
'usuario' => self::getUsuarioData($usuario),
'origem' => [
'feriados' => self::getFeriados(),
'unidades' => self::getOrigemUnidades((object) ['usuario_id' => $usuario->id]),
'infraestruturas' => [],
'ocupacoes' => [],
'especialidades' => [],
'datas' => [],
'agendamentos' => [],
],
'destino' => [
'unidades' => [],
'infraestruturas' => [],
'ocupacoes' => [],
'especialidades' => [],
'usuarios' => [],
'jornadas' => [],
]
];
}
private static function getUsuarioData($usuario)
{
$cidadao = $usuario->cidadao()->setEagerLoads([])->first(['nome', 'data_nascimento', 'cns', 'cpf']);
return [
'nome' => $cidadao->nome,
'data_nascimento' => is_null($cidadao->data_nascimento)
? null : (new Carbon($cidadao->data_nascimento))->format('d/m/Y'),
'cns' => MaskUtil::getCnsMasked($cidadao->cns),
'cpf' => MaskUtil::getCpfMasked($cidadao->cpf),
];
}
private static function getModelData()
{
return [
'origem' => [
'unidade_id' => null,
'infraestrutura_id' => null,
'ocupacao_id' => null,
'especialidade_id' => null,
'data' => null,
],
'destino' => [
'unidade_id' => null,
'infraestrutura_id' => null,
'ocupacao_id' => null,
'especialidade_id' => null,
'usuario_id' => null,
'agendamentos' => [],
'jornada_id' => null,
'motivo_agendamento_excedente' => null,
],
'cancelamento' => [
'agendamentos' => [],
'motivo' => null,
]
];
}
public static function list()
{
$params = (object) request()->all();
switch (request()->origem) {
case 'origem': {
return self::getListOrigemData($params);
}
case 'destino': {
return self::getListDestinoData($params);
}
}
}
private static function getListOrigemData($params)
{
switch (request()->listar) {
case 'infraestruturas': {
return [
'infraestruturas' => self::getOrigemInfraestruturas($params),
'ocupacoes' => [],
'especialidades' => [],
'datas' => [],
'agendamentos' => [],
];
}
case 'ocupacoes': {
return [
'ocupacoes' => self::getOrigemOcupacoes($params),
'especialidades' => [],
'datas' => [],
'agendamentos' => [],
];
}
case 'especialidades': {
return [
'especialidades' => self::getOrigemEspecialidades($params),
'datas' => [],
'agendamentos' => [],
];
}
case 'datas': {
return [
'datas' => self::getOrigemDatas($params),
'agendamentos' => [],
];
}
case 'agendamentos': {
return [
'agendamentos' => self::getOrigemAgendamentos($params),
];
}
}
}
private static function getOrigemUnidades($params)
{
return Unidade::whereHas('infraestruturas', fn ($q) => $q
->whereHas('lotacoes', fn ($q) => $q
->where('usuario_id', $params->usuario_id)
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereDate('data', '>=', Carbon::today())
->whereHas('agendamentos', fn ($q) => $q
->where('status_id', AgendamentoStatus::AGENDADO)
)
)
)
)
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']);
}
private static function getOrigemInfraestruturas($params)
{
return Infraestrutura::setEagerLoads([])
->where('unidade_id', $params->unidade_id)
->whereHas('lotacoes', fn ($q) => $q
->where('usuario_id', $params->usuario_id)
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereDate('data', '>=', Carbon::today())
->whereHas('agendamentos', fn ($q) => $q
->where('status_id', AgendamentoStatus::AGENDADO)
)
)
)
->get(['id', 'nome', 'principal', 'unidade_id'])
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome,
])
->sortBy('nome')
->values();
}
private static function getOrigemOcupacoes($params)
{
return DB::table('sigtap.ocupacao as ocupacao')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('cadastro_lotacao as lotacao')
->whereColumn('lotacao.ocupacao_id', 'ocupacao.id')
->where('lotacao.usuario_id', $params->usuario_id)
->where('lotacao.infraestrutura_id', $params->infraestrutura_id)
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('ambulatorio_jornada as jornada')
->whereColumn('jornada.lotacao_id', 'lotacao.id')
->whereDate('jornada.data', '>=', Carbon::today())
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('ambulatorio_agendamento as agendamento')
->whereColumn('agendamento.jornada_id', 'jornada.id')
->where('status_id', AgendamentoStatus::AGENDADO)
)
)
)
->orderByRaw("CONCAT(ocupacao.codigo, ' - ', ocupacao.nome)")
->select(
'ocupacao.id',
DB::raw("CONCAT(ocupacao.codigo, ' - ', ocupacao.nome) as descricao")
)
->get();
}
private static function getOrigemEspecialidades($params)
{
return Especialidade::where('ocupacao_id', $params->ocupacao_id)
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereDate('data', '>=', Carbon::today())
->whereHas('lotacao', fn ($q) => $q
->where('usuario_id', $params->usuario_id)
->where('infraestrutura_id', $params->infraestrutura_id)
)
->whereHas('agendamentos', fn ($q) => $q
->where('status_id', AgendamentoStatus::AGENDADO)
)
)
->orderBy('nome')
->get(['id', 'nome']);
}
private static function getOrigemDatas($params)
{
$feriados = self::getFeriados()->map(fn ($f) => Carbon::createFromFormat('d/m/Y', $f->data)->setTime(0, 0));
$datas = Jornada::whereDate('data', '>=', Carbon::today())
->where('especialidade_id', $params->especialidade_id)
->whereHas('lotacao', fn ($q) => $q
->where('usuario_id', $params->usuario_id)
->where('infraestrutura_id', $params->infraestrutura_id)
)
->whereHas('agendamentos', fn ($q) => $q
->where('status_id', AgendamentoStatus::AGENDADO)
)
->groupBy('data')
->select(
'data',
DB::raw("(
SUM(COALESCE(quantidade_consulta, 0))
+
SUM(COALESCE(quantidade_retorno, 0))
) as quantidade_total")
)
->get()
->reject(fn ($d) => $feriados->contains($d->data))
->values();
$datas->each(function ($data) use ($params) {
$data->quantidade_total = (int) $data->quantidade_total;
$data->quantidade_agendada = Agendamento::whereNotIn('status_id', self::getStatusLiberamHorario())
->whereHas('jornada', fn ($q) => $q
->whereDate('data', $data->data)
->whereHas('lotacao', fn ($q) => $q
->where('usuario_id', $params->usuario_id)
->where('infraestrutura_id', $params->infraestrutura_id)
)
)
->count();
});
return $datas;
}
private static function getFeriados()
{
return Feriado::whereHas('modulos', fn ($q) => $q
->where('identificador', Modulo::AMBULATORIO)
)
->orderBy('data')
->get()
->map(fn ($feriado) => (object) [
'data' => (new Carbon($feriado->data))->format('d/m/Y'),
'tipo_descricao' => $feriado->tipo->descricao,
'observacao' => $feriado->observacao,
]);
}
private static function getOrigemAgendamentos($params)
{
return Agendamento::where('status_id', AgendamentoStatus::AGENDADO)
->whereHas('jornada', fn ($q) => $q
->whereDate('data', Carbon::createFromFormat('d/m/Y', $params->data))
->where('especialidade_id', $params->especialidade_id)
->whereHas('lotacao', fn ($q) => $q
->where('usuario_id', $params->usuario_id)
->where('infraestrutura_id', $params->infraestrutura_id)
)
)
->get(['id', 'jornada_id', 'horario', 'tipo_id', 'paciente_id', 'regulacao_solicitacao_id', 'created_lotacao_id'])
->map(function ($agendamento) {
$paciente = $agendamento->paciente()->setEagerLoads([])->first(['cidadao_id', 'prontuario']);
$cidadao = $paciente->cidadao()->setEagerLoads([])->first(['id', 'nome', 'data_nascimento']);
$tipo = $agendamento->tipo()->first(['id', 'nome']);
return (object) [
'id' => $agendamento->id,
'is_from_regulacao' => !is_null($agendamento->regulacao_solicitacao_id),
'horario' => $agendamento->horario->format('H:i'),
'tipo_id' => $tipo->id,
'tipo_nome' => $tipo->nome,
'paciente_nome' => $cidadao->nome,
'paciente_data_nascimento' => is_null($cidadao->data_nascimento)
? null : (new Carbon($cidadao->data_nascimento))->format('d/m/Y'),
'paciente_prontuario' => $paciente->prontuario,
'paciente_telefone' => MaskUtil::getPhoneMasked($paciente->cidadao->telefone_principal->numero ?? null),
'usuario_agendador_nome' => $agendamento->createdLotacao()
->first('usuario_id')
->usuario()
->setEagerLoads([])
->first('cidadao_id')
->cidadao()
->setEagerLoads([])
->first('nome')
->nome
];
})
->sortBy([
['horario', 'asc'],
['paciente_nome', 'asc'],
])
->values();
}
private static function getListDestinoData($params)
{
switch (request()->listar) {
case 'unidades': {
return [
'unidades' => self::getDestinoUnidades(),
'infraestruturas' => [],
'ocupacoes' => [],
'especialidades' => [],
'usuarios' => [],
'jornadas' => [],
];
}
case 'infraestruturas': {
return [
'infraestruturas' => self::getDestinoInfraestruturas($params),
'ocupacoes' => [],
'especialidades' => [],
'usuarios' => [],
'jornadas' => [],
];
}
case 'ocupacoes': {
return [
'ocupacoes' => self::getDestinoOcupacoes($params),
'especialidades' => [],
'usuarios' => [],
'jornadas' => [],
];
}
case 'especialidades': {
return [
'especialidades' => self::getDestinoEspecialidades($params),
'usuarios' => [],
'jornadas' => [],
];
}
case 'usuarios': {
return [
'usuarios' => self::getDestinoUsuarios($params),
'jornadas' => [],
];
}
case 'jornadas': {
return [
'jornadas' => self::getDestinoJornadas($params),
];
}
}
}
private static function getDestinoUnidades()
{
return Unidade::whereHas('infraestruturas', fn ($q) => $q
->whereHas('lotacoes', fn ($q) => $q
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereNull('situacao_id')
->whereDate('data', '>=', Carbon::today())
)
)
)
->orderBy('nome_fantasia')
->get(['id', 'nome_fantasia']);
}
private static function getDestinoInfraestruturas($params)
{
return Infraestrutura::setEagerLoads([])
->where('unidade_id', $params->unidade_id)
->whereHas('lotacoes', fn ($q) => $q
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereNull('situacao_id')
->whereDate('data', '>=', Carbon::today())
)
)
->get(['id', 'nome', 'principal', 'unidade_id'])
->map(fn ($infraestrutura) => [
'id' => $infraestrutura->id,
'nome' => $infraestrutura->nome
])
->sortBy('nome')
->values();
}
private static function getDestinoOcupacoes($params)
{
return DB::table('sigtap.ocupacao as ocupacao')
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('cadastro_lotacao as lotacao')
->whereColumn('lotacao.ocupacao_id', 'ocupacao.id')
->where('lotacao.infraestrutura_id', $params->infraestrutura_id)
->whereExists(fn ($q) => $q
->select(DB::raw(1))
->from('ambulatorio_jornada as jornada')
->whereColumn('jornada.lotacao_id', 'lotacao.id')
->whereNull('jornada.situacao_id')
->whereDate('jornada.data', '>=', Carbon::today())
)
)
->orderByRaw("CONCAT(ocupacao.codigo, ' - ', ocupacao.nome)")
->select(DB::raw("
ocupacao.id,
CONCAT(ocupacao.codigo, ' - ', ocupacao.nome) as descricao
"))
->get();
}
private static function getDestinoEspecialidades($params)
{
return Especialidade::where('ocupacao_id', $params->ocupacao_id)
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereNull('situacao_id')
->whereDate('data', '>=', Carbon::today())
->whereHas('lotacao', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
)
)
->orderBy('nome')
->get(['id', 'nome']);
}
private static function getDestinoUsuarios($params)
{
return Usuario::setEagerLoads([])
->whereHas('lotacoes', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->whereHas('ambulatorioJornadas', fn ($q) => $q
->whereNull('situacao_id')
->whereDate('data', '>=', Carbon::today())
->where('especialidade_id', $params->especialidade_id)
)
)
->get(['id', 'cidadao_id'])
->map(fn ($usuario) => [
'id' => $usuario->id,
'nome' => $usuario->cidadao()->setEagerLoads([])->first(['nome'])->nome,
])
->sortBy('nome')
->values();
}
private static function getDestinoJornadas($params)
{
return Jornada::whereNull('situacao_id')
->whereDate('data', '>=', Carbon::today())
->where('especialidade_id', $params->especialidade_id)
->whereHas('lotacao', fn ($q) => $q
->where('infraestrutura_id', $params->infraestrutura_id)
->where('usuario_id', $params->usuario_id)
)
->select(
'id',
'data',
'inicio',
'fim',
DB::raw("COALESCE(quantidade_consulta, 0) as quantidade_consulta_total"),
DB::raw("COALESCE(quantidade_retorno, 0) as quantidade_retorno_total")
)
->get()
->map(function ($jornada) {
return [
'id' => $jornada->id,
'data' => $jornada->data->format('d/m/Y'),
'dia_semana' => DiaSemana::findOrFail($jornada->dia_semana)->descricao,
'inicio' => $jornada->inicio->format('H:i'),
'fim' => $jornada->fim->format('H:i'),
'quantidade_consulta_agendada' => Agendamento::where('jornada_id', $jornada->id)
->where('tipo_id', AgendamentoTipo::CONSULTA)
->whereNotIn('status_id', self::getStatusLiberamHorario())
->count(),
'quantidade_consulta_total' => (int) $jornada->quantidade_consulta_total,
'quantidade_retorno_agendado' => Agendamento::where('jornada_id', $jornada->id)
->where('tipo_id', AgendamentoTipo::RETORNO)
->whereNotIn('status_id', self::getStatusLiberamHorario())
->count(),
'quantidade_retorno_total' => (int) $jornada->quantidade_retorno_total,
];
});
}
public static function reschedule()
{
self::validateReschedule();
$agendamentosNaoReagendados = (object) [
'status_nao_permite_alteracao' => collect(),
'incompativel_com_especialidade' => collect(),
];
DB::transaction(function () use ($agendamentosNaoReagendados) {
collect(request()->agendamentos)->each(function ($id) use ($agendamentosNaoReagendados) {
$agendamentoAnterior = Agendamento::findOrFail($id);
if ($agendamentoAnterior->status_id === AgendamentoStatus::AGENDADO) {
$jornada = Jornada::findOrFail(request()->jornada_id);
if (self::isPacienteValidForEspecialidade($agendamentoAnterior->paciente, $jornada->especialidade)) {
$agendamentoAnterior->update(['status_id' => AgendamentoStatus::REAGENDADO_PELO_MEDICO]);
$nextHorario = self::getNextHorario($jornada, $agendamentoAnterior->tipo_id);
$agendamentoNovo = Agendamento::create([
'agendamento_anterior_id' => $agendamentoAnterior->id,
'jornada_id' => $jornada->id,
'tipo_id' => $agendamentoAnterior->tipo_id,
'horario' => $nextHorario->horario,
'paciente_id' => $agendamentoAnterior->paciente_id,
'motivo_agendamento_excedente' => $nextHorario->is_excedente
? request()->motivo_agendamento_excedente : null,
'observacao' => $agendamentoAnterior->observacao,
'status_id' => AgendamentoStatus::AGENDADO,
]);
(new SmsService($agendamentoAnterior->id))->cancel();
(new SmsService($agendamentoNovo->id))->send();
}
else {
$agendamentosNaoReagendados->incompativel_com_especialidade->push($agendamentoAnterior->id);
}
}
else {
$agendamentosNaoReagendados->status_nao_permite_alteracao->push($agendamentoAnterior->id);
}
});
});
return (object) ['agendamentos_nao_reagendados' => $agendamentosNaoReagendados];
}
private static function validateReschedule()
{
request()->validate([
'agendamentos' => [
'required',
'array',
],
'agendamentos.*' => [
'required',
'integer',
Rule::exists(Agendamento::class, 'id'),
],
'jornada_id' => [
'required',
'integer',
Rule::exists(Jornada::class, 'id'),
function ($attribute, $value, $fail) {
$hasAgendamentoConsulta = false;
$hasAgendamentoRetorno = false;
collect(request()->agendamentos)
->each(function ($id) use (&$hasAgendamentoConsulta, &$hasAgendamentoRetorno) {
$agendamento = Agendamento::findOrFail($id);
if ($agendamento->tipo_id === AgendamentoTipo::CONSULTA) {
$hasAgendamentoConsulta = true;
}
else if ($agendamento->tipo_id === AgendamentoTipo::RETORNO) {
$hasAgendamentoRetorno = true;
}
});
$jornada = Jornada::findOrFail($value);
if (($hasAgendamentoConsulta && is_null($jornada->quantidade_consulta))
|| ($hasAgendamentoRetorno && is_null($jornada->quantidade_retorno))
) {
$fail("A jornada não é compatível com os agendamentos.");
}
}
],
'motivo_agendamento_excedente' => [
'nullable',
'string',
'max:500',
]
]);
}
private static function isPacienteValidForEspecialidade($paciente, $especialidade)
{
$idade = $paciente->cidadao->idade['anos'];
$sexo = $paciente->cidadao->sexo;
if (!is_null($especialidade->sexo_id) && $especialidade->sexo_id !== $sexo->id) {
return false;
}
if ((!is_null($especialidade->idade_minima) && $idade < $especialidade->idade_minima)
|| (!is_null($especialidade->idade_maxima) && $idade > $especialidade->idade_maxima)
) {
return false;
}
if (!is_null($especialidade->procedimento_grupo_codigo)) {
$procedimento = Procedimento::where('codigo', $especialidade->procedimento_grupo_codigo)
->orderByDesc('competencia_id')
->first();
$validator = new ProcedimentoValidationService($procedimento);
if (!$validator->isSexoValid($sexo) || !$validator->isIdadeValid($idade)) {
return false;
}
}
return true;
}
private static function getNextHorario($jornada, $agendamentoTipoId)
{
$nextHorario = (object) [
'horario' => null,
'is_excedente' => false,
];
if ($jornada->tipo_id === JornadaTipo::FIXA) {
$quantidadeAgendada = Agendamento::where('jornada_id', $jornada->id)
->where('tipo_id', $agendamentoTipoId)
->whereTime('horario', $jornada->inicio)
->whereNotIn('status_id', self::getStatusLiberamHorario())
->count();
$nextHorario->horario = $jornada->inicio->format('H:i');
$nextHorario->is_excedente = $quantidadeAgendada >= $jornada->{self::getCampoQuantidade($agendamentoTipoId)};
}
else if ($jornada->tipo_id === JornadaTipo::DINAMICA) {
$horarios = collect();
$agendamentos = self::getAgendamentos($jornada->id);
$agendamentos->each(fn ($a) => $a->horario = $jornada->inicio->copy()->setTimeFromTimeString($a->horario));
$agendamentos->where('tipo_id', $agendamentoTipoId)
->each(fn ($agendamento) => $horarios->push((object) [
'horario' => $agendamento->horario->format('H:i'),
'quantidade_agendada' => $agendamento->quantidade_agendada,
'quantidade_total' => 1,
]));
$quantidade = $agendamentos->where('tipo_id', $agendamentoTipoId)->count();
if ($quantidade < $jornada->{self::getCampoQuantidade($agendamentoTipoId)}) {
$data = $jornada->inicio->copy();
self::setHorarioJornadaDinamica(
$horarios,
$agendamentos,
$jornada,
$agendamentoTipoId,
$quantidade,
$data
);
}
$horarios = $horarios->sortBy('horario')->values();
$horario = $horarios->where('quantidade_agendada', 0)->first();
if (is_null($horario)) {
$horario = $horarios->last();
}
$nextHorario->horario = $horario->horario;
$nextHorario->is_excedente = $horario->quantidade_agendada >= $horario->quantidade_total;
}
return $nextHorario;
}
private static function getAgendamentos($jornadaId)
{
return Agendamento::where('jornada_id', $jornadaId)
->whereNotIn('status_id', self::getStatusLiberamHorario())
->groupBy([
'tipo_id',
'horario',
])
->orderBy('horario')
->select(
'tipo_id',
'horario',
DB::raw("COUNT(id) as quantidade_agendada")
)
->get();
}
private static function getStatusLiberamHorario()
{
return [
AgendamentoStatus::REAGENDADO_PELO_PACIENTE,
AgendamentoStatus::REAGENDADO_PELO_MEDICO,
AgendamentoStatus::CANCELADO_PELO_PACIENTE,
AgendamentoStatus::CANCELADO_PELO_MEDICO,
];
}
private static function setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data)
{
$agendamento = $agendamentos->where('horario', $data)->first();
if (is_null($agendamento)) {
$final = $data->copy()->addMinutes($jornada->{self::getCampoTempo($tipoId)});
$agendamento = $agendamentos
->where('horario', '>', $data)
->where('horario', '<', $final)
->first();
if ($agendamento) {
self::setHorarioJornadaDinamica(
$horarios,
$agendamentos,
$jornada,
$tipoId,
$quantidade,
$agendamento->horario
);
}
else {
$horarios->push((object) [
'horario' => $data->format('H:i'),
'quantidade_agendada' => 0,
'quantidade_total' => 1,
]);
if (++$quantidade < $jornada->{self::getCampoQuantidade($tipoId)}) {
$data->addMinutes($jornada->{self::getCampoTempo($tipoId)});
self::setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data);
}
}
}
else {
if ($agendamento->tipo_id == $tipoId) {
$data->addMinutes($jornada->{self::getCampoTempo($tipoId)});
self::setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data);
}
else {
$data = $agendamento->horario->copy()->addMinutes($jornada->{self::getCampoTempo($tipoId, true)});
self::setHorarioJornadaDinamica($horarios, $agendamentos, $jornada, $tipoId, $quantidade, $data);
}
}
}
private static function getCampoQuantidade($tipoId)
{
if ($tipoId === AgendamentoTipo::CONSULTA) {
return 'quantidade_consulta';
}
else if ($tipoId === AgendamentoTipo::RETORNO) {
return 'quantidade_retorno';
}
}
private static function getCampoTempo($tipoId, $inverso = false)
{
if ($tipoId === AgendamentoTipo::CONSULTA) {
return $inverso ? 'tempo_retorno' : 'tempo_consulta';
}
else if ($tipoId === AgendamentoTipo::RETORNO) {
return $inverso ? 'tempo_consulta' : 'tempo_retorno';
}
}
public static function cancel()
{
self::validateCancel();
$agendamentosNaoCancelados = (object) [
'status_nao_permite_alteracao' => collect()
];
DB::transaction(function () use ($agendamentosNaoCancelados) {
collect(request()->agendamentos)->each(function ($id) use ($agendamentosNaoCancelados) {
$agendamento = Agendamento::findOrFail($id);
if ($agendamento->status_id === AgendamentoStatus::AGENDADO) {
$agendamento->update([
'status_id' => AgendamentoStatus::CANCELADO_PELO_MEDICO,
'motivo_cancelamento' => request()->motivo,
]);
(new SmsService($agendamento->id))->cancel();
if (!is_null($agendamento->regulacao_solicitacao_id)) {
RegulacaoSolicitacaoService::voltarParaStatusSolicitado($agendamento->regulacao_solicitacao_id);
}
}
else {
$agendamentosNaoCancelados->status_nao_permite_alteracao->push($id);
}
});
});
return (object) ['agendamentos_nao_cancelados' => $agendamentosNaoCancelados];
}
private static function validateCancel()
{
request()->validate([
'agendamentos' => [
'required',
'array',
],
'agendamentos.*' => [
'required',
'integer',
Rule::exists(Agendamento::class, 'id'),
],
'motivo' => [
'required',
'string',
'max:500',
],
]);
}
}