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