Add species filtering

This commit is contained in:
2026-04-14 20:02:03 -06:00
parent 0c63963ddf
commit 933bd6b7fd
4 changed files with 25 additions and 13 deletions

View File

@@ -25,8 +25,9 @@ public class ServiceController {
@GetMapping @GetMapping
public ResponseEntity<Page<ServiceResponse>> getAllServices( public ResponseEntity<Page<ServiceResponse>> getAllServices(
@RequestParam(required = false) String q, @RequestParam(required = false) String q,
@RequestParam(required = false) String species,
Pageable pageable) { Pageable pageable) {
return ResponseEntity.ok(serviceService.getAllServices(q, pageable)); return ResponseEntity.ok(serviceService.getAllServices(q, species, pageable));
} }
@GetMapping("/{id}") @GetMapping("/{id}")

View File

@@ -11,8 +11,8 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public interface ServiceRepository extends JpaRepository<Service, Long> { public interface ServiceRepository extends JpaRepository<Service, Long> {
@Query("SELECT s FROM Service s WHERE " + @Query("SELECT DISTINCT s FROM Service s LEFT JOIN s.species sp WHERE " +
"LOWER(s.serviceName) LIKE LOWER(CONCAT('%', :q, '%')) OR " + "(:q IS NULL OR LOWER(s.serviceName) LIKE LOWER(CONCAT('%', :q, '%')) OR LOWER(COALESCE(s.serviceDesc, '')) LIKE LOWER(CONCAT('%', :q, '%'))) AND " +
"LOWER(s.serviceDesc) LIKE LOWER(CONCAT('%', :q, '%'))") "(:species IS NULL OR LOWER(sp) = LOWER(:species))")
Page<Service> searchServices(@Param("q") String query, Pageable pageable); Page<Service> searchServices(@Param("q") String q, @Param("species") String species, Pageable pageable);
} }

View File

@@ -8,6 +8,7 @@ import com.petshop.backend.entity.Appointment;
import com.petshop.backend.entity.Pet; import com.petshop.backend.entity.Pet;
import com.petshop.backend.entity.StoreLocation; import com.petshop.backend.entity.StoreLocation;
import com.petshop.backend.entity.User; import com.petshop.backend.entity.User;
import com.petshop.backend.exception.BusinessException;
import com.petshop.backend.exception.ResourceNotFoundException; import com.petshop.backend.exception.ResourceNotFoundException;
import com.petshop.backend.repository.AdoptionRepository; import com.petshop.backend.repository.AdoptionRepository;
import com.petshop.backend.repository.AppointmentRepository; import com.petshop.backend.repository.AppointmentRepository;
@@ -28,6 +29,7 @@ import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@@ -108,6 +110,7 @@ public class AppointmentService {
User employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId()); User employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId());
validateStoreAccess(store.getStoreId(), authenticatedUser); validateStoreAccess(store.getStoreId(), authenticatedUser);
validatePetServiceCompatibility(pet, service);
validateAvailability(employee, service, request.getAppointmentDate(), request.getAppointmentTime(), null); validateAvailability(employee, service, request.getAppointmentDate(), request.getAppointmentTime(), null);
Appointment appointment = new Appointment(); Appointment appointment = new Appointment();
@@ -147,6 +150,7 @@ public class AppointmentService {
User employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId()); User employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId());
validateStoreAccess(store.getStoreId(), authenticatedUser); validateStoreAccess(store.getStoreId(), authenticatedUser);
validatePetServiceCompatibility(pet, service);
validateAvailability(employee, service, request.getAppointmentDate(), request.getAppointmentTime(), id); validateAvailability(employee, service, request.getAppointmentDate(), request.getAppointmentTime(), id);
appointment.setCustomer(customer); appointment.setCustomer(customer);
@@ -254,6 +258,17 @@ public class AppointmentService {
return trimmed.isEmpty() ? null : trimmed; return trimmed.isEmpty() ? null : trimmed;
} }
private void validatePetServiceCompatibility(Pet pet, com.petshop.backend.entity.Service service) {
if (pet == null) return;
Set<String> allowed = service.getSpecies();
if (allowed == null || allowed.isEmpty()) return;
boolean compatible = allowed.stream().anyMatch(s -> s.equalsIgnoreCase(pet.getPetSpecies()));
if (!compatible) {
throw new BusinessException(
"Service \"" + service.getServiceName() + "\" is not available for " + pet.getPetSpecies());
}
}
private void validateAppointmentRequest(AppointmentRequest request) { private void validateAppointmentRequest(AppointmentRequest request) {
if ("Booked".equalsIgnoreCase(request.getAppointmentStatus())) { if ("Booked".equalsIgnoreCase(request.getAppointmentStatus())) {
LocalDateTime appointmentDateTime = LocalDateTime.of(request.getAppointmentDate(), request.getAppointmentTime()); LocalDateTime appointmentDateTime = LocalDateTime.of(request.getAppointmentDate(), request.getAppointmentTime());

View File

@@ -20,14 +20,10 @@ public class ServiceService {
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Page<ServiceResponse> getAllServices(String query, Pageable pageable) { public Page<ServiceResponse> getAllServices(String query, String species, Pageable pageable) {
Page<com.petshop.backend.entity.Service> services; String q = (query != null && !query.trim().isEmpty()) ? query.trim() : null;
if (query != null && !query.trim().isEmpty()) { String sp = (species != null && !species.trim().isEmpty()) ? species.trim() : null;
services = serviceRepository.searchServices(query, pageable); return serviceRepository.searchServices(q, sp, pageable).map(this::mapToResponse);
} else {
services = serviceRepository.findAll(pageable);
}
return services.map(this::mapToResponse);
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)