all()); } private static function validateIndex($request) { return $request->validate([ 'data_solicitacao' => [ 'nullable', 'required_without:data_coleta', 'date_format:Y-m-d', 'before_or_equal:' . Carbon::now()->format('Y-m-d'), ], 'data_coleta' => [ 'nullable', 'required_without:data_solicitacao', 'date_format:Y-m-d', ], 'nome_paciente' => [ 'nullable', 'string', 'max:150', ], 'status_id' => [ 'nullable', 'integer', Rule::exists(PedidoStatus::class, 'id'), ], ]); } public static function show($laboratorioId, $id) { $laboratorio = LaboratorioService::getLaboratorioModel($laboratorioId); $pedido = self::getPedidoModel($laboratorio, $id); $pedidos = self::getPedidos($laboratorio, (object) ['pedido_id' => $pedido->id]); if ($pedidos->isEmpty()) { throw new PedidoNotFoundException(); } return $pedidos->first(); } private static function getPedidos($laboratorio, $params) { $isIntegracaoParcial = (ParametrizacaoWebService::first()->tipo_id ?? null) === ParametrizacaoWebServiceTipo::PARCIAL; $pedidos = DB::table('exame_laboratorial_agendamento AS agendamento') ->join('cadastro_paciente AS paciente', 'paciente.id', 'agendamento.paciente_id') ->join('cadastro_cidadao AS paciente_cidadao', 'paciente_cidadao.id', 'paciente.cidadao_id') ->join('cadastro_sexo AS paciente_sexo', 'paciente_sexo.id', 'paciente_cidadao.sexo_id') ->join( 'cadastro_infraestrutura AS infraestrutura_solicitante', 'infraestrutura_solicitante.id', 'agendamento.infraestrutura_id' ) ->join( 'cadastro_unidade AS unidade_solicitante', 'unidade_solicitante.id', 'infraestrutura_solicitante.unidade_id' ) ->join('cadastro_usuario AS usuario_solicitante', 'usuario_solicitante.id', 'agendamento.medico_id') ->join( 'cadastro_cidadao AS usuario_cidadao_solicitante', 'usuario_cidadao_solicitante.id', 'usuario_solicitante.cidadao_id' ) ->leftJoin('cadastro_cidadao_telefone AS paciente_telefone', fn ($q) => $q ->on('paciente_telefone.cidadao_id', 'paciente_cidadao.id') ->where('paciente_telefone.id', fn ($q) => $q ->select('paciente_telefone2.id') ->from('cadastro_cidadao_telefone AS paciente_telefone2') ->whereColumn('paciente_telefone2.cidadao_id', 'paciente_cidadao.id') ->where('paciente_telefone2.principal', true) ->limit(1) ) ) ->leftJoin( 'cadastro_domicilio AS paciente_domicilio', 'paciente_domicilio.id', 'paciente_cidadao.domicilio_id' ) ->leftJoin( 'cadastro_endereco AS paciente_endereco', 'paciente_endereco.id', 'paciente_domicilio.endereco_id' ) ->leftJoin( 'cadastro_logradouro AS paciente_logradouro', 'paciente_logradouro.id', 'paciente_endereco.logradouro_id' ) ->leftJoin( 'cadastro_logradouro_tipo AS paciente_logradouro_tipo', 'paciente_logradouro_tipo.id', 'paciente_logradouro.tipo_id' ) ->leftJoin( 'cadastro_bairro AS paciente_logradouro_bairro', 'paciente_logradouro_bairro.id', 'paciente_logradouro.bairro_id' ) ->leftJoin( 'intranet.cadastro_municipio AS paciente_municipio', 'paciente_municipio.id', 'paciente_logradouro.municipio_id' ) ->leftJoin( 'cadastro_usuario_registro_tipo AS usuario_registro_tipo', 'usuario_registro_tipo.id', 'usuario_solicitante.registro_tipo_id' ) ->where('agendamento.laboratorio_infraestrutura_id', $laboratorio->conectasus_infraestrutura_id) ->where(fn ($q) => $q ->when($params->data_solicitacao ?? null, fn ($q, $data) => $q ->orWhereDate('agendamento.created_at', $data) ) ->when($params->data_coleta ?? null, fn ($q, $data) => $q ->orWhere('agendamento.data', $data) ) ) ->when($params->pedido_id ?? null, fn ($q, $id) => $q->where('agendamento.id', $id)) ->when($params->nome_paciente ?? null, fn ($q, $nome) => $q ->where('paciente_cidadao.nome', 'LIKE', "{$nome}%") ) ->when($params->status_id ?? null, fn ($q, $id) => $q ->where('agendamento.web_service_laboratorio_cliente_pedido_status_id', $id) ) ->when($isIntegracaoParcial, fn ($q) => $q ->whereNotExists(fn ($q) => $q ->selectRaw(1) ->from('exame_laboratorial_agendamento_exame AS agendamento_exame') ->whereColumn('agendamento_exame.agendamento_id', 'agendamento.id') ->whereNull('agendamento_exame.data_coleta') ) ) ->select( 'agendamento.id', 'agendamento.agendamento_numero as numero_agendamento', 'agendamento.web_service_laboratorio_cliente_pedido_status_id AS status_id', DB::raw("CAST(agendamento.created_at AS DATE) AS data_solicitacao"), 'paciente_cidadao.nome AS paciente_nome', 'paciente_cidadao.data_nascimento AS paciente_data_nascimento', DB::raw("TIMESTAMPDIFF(YEAR, paciente_cidadao.data_nascimento, NOW()) AS paciente_idade"), 'paciente_sexo.id AS paciente_sexo_id', 'paciente_sexo.descricao AS paciente_sexo_descricao', DB::raw("LPAD(paciente.prontuario, 7, '0') AS paciente_prontuario"), 'agendamento.gestante AS paciente_gestante', 'agendamento.ultima_menstruacao AS paciente_data_ultima_menstruacao', 'paciente_telefone.numero AS paciente_telefone', DB::raw("CONCAT(paciente_logradouro_tipo.descricao, ' ', paciente_logradouro.nome) AS paciente_logradouro_descricao"), 'paciente_endereco.numero AS paciente_logradouro_numero', 'paciente_logradouro_bairro.nome AS paciente_bairro_nome', 'paciente_logradouro.cep AS paciente_cep', 'paciente_municipio.nome AS paciente_municipio_nome', 'usuario_cidadao_solicitante.nome AS medico_solicitante_nome', DB::raw("IF( usuario_solicitante.registro_tipo_id = " . TipoRegistroUsuario::OUTRO . ", registro_tipo_outro, usuario_registro_tipo.sigla ) AS conselho_profissional_tipo_sigla"), 'usuario_solicitante.registro_numero AS conselho_profissional_numero', 'unidade_solicitante.id AS unidade_solicitante_id', 'unidade_solicitante.nome_fantasia AS unidade_solicitante_nome_fantasia', 'infraestrutura_solicitante.id AS local_atendimento_solicitante_id', DB::raw("COALESCE(infraestrutura_solicitante.nome, unidade_solicitante.nome_fantasia) AS local_atendimento_solicitante_nome") ) ->orderBy('agendamento.created_at') ->get(); $pedidos->each(function ($pedido) use ($laboratorio) { $pedido->itens = self::getPedidoItens($pedido, $laboratorio); if ($pedido->paciente_sexo_id !== Sexo::FEMININO) { unset($pedido->paciente_gestante, $pedido->paciente_data_ultima_menstruacao); } else { $pedido->paciente_gestante = (bool) $pedido->paciente_gestante; } self::setMovimentacaoFields($pedido); unset($pedido->paciente_sexo_id); }); return $pedidos; } private static function getPedidoItens($pedido, $laboratorio) { return DB::table('exame_laboratorial_agendamento_exame AS agendamento_exame') ->join( 'exame_laboratorial_agendamento AS agendamento', 'agendamento.id', 'agendamento_exame.agendamento_id' ) ->leftJoin('web_service_laboratorio_cliente_exame AS cliente_exame', fn ($q) => $q ->on('cliente_exame.conectasus_exame_id', 'agendamento_exame.exame_id') ->where('cliente_exame.laboratorio_id', $laboratorio->id) ) ->where('agendamento_exame.agendamento_id', $pedido->id) ->select( 'agendamento_exame.exame_id AS conectasus_exame_id', 'cliente_exame.id AS cliente_exame_id', 'agendamento.data AS data_coleta' ) ->orderBy('agendamento_exame.data_coleta') ->get(); } private static function setMovimentacaoFields($pedido) { $pedido->processado_em = null; $pedido->realizado_em = null; $pedido->cancelado_em = null; $pedido->motivo_cancelamento = null; self::getPedidoMovimentacoes($pedido)->each(function ($movimentacao) use ($pedido) { if ($movimentacao->status_id === PedidoStatusEnum::PROCESSANDO) { $pedido->processado_em = $movimentacao->movimentado_em; } else if ($movimentacao->status_id === PedidoStatusEnum::REALIZADO) { $pedido->realizado_em = $movimentacao->movimentado_em; } else if ($movimentacao->status_id === PedidoStatusEnum::CANCELADO_PELO_LABORATORIO) { $pedido->cancelado_em = $movimentacao->movimentado_em; $pedido->motivo_cancelamento = $movimentacao->motivo; } }); } private static function getPedidoMovimentacoes($pedido) { return DB::table('web_service_laboratorio_cliente_pedido_movimentacao AS movimentacao') ->where('movimentacao.conectasus_exame_laboratorial_agendamento_id', $pedido->id) ->select( 'movimentacao.status_id', 'movimentacao.motivo', 'movimentacao.movimentado_em', ) ->orderBy('movimentacao.movimentado_em') ->get(); } public static function process($laboratorioId, $id) { $laboratorio = LaboratorioService::getLaboratorioModel($laboratorioId); $pedido = self::getPedidoModel($laboratorio, $id); if ($pedido->web_service_laboratorio_cliente_pedido_status_id !== PedidoStatusEnum::AGUARDANDO_PROCESSAMENTO) { $mensagemStatus = null; if ($pedido->web_service_laboratorio_cliente_pedido_status_id === PedidoStatusEnum::CANCELADO_PELO_LABORATORIO) { $mensagemStatus = 'O status não pode ser alterado pois o pedido foi cancelado pelo laboratório.'; } else if ($pedido->web_service_laboratorio_cliente_pedido_status_id === PedidoStatusEnum::PROCESSANDO) { $mensagemStatus = 'O status não pode ser alterado pois o pedido já está em processamento.'; } else if ($pedido->web_service_laboratorio_cliente_pedido_status_id === PedidoStatusEnum::REALIZADO) { $mensagemStatus = 'O status não pode ser alterado pois o pedido já está realizado.'; } throw new CannotChangeStatusException($mensagemStatus); } else if (self::vinculoEntreExamesConectasusClienteIncompleto($laboratorio, $pedido)) { throw new IncompleteExameParametrizationException(); } DB::transaction(function () use ($pedido) { $pedido->update(['web_service_laboratorio_cliente_pedido_status_id' => PedidoStatusEnum::PROCESSANDO]); $pedido->refresh(); self::saveMovimentacao($pedido); }); } private static function vinculoEntreExamesConectasusClienteIncompleto($laboratorio, $pedido) { return $pedido->agendamentoExame() ->whereHas('exame', fn ($q) => $q ->whereDoesntHave('webServiceLaboratorioClienteExame', fn ($q) => $q ->where('laboratorio_id', $laboratorio->id) ) ) ->exists(); } public static function cancel($request, $laboratorioId, $id) { $laboratorio = LaboratorioService::getLaboratorioModel($laboratorioId); $pedido = self::getPedidoModel($laboratorio, $id); self::validateCancel($request); if ($pedido->web_service_laboratorio_cliente_pedido_status_id !== PedidoStatusEnum::PROCESSANDO) { $mensagemStatus = null; if ($pedido->web_service_laboratorio_cliente_pedido_status_id === PedidoStatusEnum::AGUARDANDO_PROCESSAMENTO) { $mensagemStatus = 'O status não pode ser alterado pois o pedido ainda não está em processamento.'; } else if ($pedido->web_service_laboratorio_cliente_pedido_status_id === PedidoStatusEnum::CANCELADO_PELO_LABORATORIO) { $mensagemStatus = 'O status não pode ser alterado pois o pedido já foi cancelado pelo laboratório.'; } else if ($pedido->web_service_laboratorio_cliente_pedido_status_id === PedidoStatusEnum::REALIZADO) { $mensagemStatus = 'O status não pode ser alterado pois o pedido já está realizado.'; } throw new CannotChangeStatusException($mensagemStatus); } DB::transaction(function () use ($request, $pedido) { $pedido->update(['web_service_laboratorio_cliente_pedido_status_id' => PedidoStatusEnum::CANCELADO_PELO_LABORATORIO]); $pedido->refresh(); self::saveMovimentacao($pedido, ['motivo' => $request->motivo]); }); } private static function validateCancel($request) { $request->validate([ 'motivo' => [ 'required', 'string', 'between:3,500', ], ]); } public static function storeResult($request, $laboratorioId, $id) { $laboratorio = LaboratorioService::getLaboratorioModel($laboratorioId); $pedido = self::getPedidoModel($laboratorio, $id); self::validateStoreResult($request); $allowedStatus = collect([ PedidoStatusEnum::PROCESSANDO, PedidoStatusEnum::REALIZADO ]); if (!$allowedStatus->contains($pedido->web_service_laboratorio_cliente_pedido_status_id)) { $mensagemStatus = null; if ($pedido->web_service_laboratorio_cliente_pedido_status_id === PedidoStatusEnum::AGUARDANDO_PROCESSAMENTO) { $mensagemStatus = 'O status não pode ser alterado pois o pedido ainda não está em processamento.'; } else if ($pedido->web_service_laboratorio_cliente_pedido_status_id === PedidoStatusEnum::CANCELADO_PELO_LABORATORIO) { $mensagemStatus = 'O status não pode ser alterado pois o pedido já foi cancelado pelo laboratório.'; } throw new CannotChangeStatusException($mensagemStatus); } else if ($pedido->data > Carbon::now()) { throw new CannotChangeStatusException('O status não pode ser alterado pois a data de coleta do pedido é maior que a data atual.'); } else if ($pedido->web_service_laboratorio_cliente_pedido_status_id === PedidoStatusEnum::PROCESSANDO && self::hasExameAgendado($pedido)) { throw new CannotChangeStatusException('O status não pode ser alterado pois o pedido está em processamento e existe um ou mais exames com o status agendado.'); } DB::transaction(function () use ($request, $pedido) { $path = 'exame-laboratorial' . DIRECTORY_SEPARATOR . 'laudos' . DIRECTORY_SEPARATOR . app('config')->get('database.default'); $laudo = AgendamentoLaudo::where('agendamento_id', $pedido->id)->where('is_enviado_webservice', true)->first(); if ($laudo) { if (is_null($laudo->url)) { if (Storage::disk('local')->exists($path . DIRECTORY_SEPARATOR . $laudo->arquivo)){ Storage::disk('local')->delete($path . DIRECTORY_SEPARATOR . $laudo->arquivo); } } $laudo->delete(); } $ordem = AgendamentoLaudo::where('agendamento_id', $pedido->id)->max('ordem') + 1; if (isset($request->url)) { $urlInfo = pathinfo(parse_url($request->url, PHP_URL_PATH)); AgendamentoLaudo::create([ 'agendamento_id' => $pedido->id, 'arquivo' => isset($urlInfo['filename']) && isset($urlInfo['extension']) ? "{$urlInfo['filename']}.{$urlInfo['extension']}" : $pedido->id . ($ordem === 1 ? '' : "_{$ordem}"), 'url' => $request->url, 'ordem' => $ordem, 'is_enviado_webservice' => true ]); } else { $base64Decoded = str_contains($request->base64, ',') ? base64_decode(explode(',', $request->base64)[1], true) : base64_decode($request->base64, true); $finfo = finfo_open(); $mime = finfo_buffer($finfo, $base64Decoded, FILEINFO_MIME_TYPE); finfo_close($finfo); $extension = explode('/', $mime)[1]; $fileName = $pedido->id . ($ordem === 1 ? '' : "_{$ordem}") . ".{$extension}"; Storage::disk('local')->put($path . DIRECTORY_SEPARATOR . $fileName, $base64Decoded); AgendamentoLaudo::create([ 'agendamento_id' => $pedido->id, 'arquivo' => $fileName, 'ordem' => $ordem, 'is_enviado_webservice' => true ]); } if ($pedido->web_service_laboratorio_cliente_pedido_status_id !== PedidoStatusEnum::REALIZADO) { $pedido->agendamentoExame->each(function ($agendamentoExame) { if ($agendamentoExame->status_id === StatusAgendamento::REALIZADO) { $agendamentoExame->update(['status_id' => StatusAgendamento::ASSINADO]); $agendamentoExame->refresh(); AgendamentoExameHistoricoService::store($agendamentoExame, $agendamentoExame->agendamento, Acao::ALTERACAO); } }); $pedido->update(['web_service_laboratorio_cliente_pedido_status_id' => PedidoStatusEnum::REALIZADO]); $pedido->refresh(); self::saveMovimentacao($pedido); } }); } private static function validateStoreResult($request) { $request->validate([ 'url' => [ Rule::requiredIf(fn () => !isset($request->base64)), 'prohibits:base64', 'string', 'max:300', ], 'base64' => [ Rule::requiredIf(fn () => !isset($request->url)), 'prohibits:url', function ($attribute, $value, $fail) { $decoded = str_contains($value, ',') ? base64_decode(explode(',', $value)[1], true) : base64_decode($value, true); if (!$decoded) { return $fail('Base64 inválido'); } $finfo = finfo_open(); $mime = finfo_buffer($finfo, $decoded, FILEINFO_MIME_TYPE); if ($mime !== 'application/pdf') { return $fail('O arquivo deve estar em um formato PDF válido'); } finfo_close($finfo); } ] ], [ 'url.prohibits' => 'O campo url não é permitido se o campo base64 estiver presente', 'base64.prohibits' => 'O campo base64 não é permitido se o campo url estiver presente' ]); } private static function hasExameAgendado($pedido) { return $pedido->agendamentoExame()->where('status_id', StatusAgendamento::AGENDADO)->exists(); } private static function getPedidoModel($laboratorio, $id) { $pedido = ExameLaboratorialAgendamento::where('laboratorio_infraestrutura_id', $laboratorio->conectasus_infraestrutura_id) ->where('id', $id) ->first(); if (is_null($pedido)) { throw new PedidoNotFoundException(); } return $pedido; } private static function saveMovimentacao($pedido, $params = []) { PedidoMovimentacao::create([ 'conectasus_exame_laboratorial_agendamento_id' => $pedido->id, 'status_id' => $pedido->web_service_laboratorio_cliente_pedido_status_id, 'motivo' => $params['motivo'] ?? null, 'movimentado_em' => Carbon::now(), ]); } }