Contextualizando:
A funcionalidade de Cancelamento de consulta deve seguir tais regras de negocio:
É obrigatório informar o motivo do cancelamento da consulta, dentre as opções: paciente desistiu, médico cancelou ou outros;
Uma consulta somente poderá ser cancelada com antecedência mínima de 24 horas.
Dito isso, a forma que eu resolvi foi que o ConsultaRepository encontrasse a Consulta a partir de uma query que já verifica se a consulta agendada tem antecedência de 24 horas:
public interface ConsultaRepository extends JpaRepository<Consulta, Long> {
@Query("""
select c from Consulta c
where
c.id = :id
and
c.data > CURRENT_DATE + 1 DAY
""")
Optional<Consulta> findByIdWhereIntervalDay(Long id);
}
Ou seja:
Supondo que:
MM-DDThh:mm:ss
Se o paciente marcou a consulta em:
03-04T10:00:00
Então ele poderia cancelar até o dia:
03-03T09:59:59
Ou seja, um dia antes do dia da consulta
De resto foi o feijão com o arroz:
Em DadosCancelamentoConsulta:
public record DadosCancelamentoConsulta(
@NotNull Long id,
@NotNull MotivoDeCancelamento motivo) {
}
Em MotivoDeCancelamento:
public enum MotivoDeCancelamento {
PACIENTE_DESISTIU,
MEDICO_CANCELOU,
OUTROS
}
Em ConsultaController:
@DeleteMapping("/cancelar")
@Transactional
public ResponseEntity<Void> calcelarConsulta(@RequestBody @Valid DadosCancelamentoConsulta dados) {
agenda.cancelar(dados);
return ResponseEntity.noContent().build();
}
Em AgendaDeConsultas:
public void cancelar(DadosCancelamentoConsulta dados) {
if (!consultaRepository.existsById(dados.id())) {
throw new ValidacaoException("O id informado não existe");
}
var optional = consultaRepository.findByIdWhereIntervalDay(dados.id());
if (optional.isEmpty()) {
throw new ValidacaoException(
"A consulta informada não pode ser cancelada, pois uma consulta só pode ser cancelada com antecedência mínima de 24 horas.");
}
consultaRepository.deleteById(optional.get().getId());
}
Vale resaltar que neste exemplo eu não fiz nada com o motivo de cancelamento, apenas verifiquei se existia (com a anotação @NotNull no record DadosCancelamentoConsulta ), tanto é que a classe Consulta não tem um atributo que guarda o motivo.