Spring Boot 3: doc, test y prep. para impl.: Cancelar consulta

This commit is contained in:
devfzn 2023-09-19 00:26:59 -03:00
parent a51a1cc54b
commit cef7520584
Signed by: devfzn
GPG Key ID: E070ECF4A754FDB1
8 changed files with 106 additions and 5 deletions

View File

@ -3,14 +3,16 @@ package med.voll.api.controller;
import jakarta.validation.Valid;
import med.voll.api.domain.consulta.AgendaDeConsultaService;
import med.voll.api.domain.consulta.DatosAgendarConsulta;
import med.voll.api.domain.consulta.DatosCancelarConsulta;
import med.voll.api.domain.consulta.DatosDetalleConsulta;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.*;
@Controller
@ResponseBody
@ -28,4 +30,19 @@ public class ConsultaController {
return ResponseEntity.ok(response);
}
@GetMapping
public ResponseEntity<Page<DatosDetalleConsulta>> listar(
@PageableDefault(size = 10, sort = {"fecha"}) Pageable paginacion) {
var response = service.consultar(paginacion);
return ResponseEntity.ok(response);
}
@DeleteMapping
@Transactional
public ResponseEntity cancelar(@RequestBody @Valid DatosCancelarConsulta dados) {
service.cancelar(dados);
return ResponseEntity.noContent().build();
}
}

View File

@ -1,11 +1,14 @@
package med.voll.api.domain.consulta;
import med.voll.api.domain.consulta.validaciones.ValidadorDeConsultas;
import med.voll.api.domain.consulta.validaciones_cancelacion.ValidadorDeCancelacionDeConsulta;
import med.voll.api.domain.medico.Medico;
import med.voll.api.domain.medico.MedicoRepository;
import med.voll.api.domain.paciente.PacienteRepository;
import med.voll.api.infra.errores.ValidacionDeIntegridad;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
@ -23,6 +26,9 @@ public class AgendaDeConsultaService {
@Autowired
List<ValidadorDeConsultas> validadores;
@Autowired
List<ValidadorDeCancelacionDeConsulta> validadoresDeCancelacion;
public DatosDetalleConsulta agendar(DatosAgendarConsulta datos) {
if (!pacienteRepository.findById(datos.idPaciente()).isPresent()) {
@ -39,7 +45,7 @@ public class AgendaDeConsultaService {
if (medico == null) {
throw new ValidacionDeIntegridad("No hay especialistas disponibles para este horario");
}
var consulta = new Consulta(null, medico, paciente, datos.fecha());
var consulta = new Consulta(medico, paciente, datos.fecha());
consultaRepository.save(consulta);
return new DatosDetalleConsulta(consulta);
@ -54,4 +60,19 @@ public class AgendaDeConsultaService {
}
return medicoRepository.seleccionarMedicoConEspecialidadEnFecha(datos.especialidad(), datos.fecha());
}
public void cancelar(DatosCancelarConsulta datos) {
if (!consultaRepository.existsById(datos.idConsulta())) {
throw new ValidacionDeIntegridad("Id de consulta inexistente");
}
validadoresDeCancelacion.forEach(v -> v.validar(datos));
var consulta = consultaRepository.getReferenceById(datos.idConsulta());
consulta.cancelar(datos.motivo());
}
public Page<DatosDetalleConsulta> consultar(Pageable paginacion) {
return consultaRepository.findAll(paginacion).map(DatosDetalleConsulta::new);
}
}

View File

@ -32,4 +32,17 @@ public class Consulta {
private LocalDateTime fecha;
@Column(name ="motivo_cancelacion")
@Enumerated(EnumType.STRING)
private MotivoCancelacion motivo;
public Consulta(Medico medico, Paciente paciente, LocalDateTime fecha) {
this.medico=medico;
this.paciente=paciente;
this.fecha=fecha;
}
public void cancelar(MotivoCancelacion motivo) {
this.motivo = motivo;
}
}

View File

@ -0,0 +1,7 @@
package med.voll.api.domain.consulta;
import jakarta.validation.constraints.NotNull;
public record DatosCancelarConsulta(@NotNull Long idConsulta,
@NotNull MotivoCancelacion motivo) {
}

View File

@ -0,0 +1,7 @@
package med.voll.api.domain.consulta;
public enum MotivoCancelacion {
PACIENTE_DESISTE,
MEDICO_CANCELA,
OTRO;
}

View File

@ -0,0 +1,8 @@
package med.voll.api.domain.consulta.validaciones_cancelacion;
import med.voll.api.domain.consulta.DatosAgendarConsulta;
import med.voll.api.domain.consulta.DatosCancelarConsulta;
public interface ValidadorDeCancelacionDeConsulta {
void validar(DatosCancelarConsulta datos);
}

View File

@ -0,0 +1,27 @@
package med.voll.api.domain.consulta.validaciones_cancelacion;
import jakarta.validation.ValidationException;
import med.voll.api.domain.consulta.ConsultaRepository;
import med.voll.api.domain.consulta.DatosCancelarConsulta;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.LocalDateTime;
@Component("ValidadorHorarioAnticipacion")
public class ValidadorHorarioAnticipacionCancelacion implements ValidadorDeCancelacionDeConsulta {
@Autowired
private ConsultaRepository repository;
@Override
public void validar(DatosCancelarConsulta datos) {
var consulta = repository.getReferenceById(datos.idConsulta());
var ahora = LocalDateTime.now();
var diferenciaEnHoras = Duration.between(ahora, consulta.getFecha()).toHours();
if (diferenciaEnHoras < 24) {
throw new ValidationException("La consulta solo se puede cancelar con 24 horas de anticipación");
}
}
}

View File

@ -0,0 +1 @@
alter table consultas add motivo_cancelacion varchar(100);