From 5de590eacdd811c74aa643a4e0d8b50e9fa123ad Mon Sep 17 00:00:00 2001 From: plnsliyanage Date: Sat, 21 Mar 2026 15:58:40 +0530 Subject: [PATCH] Resheduling of booking part done --- mainservice/pom.xml | 5 ++ .../AdminAppointmentController.java | 72 +++++++++++++++---- .../controller/AppointmentController.java | 51 +++++++++++-- .../mainservice/dto/AppointmentDTO.java | 3 +- .../mainservice/entity/Appointment.java | 11 ++- .../service/AppointmentService.java | 72 ++++++++++++------- 6 files changed, 161 insertions(+), 53 deletions(-) diff --git a/mainservice/pom.xml b/mainservice/pom.xml index e04b823..c7de6de 100644 --- a/mainservice/pom.xml +++ b/mainservice/pom.xml @@ -9,6 +9,11 @@ mainservice Archetype - mainservice http://maven.apache.org + + 17 + 17 + 17 + diff --git a/mainservice/src/main/java/com/example/mainservice/controller/AdminAppointmentController.java b/mainservice/src/main/java/com/example/mainservice/controller/AdminAppointmentController.java index 9b7cd49..2741fa4 100644 --- a/mainservice/src/main/java/com/example/mainservice/controller/AdminAppointmentController.java +++ b/mainservice/src/main/java/com/example/mainservice/controller/AdminAppointmentController.java @@ -9,7 +9,10 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.time.LocalDate; +import java.time.LocalTime; import java.util.List; +import java.util.Map; @RestController @RequestMapping("/api/admin/appointments") @@ -19,23 +22,21 @@ public class AdminAppointmentController { private final AppointmentRepository appointmentRepository; - // 🔹 GET ALL APPOINTMENTS + /* ================= GET ALL PAID APPOINTMENTS ================= */ @GetMapping public List getAllAppointments() { - // ONLY SUCCESS PAYMENTS - List list = + List appointments = appointmentRepository.findByPaymentStatus(PaymentStatus.SUCCESS); - System.out.println("PAID APPOINTMENTS = " + list.size()); - - return list.stream().map(a -> new AppointmentDTO( + return appointments.stream().map(a -> new AppointmentDTO( a.getId(), a.getAvailability() != null ? a.getAvailability().getId() : null, + a.getDoctor() != null ? a.getDoctor().getId() : null, a.getDoctor() != null ? a.getDoctor().getName() : "N/A", a.getDoctor() != null ? a.getDoctor().getSpecialty() : "N/A", a.getDoctor() != null ? a.getDoctor().getConsultationFee() : 0.0, - a.getAppointmentType().getTypeName(), + a.getAppointmentType() != null ? a.getAppointmentType().getTypeName() : "N/A", a.getPhysicalLocation() != null ? a.getPhysicalLocation() : a.getOnlineLink(), a.getBookingDate(), a.getBookingTime(), @@ -45,7 +46,7 @@ public List getAllAppointments() { )).toList(); } - // 🔹 CONFIRM APPOINTMENT + /* ================= CONFIRM APPOINTMENT ================= */ @PostMapping("/confirm/{id}") public ResponseEntity confirmAppointment( @PathVariable Long id, @@ -53,18 +54,59 @@ public ResponseEntity confirmAppointment( @RequestParam(required = false) String zoomLink ) { - Appointment a = appointmentRepository.findById(id) + Appointment appointment = appointmentRepository.findById(id) .orElseThrow(() -> new RuntimeException("Appointment not found")); - if ("Physical".equalsIgnoreCase(a.getAppointmentType().getTypeName())) { - a.setPhysicalLocation(physicalLocation); + if (appointment.getAppointmentType() != null && + "Physical".equalsIgnoreCase(appointment.getAppointmentType().getTypeName())) { + + appointment.setPhysicalLocation(physicalLocation); + } else { - a.setOnlineLink(zoomLink); + + appointment.setOnlineLink(zoomLink); } - a.setAppointmentStatus(AppointmentStatus.CONFIRMED); - appointmentRepository.save(a); + appointment.setAppointmentStatus(AppointmentStatus.CONFIRMED); + + appointmentRepository.save(appointment); + + return ResponseEntity.ok("Appointment confirmed successfully"); + } + + /* ================= UPDATE APPOINTMENT DATE & TIME ================= */ + @PutMapping("/update-date/{id}") + public ResponseEntity updateAppointmentDate( + @PathVariable Long id, + @RequestBody Map body + ) { + + Appointment appointment = appointmentRepository.findById(id) + .orElseThrow(() -> new RuntimeException("Appointment not found")); + + String bookingDate = body.get("bookingDate"); + String bookingTime = body.get("bookingTime"); + + try { + + if (bookingDate != null && !bookingDate.isBlank()) { + LocalDate newDate = LocalDate.parse(bookingDate); + appointment.setBookingDate(newDate); + } - return ResponseEntity.ok("Confirmed"); + if (bookingTime != null && !bookingTime.isBlank()) { + // Convert String to LocalTime to match entity + LocalTime newTime = LocalTime.parse(bookingTime); + appointment.setBookingTime(newTime); + } + + appointmentRepository.save(appointment); + + return ResponseEntity.ok("Appointment date/time updated successfully"); + + } catch (Exception e) { + return ResponseEntity.badRequest().body("Invalid date or time format"); + } } + } \ No newline at end of file diff --git a/mainservice/src/main/java/com/example/mainservice/controller/AppointmentController.java b/mainservice/src/main/java/com/example/mainservice/controller/AppointmentController.java index 8abc933..da7ac80 100644 --- a/mainservice/src/main/java/com/example/mainservice/controller/AppointmentController.java +++ b/mainservice/src/main/java/com/example/mainservice/controller/AppointmentController.java @@ -2,9 +2,11 @@ import com.example.mainservice.dto.AppointmentDTO; import com.example.mainservice.dto.AppointmentRequestDTO; +import com.example.mainservice.security.CustomUserDetails; import com.example.mainservice.service.AppointmentService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -18,24 +20,61 @@ public class AppointmentController { private final AppointmentService appointmentService; + /* ============================ BOOK APPOINTMENT ============================ */ @PostMapping("/book") - public ResponseEntity bookAppointment(@RequestBody AppointmentRequestDTO dto) { + public ResponseEntity bookAppointment( + @RequestBody AppointmentRequestDTO dto, + @AuthenticationPrincipal CustomUserDetails userDetails) { try { - return ResponseEntity.ok(appointmentService.bookAppointment(dto)); + Long patientId = userDetails.getId(); + AppointmentDTO appointment = appointmentService.bookAppointment(dto, patientId); + return ResponseEntity.ok(appointment); } catch (RuntimeException e) { return ResponseEntity.badRequest().body(Map.of("error", e.getMessage())); } catch (Exception e) { - return ResponseEntity.internalServerError().body(Map.of("error", "Internal server error")); + return ResponseEntity.internalServerError() + .body(Map.of("error", "Internal server error")); } } + /* ============================ GET MY SUCCESSFUL APPOINTMENTS ============================ */ @GetMapping("/user/success") + public ResponseEntity> getMySuccessfulAppointments( + @AuthenticationPrincipal CustomUserDetails userDetails) { + Long patientId = userDetails.getId(); + return ResponseEntity.ok( + appointmentService.getSuccessfulAppointmentsByPatient(patientId) + ); + } + + /* ============================ GET ALL SUCCESSFUL APPOINTMENTS (ADMIN) ============================ */ + @GetMapping("/user/success/all") public ResponseEntity> getSuccessfulAppointments() { - return ResponseEntity.ok(appointmentService.getSuccessfulAppointments()); + return ResponseEntity.ok( + appointmentService.getSuccessfulAppointments() + ); } + /* ============================ GET ALL APPOINTMENTS (ADMIN) ============================ */ @GetMapping("/admin/all") public ResponseEntity> getAllAppointments() { - return ResponseEntity.ok(appointmentService.getAllAppointments()); + return ResponseEntity.ok( + appointmentService.getAllAppointments() + ); + } + + /* ============================ RESCHEDULE APPOINTMENT ============================ */ + @PutMapping("/reschedule/{appointmentId}") + public ResponseEntity rescheduleAppointment( + @PathVariable Long appointmentId, + @RequestParam Long newAvailabilityId) { + try { + AppointmentDTO updated = appointmentService.rescheduleAppointment(appointmentId, newAvailabilityId); + return ResponseEntity.ok(updated); + } catch (RuntimeException e) { + return ResponseEntity.badRequest().body(Map.of("error", e.getMessage())); + } catch (Exception e) { + return ResponseEntity.internalServerError().body(Map.of("error", "Internal server error")); + } } -} +} \ No newline at end of file diff --git a/mainservice/src/main/java/com/example/mainservice/dto/AppointmentDTO.java b/mainservice/src/main/java/com/example/mainservice/dto/AppointmentDTO.java index 189a247..c487abb 100644 --- a/mainservice/src/main/java/com/example/mainservice/dto/AppointmentDTO.java +++ b/mainservice/src/main/java/com/example/mainservice/dto/AppointmentDTO.java @@ -11,6 +11,7 @@ public class AppointmentDTO { private Long appointmentId; private Long availabilityId; + private Long doctorId; // <-- add this private String doctorName; private String specialty; private Double consultationFee; @@ -21,4 +22,4 @@ public class AppointmentDTO { private String reason; private String paymentStatus; private String appointmentStatus; -} +} \ No newline at end of file diff --git a/mainservice/src/main/java/com/example/mainservice/entity/Appointment.java b/mainservice/src/main/java/com/example/mainservice/entity/Appointment.java index ce0d0fc..06f1607 100644 --- a/mainservice/src/main/java/com/example/mainservice/entity/Appointment.java +++ b/mainservice/src/main/java/com/example/mainservice/entity/Appointment.java @@ -35,27 +35,24 @@ public class Appointment { @JoinColumn(name = "appointment_type_id") private AppointmentType appointmentType; - /* ================= BASIC DETAILS ================= */ + @ManyToOne + @JoinColumn(name = "patient_id", nullable = false) + private Patient patient; // link to the logged-in user + /* ================= BASIC DETAILS ================= */ private LocalDate bookingDate; - private LocalTime bookingTime; - private String reason; - private String physicalLocation; - private String onlineLink; /* ================= PAYMENT ================= */ - @Enumerated(EnumType.STRING) private PaymentStatus paymentStatus; @Enumerated(EnumType.STRING) private AppointmentStatus appointmentStatus; - // PayHere order_id (STRING — very important) @Column(unique = true) private String orderId; } diff --git a/mainservice/src/main/java/com/example/mainservice/service/AppointmentService.java b/mainservice/src/main/java/com/example/mainservice/service/AppointmentService.java index 8c448a8..6f5e11c 100644 --- a/mainservice/src/main/java/com/example/mainservice/service/AppointmentService.java +++ b/mainservice/src/main/java/com/example/mainservice/service/AppointmentService.java @@ -8,6 +8,7 @@ import com.example.mainservice.repository.AppointmentRepository; import com.example.mainservice.repository.AppointmentTypeRepository; import com.example.mainservice.repository.SpecialDoctorRepository; +import com.example.mainservice.repository.PatientRepo; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -23,12 +24,13 @@ public class AppointmentService { private final DoctorAvailabilityService availabilityService; private final SpecialDoctorRepository doctorRepository; private final AppointmentTypeRepository appointmentTypeRepository; + private final PatientRepo patientRepo; - // ============================ - // BOOK APPOINTMENT - // ============================ + /* ============================ BOOK APPOINTMENT ============================ */ @Transactional - public AppointmentDTO bookAppointment(AppointmentRequestDTO request) { + public AppointmentDTO bookAppointment(AppointmentRequestDTO request, Long patientId) { + Patient patient = patientRepo.findById(patientId) + .orElseThrow(() -> new RuntimeException("Patient not found")); SpecialDoctor doctor = doctorRepository.findById(request.getDoctorId()) .orElseThrow(() -> new RuntimeException("Doctor not found")); @@ -44,8 +46,7 @@ public AppointmentDTO bookAppointment(AppointmentRequestDTO request) { .findFirst() .orElseThrow(() -> new RuntimeException("Selected time slot not available")); - DoctorAvailability bookedSlot = - availabilityService.markSlotBooked(availableSlot.getId()); + DoctorAvailability bookedSlot = availabilityService.markSlotBooked(availableSlot.getId()); Appointment appointment = Appointment.builder() .doctor(doctor) @@ -54,18 +55,24 @@ public AppointmentDTO bookAppointment(AppointmentRequestDTO request) { .bookingDate(bookedSlot.getAvailableDate()) .bookingTime(bookedSlot.getAvailableTime()) .reason(request.getReason()) - .paymentStatus(PaymentStatus.PENDING) // Payment not done yet + .patient(patient) + .paymentStatus(PaymentStatus.PENDING) .appointmentStatus(AppointmentStatus.PENDING) .build(); - return convertToDTO( - appointmentRepository.save(appointment) - ); + return convertToDTO(appointmentRepository.save(appointment)); + } + + /* ============================ GET PATIENT SUCCESSFUL APPOINTMENTS ============================ */ + public List getSuccessfulAppointmentsByPatient(Long patientId) { + return appointmentRepository + .findByPatientIdAndPaymentStatus(patientId, PaymentStatus.SUCCESS) + .stream() + .map(this::convertToDTO) + .collect(Collectors.toList()); } - // ============================ - // USER → ONLY SUCCESS PAYMENTS - // ============================ + /* ============================ GET ALL SUCCESSFUL APPOINTMENTS ============================ */ public List getSuccessfulAppointments() { return appointmentRepository .findByPaymentStatus(PaymentStatus.SUCCESS) @@ -74,9 +81,7 @@ public List getSuccessfulAppointments() { .collect(Collectors.toList()); } - // ============================ - // ADMIN → ALL APPOINTMENTS - // ============================ + /* ============================ GET ALL APPOINTMENTS ============================ */ public List getAllAppointments() { return appointmentRepository.findAll() .stream() @@ -84,11 +89,31 @@ public List getAllAppointments() { .collect(Collectors.toList()); } - // ============================ - // ENTITY → DTO - // ============================ - private AppointmentDTO convertToDTO(Appointment appointment) { + /* ============================ RESCHEDULE APPOINTMENT ============================ */ + @Transactional + public AppointmentDTO rescheduleAppointment(Long appointmentId, Long newAvailabilityId) { + Appointment appointment = appointmentRepository.findById(appointmentId) + .orElseThrow(() -> new RuntimeException("Appointment not found")); + + // Mark new slot as booked + DoctorAvailability newSlot = availabilityService.markSlotBooked(newAvailabilityId); + + // Free old slot + DoctorAvailability oldSlot = appointment.getAvailability(); + if (oldSlot != null) { + oldSlot.setIsBooked(false); + } + + // Update appointment with new slot + appointment.setAvailability(newSlot); + appointment.setBookingDate(newSlot.getAvailableDate()); + appointment.setBookingTime(newSlot.getAvailableTime()); + return convertToDTO(appointmentRepository.save(appointment)); + } + + /* ============================ ENTITY → DTO ============================ */ + private AppointmentDTO convertToDTO(Appointment appointment) { String locationOrLink = appointment.getAppointmentType().getTypeName().equalsIgnoreCase("Physical") ? appointment.getPhysicalLocation() @@ -96,9 +121,8 @@ private AppointmentDTO convertToDTO(Appointment appointment) { return new AppointmentDTO( appointment.getId(), - appointment.getAvailability() != null - ? appointment.getAvailability().getId() - : null, + appointment.getAvailability() != null ? appointment.getAvailability().getId() : null, + appointment.getDoctor().getId(), // include doctorId for frontend appointment.getDoctor().getName(), appointment.getDoctor().getSpecialty(), appointment.getDoctor().getConsultationFee(), @@ -111,4 +135,4 @@ private AppointmentDTO convertToDTO(Appointment appointment) { appointment.getAppointmentStatus().name() ); } -} +} \ No newline at end of file