Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions mainservice/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
<artifactId>mainservice</artifactId>
<name>Archetype - mainservice</name>
<url>http://maven.apache.org</url>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

<dependencies>
<!-- WebSocket Support -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -19,23 +22,21 @@ public class AdminAppointmentController {

private final AppointmentRepository appointmentRepository;

// 🔹 GET ALL APPOINTMENTS
/* ================= GET ALL PAID APPOINTMENTS ================= */
@GetMapping
public List<AppointmentDTO> getAllAppointments() {

// ONLY SUCCESS PAYMENTS
List<Appointment> list =
List<Appointment> 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(),
Expand All @@ -45,26 +46,67 @@ public List<AppointmentDTO> getAllAppointments() {
)).toList();
}

// 🔹 CONFIRM APPOINTMENT
/* ================= CONFIRM APPOINTMENT ================= */
@PostMapping("/confirm/{id}")
public ResponseEntity<String> confirmAppointment(
@PathVariable Long id,
@RequestParam(required = false) String physicalLocation,
@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<String> updateAppointmentDate(
@PathVariable Long id,
@RequestBody Map<String, String> 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");
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<List<AppointmentDTO>> 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<List<AppointmentDTO>> getSuccessfulAppointments() {
return ResponseEntity.ok(appointmentService.getSuccessfulAppointments());
return ResponseEntity.ok(
appointmentService.getSuccessfulAppointments()
);
}

/* ============================ GET ALL APPOINTMENTS (ADMIN) ============================ */
@GetMapping("/admin/all")
public ResponseEntity<List<AppointmentDTO>> 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"));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,4 +22,4 @@ public class AppointmentDTO {
private String reason;
private String paymentStatus;
private String appointmentStatus;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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"));
Expand All @@ -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)
Expand All @@ -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<AppointmentDTO> 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<AppointmentDTO> getSuccessfulAppointments() {
return appointmentRepository
.findByPaymentStatus(PaymentStatus.SUCCESS)
Expand All @@ -74,31 +81,48 @@ public List<AppointmentDTO> getSuccessfulAppointments() {
.collect(Collectors.toList());
}

// ============================
// ADMIN → ALL APPOINTMENTS
// ============================
/* ============================ GET ALL APPOINTMENTS ============================ */
public List<AppointmentDTO> getAllAppointments() {
return appointmentRepository.findAll()
.stream()
.map(this::convertToDTO)
.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()
: appointment.getOnlineLink();

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(),
Expand All @@ -111,4 +135,4 @@ private AppointmentDTO convertToDTO(Appointment appointment) {
appointment.getAppointmentStatus().name()
);
}
}
}
Loading