Harden staff assignment
This commit is contained in:
@@ -8,6 +8,8 @@ public class AdoptionDTO {
|
||||
private String petName;
|
||||
private Long customerId;
|
||||
private String customerName;
|
||||
private Long employeeId;
|
||||
private String employeeName;
|
||||
private String adoptionDate;
|
||||
private String adoptionStatus;
|
||||
private BigDecimal adoptionFee;
|
||||
@@ -16,8 +18,13 @@ public class AdoptionDTO {
|
||||
|
||||
// Constructor for create/update requests
|
||||
public AdoptionDTO(Long petId, Long customerId, String adoptionDate, String adoptionStatus) {
|
||||
this(petId, customerId, null, adoptionDate, adoptionStatus);
|
||||
}
|
||||
|
||||
public AdoptionDTO(Long petId, Long customerId, Long employeeId, String adoptionDate, String adoptionStatus) {
|
||||
this.petId = petId;
|
||||
this.customerId = customerId;
|
||||
this.employeeId = employeeId;
|
||||
this.adoptionDate = adoptionDate;
|
||||
this.adoptionStatus = adoptionStatus;
|
||||
}
|
||||
@@ -42,6 +49,14 @@ public class AdoptionDTO {
|
||||
return customerName;
|
||||
}
|
||||
|
||||
public Long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public String getEmployeeName() {
|
||||
return employeeName;
|
||||
}
|
||||
|
||||
public String getAdoptionDate() {
|
||||
return adoptionDate;
|
||||
}
|
||||
@@ -65,4 +80,4 @@ public class AdoptionDTO {
|
||||
public String getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ public class AppointmentDTO {
|
||||
private String storeName;
|
||||
private Long serviceId;
|
||||
private String serviceName;
|
||||
private Long employeeId;
|
||||
private String employeeName;
|
||||
private String appointmentDate;
|
||||
private String appointmentTime;
|
||||
private String appointmentStatus;
|
||||
@@ -25,9 +27,16 @@ public class AppointmentDTO {
|
||||
public AppointmentDTO(Long customerId, Long storeId, Long serviceId,
|
||||
String appointmentDate, String appointmentTime,
|
||||
String appointmentStatus, List<Long> petIds) {
|
||||
this(customerId, storeId, serviceId, null, appointmentDate, appointmentTime, appointmentStatus, petIds);
|
||||
}
|
||||
|
||||
public AppointmentDTO(Long customerId, Long storeId, Long serviceId, Long employeeId,
|
||||
String appointmentDate, String appointmentTime,
|
||||
String appointmentStatus, List<Long> petIds) {
|
||||
this.customerId = customerId;
|
||||
this.storeId = storeId;
|
||||
this.serviceId = serviceId;
|
||||
this.employeeId = employeeId;
|
||||
this.appointmentDate = appointmentDate;
|
||||
this.appointmentTime = appointmentTime;
|
||||
this.appointmentStatus = appointmentStatus;
|
||||
@@ -63,6 +72,14 @@ public class AppointmentDTO {
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
public Long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public String getEmployeeName() {
|
||||
return employeeName;
|
||||
}
|
||||
|
||||
public String getAppointmentDate() {
|
||||
return appointmentDate;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.petshop.backend.controller;
|
||||
|
||||
import com.petshop.backend.dto.common.DropdownOption;
|
||||
import com.petshop.backend.entity.CustomerPet;
|
||||
import com.petshop.backend.entity.EmployeeStore;
|
||||
import com.petshop.backend.entity.User;
|
||||
import com.petshop.backend.repository.*;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
@@ -25,12 +27,15 @@ public class DropdownController {
|
||||
private final CategoryRepository categoryRepository;
|
||||
private final StoreRepository storeRepository;
|
||||
private final SupplierRepository supplierRepository;
|
||||
private final EmployeeStoreRepository employeeStoreRepository;
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public DropdownController(PetRepository petRepository, CustomerRepository customerRepository,
|
||||
CustomerPetRepository customerPetRepository,
|
||||
ServiceRepository serviceRepository, ProductRepository productRepository,
|
||||
CategoryRepository categoryRepository, StoreRepository storeRepository,
|
||||
SupplierRepository supplierRepository) {
|
||||
SupplierRepository supplierRepository, EmployeeStoreRepository employeeStoreRepository,
|
||||
UserRepository userRepository) {
|
||||
this.petRepository = petRepository;
|
||||
this.customerRepository = customerRepository;
|
||||
this.customerPetRepository = customerPetRepository;
|
||||
@@ -39,6 +44,8 @@ public class DropdownController {
|
||||
this.categoryRepository = categoryRepository;
|
||||
this.storeRepository = storeRepository;
|
||||
this.supplierRepository = supplierRepository;
|
||||
this.employeeStoreRepository = employeeStoreRepository;
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@GetMapping("/pets")
|
||||
@@ -129,6 +136,17 @@ public class DropdownController {
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/stores/{storeId}/employees")
|
||||
@PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')")
|
||||
public ResponseEntity<List<DropdownOption>> getStoreEmployees(@PathVariable Long storeId) {
|
||||
return ResponseEntity.ok(
|
||||
employeeStoreRepository.findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(storeId).stream()
|
||||
.filter(this::isAssignableEmployee)
|
||||
.map(this::toEmployeeOption)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/suppliers")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseEntity<List<DropdownOption>> getSuppliers() {
|
||||
@@ -144,4 +162,20 @@ public class DropdownController {
|
||||
String breed = pet.getBreed() == null || pet.getBreed().isBlank() ? "" : " · " + pet.getBreed();
|
||||
return new DropdownOption(pet.getCustomerPetId(), pet.getPetName() + " (" + species + breed + ")");
|
||||
}
|
||||
|
||||
private DropdownOption toEmployeeOption(EmployeeStore employeeStore) {
|
||||
var employee = employeeStore.getEmployee();
|
||||
return new DropdownOption(employee.getEmployeeId(), employee.getFirstName() + " " + employee.getLastName());
|
||||
}
|
||||
|
||||
private boolean isAssignableEmployee(EmployeeStore employeeStore) {
|
||||
Long userId = employeeStore.getEmployee().getUserId();
|
||||
if (userId == null) {
|
||||
return false;
|
||||
}
|
||||
return userRepository.findById(userId)
|
||||
.map(User::getRole)
|
||||
.filter(role -> role == User.Role.STAFF)
|
||||
.isPresent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ public class AdoptionRequest {
|
||||
@NotBlank(message = "Adoption status is required")
|
||||
private String adoptionStatus;
|
||||
|
||||
private Long employeeId;
|
||||
|
||||
public Long getPetId() {
|
||||
return petId;
|
||||
}
|
||||
@@ -50,6 +52,14 @@ public class AdoptionRequest {
|
||||
this.adoptionStatus = adoptionStatus;
|
||||
}
|
||||
|
||||
public Long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public void setEmployeeId(Long employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -58,12 +68,13 @@ public class AdoptionRequest {
|
||||
return Objects.equals(petId, that.petId) &&
|
||||
Objects.equals(customerId, that.customerId) &&
|
||||
Objects.equals(adoptionDate, that.adoptionDate) &&
|
||||
Objects.equals(adoptionStatus, that.adoptionStatus);
|
||||
Objects.equals(adoptionStatus, that.adoptionStatus) &&
|
||||
Objects.equals(employeeId, that.employeeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(petId, customerId, adoptionDate, adoptionStatus);
|
||||
return Objects.hash(petId, customerId, adoptionDate, adoptionStatus, employeeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,6 +84,7 @@ public class AdoptionRequest {
|
||||
", customerId=" + customerId +
|
||||
", adoptionDate=" + adoptionDate +
|
||||
", adoptionStatus='" + adoptionStatus + '\'' +
|
||||
", employeeId=" + employeeId +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ public class AdoptionResponse {
|
||||
private String petName;
|
||||
private Long customerId;
|
||||
private String customerName;
|
||||
private Long employeeId;
|
||||
private String employeeName;
|
||||
private LocalDate adoptionDate;
|
||||
private String adoptionStatus;
|
||||
private BigDecimal adoptionFee;
|
||||
@@ -20,12 +22,14 @@ public class AdoptionResponse {
|
||||
public AdoptionResponse() {
|
||||
}
|
||||
|
||||
public AdoptionResponse(Long adoptionId, Long petId, String petName, Long customerId, String customerName, LocalDate adoptionDate, String adoptionStatus, BigDecimal adoptionFee, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
public AdoptionResponse(Long adoptionId, Long petId, String petName, Long customerId, String customerName, Long employeeId, String employeeName, LocalDate adoptionDate, String adoptionStatus, BigDecimal adoptionFee, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
this.adoptionId = adoptionId;
|
||||
this.petId = petId;
|
||||
this.petName = petName;
|
||||
this.customerId = customerId;
|
||||
this.customerName = customerName;
|
||||
this.employeeId = employeeId;
|
||||
this.employeeName = employeeName;
|
||||
this.adoptionDate = adoptionDate;
|
||||
this.adoptionStatus = adoptionStatus;
|
||||
this.adoptionFee = adoptionFee;
|
||||
@@ -73,6 +77,22 @@ public class AdoptionResponse {
|
||||
this.customerName = customerName;
|
||||
}
|
||||
|
||||
public Long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public void setEmployeeId(Long employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
public String getEmployeeName() {
|
||||
return employeeName;
|
||||
}
|
||||
|
||||
public void setEmployeeName(String employeeName) {
|
||||
this.employeeName = employeeName;
|
||||
}
|
||||
|
||||
public LocalDate getAdoptionDate() {
|
||||
return adoptionDate;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ public class AppointmentRequest {
|
||||
|
||||
private List<Long> customerPetIds;
|
||||
|
||||
private Long employeeId;
|
||||
|
||||
public Long getCustomerId() {
|
||||
return customerId;
|
||||
}
|
||||
@@ -93,6 +95,14 @@ public class AppointmentRequest {
|
||||
this.customerPetIds = customerPetIds;
|
||||
}
|
||||
|
||||
public Long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public void setEmployeeId(Long employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -105,12 +115,13 @@ public class AppointmentRequest {
|
||||
Objects.equals(appointmentTime, that.appointmentTime) &&
|
||||
Objects.equals(appointmentStatus, that.appointmentStatus) &&
|
||||
Objects.equals(petIds, that.petIds) &&
|
||||
Objects.equals(customerPetIds, that.customerPetIds);
|
||||
Objects.equals(customerPetIds, that.customerPetIds) &&
|
||||
Objects.equals(employeeId, that.employeeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(customerId, storeId, serviceId, appointmentDate, appointmentTime, appointmentStatus, petIds, customerPetIds);
|
||||
return Objects.hash(customerId, storeId, serviceId, appointmentDate, appointmentTime, appointmentStatus, petIds, customerPetIds, employeeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,6 +135,7 @@ public class AppointmentRequest {
|
||||
", appointmentStatus='" + appointmentStatus + '\'' +
|
||||
", petIds=" + petIds +
|
||||
", customerPetIds=" + customerPetIds +
|
||||
", employeeId=" + employeeId +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ public class AppointmentResponse {
|
||||
private LocalDate appointmentDate;
|
||||
private LocalTime appointmentTime;
|
||||
private String appointmentStatus;
|
||||
private Long employeeId;
|
||||
private String employeeName;
|
||||
private List<String> petNames;
|
||||
private List<Long> petIds;
|
||||
private List<String> customerPetNames;
|
||||
@@ -124,6 +126,22 @@ public class AppointmentResponse {
|
||||
this.appointmentStatus = appointmentStatus;
|
||||
}
|
||||
|
||||
public Long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public void setEmployeeId(Long employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
public String getEmployeeName() {
|
||||
return employeeName;
|
||||
}
|
||||
|
||||
public void setEmployeeName(String employeeName) {
|
||||
this.employeeName = employeeName;
|
||||
}
|
||||
|
||||
public List<String> getPetNames() {
|
||||
return petNames;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ public class Adoption {
|
||||
@JoinColumn(name = "customerId", nullable = false)
|
||||
private Customer customer;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "employeeId", nullable = false)
|
||||
private Employee employee;
|
||||
|
||||
@Column(nullable = false)
|
||||
private LocalDate adoptionDate;
|
||||
|
||||
@@ -42,10 +46,11 @@ public class Adoption {
|
||||
public Adoption() {
|
||||
}
|
||||
|
||||
public Adoption(Long adoptionId, Pet pet, Customer customer, LocalDate adoptionDate, String adoptionStatus, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
public Adoption(Long adoptionId, Pet pet, Customer customer, Employee employee, LocalDate adoptionDate, String adoptionStatus, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
this.adoptionId = adoptionId;
|
||||
this.pet = pet;
|
||||
this.customer = customer;
|
||||
this.employee = employee;
|
||||
this.adoptionDate = adoptionDate;
|
||||
this.adoptionStatus = adoptionStatus;
|
||||
this.createdAt = createdAt;
|
||||
@@ -76,6 +81,14 @@ public class Adoption {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public Employee getEmployee() {
|
||||
return employee;
|
||||
}
|
||||
|
||||
public void setEmployee(Employee employee) {
|
||||
this.employee = employee;
|
||||
}
|
||||
|
||||
public LocalDate getAdoptionDate() {
|
||||
return adoptionDate;
|
||||
}
|
||||
@@ -127,6 +140,7 @@ public class Adoption {
|
||||
"adoptionId=" + adoptionId +
|
||||
", pet=" + pet +
|
||||
", customer=" + customer +
|
||||
", employee=" + employee +
|
||||
", adoptionDate=" + adoptionDate +
|
||||
", adoptionStatus='" + adoptionStatus + '\'' +
|
||||
", createdAt=" + createdAt +
|
||||
|
||||
@@ -31,6 +31,10 @@ public class Appointment {
|
||||
@JoinColumn(name = "serviceId", nullable = false)
|
||||
private Service service;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "employeeId", nullable = false)
|
||||
private Employee employee;
|
||||
|
||||
@Column(nullable = false)
|
||||
private LocalDate appointmentDate;
|
||||
|
||||
@@ -67,11 +71,12 @@ public class Appointment {
|
||||
public Appointment() {
|
||||
}
|
||||
|
||||
public Appointment(Long appointmentId, Customer customer, StoreLocation store, Service service, LocalDate appointmentDate, LocalTime appointmentTime, String appointmentStatus, Set<Pet> pets, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
public Appointment(Long appointmentId, Customer customer, StoreLocation store, Service service, Employee employee, LocalDate appointmentDate, LocalTime appointmentTime, String appointmentStatus, Set<Pet> pets, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
this.appointmentId = appointmentId;
|
||||
this.customer = customer;
|
||||
this.store = store;
|
||||
this.service = service;
|
||||
this.employee = employee;
|
||||
this.appointmentDate = appointmentDate;
|
||||
this.appointmentTime = appointmentTime;
|
||||
this.appointmentStatus = appointmentStatus;
|
||||
@@ -112,6 +117,14 @@ public class Appointment {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public Employee getEmployee() {
|
||||
return employee;
|
||||
}
|
||||
|
||||
public void setEmployee(Employee employee) {
|
||||
this.employee = employee;
|
||||
}
|
||||
|
||||
public LocalDate getAppointmentDate() {
|
||||
return appointmentDate;
|
||||
}
|
||||
@@ -189,6 +202,7 @@ public class Appointment {
|
||||
", customer=" + customer +
|
||||
", store=" + store +
|
||||
", service=" + service +
|
||||
", employee=" + employee +
|
||||
", appointmentDate=" + appointmentDate +
|
||||
", appointmentTime=" + appointmentTime +
|
||||
", appointmentStatus='" + appointmentStatus + '\'' +
|
||||
|
||||
@@ -15,6 +15,8 @@ import java.util.Optional;
|
||||
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
|
||||
Optional<Employee> findByUserId(Long userId);
|
||||
List<Employee> findAllByEmail(String email);
|
||||
Optional<Employee> findFirstByIsActiveTrueOrderByEmployeeIdAsc();
|
||||
List<Employee> findAllByIsActiveTrueOrderByEmployeeIdAsc();
|
||||
|
||||
@Query("SELECT e FROM Employee e WHERE " +
|
||||
"LOWER(e.firstName) LIKE LOWER(CONCAT('%', :q, '%')) OR " +
|
||||
|
||||
@@ -2,11 +2,17 @@ package com.petshop.backend.repository;
|
||||
|
||||
import com.petshop.backend.entity.EmployeeStore;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface EmployeeStoreRepository extends JpaRepository<EmployeeStore, EmployeeStore.EmployeeStoreId> {
|
||||
Optional<EmployeeStore> findByEmployeeEmployeeId(Long employeeId);
|
||||
|
||||
@Query("SELECT es FROM EmployeeStore es WHERE es.store.storeId = :storeId AND es.employee.isActive = true ORDER BY es.employee.employeeId ASC")
|
||||
List<EmployeeStore> findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(@Param("storeId") Long storeId);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,15 @@ import com.petshop.backend.dto.adoption.AdoptionResponse;
|
||||
import com.petshop.backend.dto.common.BulkDeleteRequest;
|
||||
import com.petshop.backend.entity.Adoption;
|
||||
import com.petshop.backend.entity.Customer;
|
||||
import com.petshop.backend.entity.Employee;
|
||||
import com.petshop.backend.entity.Pet;
|
||||
import com.petshop.backend.entity.User;
|
||||
import com.petshop.backend.exception.ResourceNotFoundException;
|
||||
import com.petshop.backend.repository.AdoptionRepository;
|
||||
import com.petshop.backend.repository.CustomerRepository;
|
||||
import com.petshop.backend.repository.EmployeeRepository;
|
||||
import com.petshop.backend.repository.PetRepository;
|
||||
import com.petshop.backend.repository.UserRepository;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -21,11 +25,15 @@ public class AdoptionService {
|
||||
private final AdoptionRepository adoptionRepository;
|
||||
private final PetRepository petRepository;
|
||||
private final CustomerRepository customerRepository;
|
||||
private final EmployeeRepository employeeRepository;
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public AdoptionService(AdoptionRepository adoptionRepository, PetRepository petRepository, CustomerRepository customerRepository) {
|
||||
public AdoptionService(AdoptionRepository adoptionRepository, PetRepository petRepository, CustomerRepository customerRepository, EmployeeRepository employeeRepository, UserRepository userRepository) {
|
||||
this.adoptionRepository = adoptionRepository;
|
||||
this.petRepository = petRepository;
|
||||
this.customerRepository = customerRepository;
|
||||
this.employeeRepository = employeeRepository;
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
public Page<AdoptionResponse> getAllAdoptions(String query, Pageable pageable, Long customerId) {
|
||||
@@ -66,10 +74,12 @@ public class AdoptionService {
|
||||
|
||||
Customer customer = customerRepository.findById(request.getCustomerId())
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Customer not found with id: " + request.getCustomerId()));
|
||||
Employee employee = resolveAdoptionEmployee(request.getEmployeeId());
|
||||
|
||||
Adoption adoption = new Adoption();
|
||||
adoption.setPet(pet);
|
||||
adoption.setCustomer(customer);
|
||||
adoption.setEmployee(employee);
|
||||
adoption.setAdoptionDate(request.getAdoptionDate());
|
||||
adoption.setAdoptionStatus(request.getAdoptionStatus());
|
||||
|
||||
@@ -87,9 +97,11 @@ public class AdoptionService {
|
||||
|
||||
Customer customer = customerRepository.findById(request.getCustomerId())
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Customer not found with id: " + request.getCustomerId()));
|
||||
Employee employee = resolveAdoptionEmployee(request.getEmployeeId());
|
||||
|
||||
adoption.setPet(pet);
|
||||
adoption.setCustomer(customer);
|
||||
adoption.setEmployee(employee);
|
||||
adoption.setAdoptionDate(request.getAdoptionDate());
|
||||
adoption.setAdoptionStatus(request.getAdoptionStatus());
|
||||
|
||||
@@ -117,6 +129,8 @@ public class AdoptionService {
|
||||
adoption.getPet().getPetName(),
|
||||
adoption.getCustomer().getCustomerId(),
|
||||
adoption.getCustomer().getFirstName() + " " + adoption.getCustomer().getLastName(),
|
||||
adoption.getEmployee().getEmployeeId(),
|
||||
adoption.getEmployee().getFirstName() + " " + adoption.getEmployee().getLastName(),
|
||||
adoption.getAdoptionDate(),
|
||||
adoption.getAdoptionStatus(),
|
||||
adoption.getPet().getPetPrice(),
|
||||
@@ -124,4 +138,31 @@ public class AdoptionService {
|
||||
adoption.getUpdatedAt()
|
||||
);
|
||||
}
|
||||
|
||||
private Employee resolveAdoptionEmployee(Long requestedEmployeeId) {
|
||||
if (requestedEmployeeId != null) {
|
||||
Employee employee = employeeRepository.findById(requestedEmployeeId)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Employee not found with id: " + requestedEmployeeId));
|
||||
if (!isAssignableEmployee(employee)) {
|
||||
throw new IllegalArgumentException("Selected employee is not assignable for adoption work");
|
||||
}
|
||||
return employee;
|
||||
}
|
||||
|
||||
return employeeRepository.findAllByIsActiveTrueOrderByEmployeeIdAsc().stream()
|
||||
.filter(this::isAssignableEmployee)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No assignable staff member is available for adoption assignment"));
|
||||
}
|
||||
|
||||
private boolean isAssignableEmployee(Employee employee) {
|
||||
Long userId = employee.getUserId();
|
||||
if (userId == null || !Boolean.TRUE.equals(employee.getIsActive())) {
|
||||
return false;
|
||||
}
|
||||
return userRepository.findById(userId)
|
||||
.map(User::getRole)
|
||||
.filter(role -> role == User.Role.STAFF)
|
||||
.isPresent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ public class AppointmentService {
|
||||
|
||||
Set<Pet> pets = hasPetIds ? fetchPets(request.getPetIds()) : new HashSet<>();
|
||||
Set<CustomerPet> customerPets = hasCustomerPetIds ? fetchCustomerPets(request.getCustomerPetIds(), customer.getCustomerId()) : new HashSet<>();
|
||||
Employee employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId());
|
||||
|
||||
Appointment appointment = new Appointment();
|
||||
appointment.setCustomer(customer);
|
||||
@@ -131,6 +132,7 @@ public class AppointmentService {
|
||||
appointment.setAppointmentStatus(request.getAppointmentStatus());
|
||||
appointment.setPets(pets);
|
||||
appointment.setCustomerPets(customerPets);
|
||||
appointment.setEmployee(employee);
|
||||
|
||||
appointment = appointmentRepository.save(appointment);
|
||||
return mapToResponse(appointment);
|
||||
@@ -165,6 +167,7 @@ public class AppointmentService {
|
||||
|
||||
Set<Pet> pets = hasPetIds ? fetchPets(request.getPetIds()) : new HashSet<>();
|
||||
Set<CustomerPet> customerPets = hasCustomerPetIds ? fetchCustomerPets(request.getCustomerPetIds(), customer.getCustomerId()) : new HashSet<>();
|
||||
Employee employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId());
|
||||
|
||||
appointment.setCustomer(customer);
|
||||
appointment.setStore(store);
|
||||
@@ -174,6 +177,7 @@ public class AppointmentService {
|
||||
appointment.setAppointmentStatus(request.getAppointmentStatus());
|
||||
appointment.setPets(pets);
|
||||
appointment.setCustomerPets(customerPets);
|
||||
appointment.setEmployee(employee);
|
||||
|
||||
appointment = appointmentRepository.save(appointment);
|
||||
return mapToResponse(appointment);
|
||||
@@ -289,6 +293,8 @@ public class AppointmentService {
|
||||
response.setAppointmentDate(appointment.getAppointmentDate());
|
||||
response.setAppointmentTime(appointment.getAppointmentTime());
|
||||
response.setAppointmentStatus(appointment.getAppointmentStatus());
|
||||
response.setEmployeeId(appointment.getEmployee().getEmployeeId());
|
||||
response.setEmployeeName(appointment.getEmployee().getFirstName() + " " + appointment.getEmployee().getLastName());
|
||||
response.setPetNames(petNames);
|
||||
response.setPetIds(petIds);
|
||||
response.setCustomerPetNames(customerPetNames);
|
||||
@@ -299,6 +305,39 @@ public class AppointmentService {
|
||||
return response;
|
||||
}
|
||||
|
||||
private Employee resolveAppointmentEmployee(Long requestedEmployeeId, Long storeId) {
|
||||
List<EmployeeStore> assignableEmployees = employeeStoreRepository.findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(storeId).stream()
|
||||
.filter(es -> isAssignableEmployee(es.getEmployee()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (requestedEmployeeId != null) {
|
||||
Employee employee = employeeRepository.findById(requestedEmployeeId)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Employee not found with id: " + requestedEmployeeId));
|
||||
boolean assignedToStore = assignableEmployees.stream()
|
||||
.anyMatch(es -> es.getEmployee().getEmployeeId().equals(requestedEmployeeId));
|
||||
if (!assignedToStore) {
|
||||
throw new IllegalArgumentException("Selected employee is not assignable for the selected store");
|
||||
}
|
||||
return employee;
|
||||
}
|
||||
|
||||
return assignableEmployees.stream()
|
||||
.map(EmployeeStore::getEmployee)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No assignable staff member is assigned to the selected store"));
|
||||
}
|
||||
|
||||
private boolean isAssignableEmployee(Employee employee) {
|
||||
Long userId = employee.getUserId();
|
||||
if (userId == null || !Boolean.TRUE.equals(employee.getIsActive())) {
|
||||
return false;
|
||||
}
|
||||
return userRepository.findById(userId)
|
||||
.map(User::getRole)
|
||||
.filter(role -> role == User.Role.STAFF)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
private void validateAvailability(StoreLocation store, com.petshop.backend.entity.Service service, LocalDate date, LocalTime time, Long appointmentIdToIgnore) {
|
||||
// Filter by same service only - different services can run at same time
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
ALTER TABLE appointment
|
||||
ADD COLUMN employeeId BIGINT NULL;
|
||||
|
||||
UPDATE appointment a
|
||||
SET a.employeeId = (
|
||||
SELECT es.employeeId
|
||||
FROM employeeStore es
|
||||
JOIN employee e ON e.employeeId = es.employeeId
|
||||
JOIN users u ON u.id = e.user_id
|
||||
WHERE es.storeId = a.storeId
|
||||
AND e.isActive = TRUE
|
||||
AND u.role = 'STAFF'
|
||||
ORDER BY es.employeeId ASC
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE a.employeeId IS NULL;
|
||||
|
||||
UPDATE appointment a
|
||||
SET a.employeeId = (
|
||||
SELECT e.employeeId
|
||||
FROM employee e
|
||||
JOIN users u ON u.id = e.user_id
|
||||
WHERE e.isActive = TRUE
|
||||
AND u.role = 'STAFF'
|
||||
ORDER BY e.employeeId ASC
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE a.employeeId IS NULL;
|
||||
|
||||
ALTER TABLE appointment
|
||||
ADD CONSTRAINT fk_appointment_employee
|
||||
FOREIGN KEY (employeeId) REFERENCES employee(employeeId);
|
||||
|
||||
CREATE INDEX idx_appointment_employeeId ON appointment(employeeId);
|
||||
|
||||
ALTER TABLE appointment
|
||||
MODIFY employeeId BIGINT NOT NULL;
|
||||
|
||||
ALTER TABLE adoption
|
||||
ADD COLUMN employeeId BIGINT NULL;
|
||||
|
||||
UPDATE adoption a
|
||||
SET a.employeeId = (
|
||||
SELECT e.employeeId
|
||||
FROM employee e
|
||||
JOIN users u ON u.id = e.user_id
|
||||
WHERE e.isActive = TRUE
|
||||
AND u.role = 'STAFF'
|
||||
ORDER BY e.employeeId ASC
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE a.employeeId IS NULL;
|
||||
|
||||
ALTER TABLE adoption
|
||||
ADD CONSTRAINT fk_adoption_employee
|
||||
FOREIGN KEY (employeeId) REFERENCES employee(employeeId);
|
||||
|
||||
CREATE INDEX idx_adoption_employeeId ON adoption(employeeId);
|
||||
|
||||
ALTER TABLE adoption
|
||||
MODIFY employeeId BIGINT NOT NULL;
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.petshop.backend.controller;
|
||||
|
||||
import com.petshop.backend.entity.Employee;
|
||||
import com.petshop.backend.entity.EmployeeStore;
|
||||
import com.petshop.backend.entity.StoreLocation;
|
||||
import com.petshop.backend.entity.User;
|
||||
import com.petshop.backend.repository.CategoryRepository;
|
||||
import com.petshop.backend.repository.CustomerPetRepository;
|
||||
import com.petshop.backend.repository.CustomerRepository;
|
||||
import com.petshop.backend.repository.EmployeeStoreRepository;
|
||||
import com.petshop.backend.repository.PetRepository;
|
||||
import com.petshop.backend.repository.ProductRepository;
|
||||
import com.petshop.backend.repository.ServiceRepository;
|
||||
import com.petshop.backend.repository.StoreRepository;
|
||||
import com.petshop.backend.repository.SupplierRepository;
|
||||
import com.petshop.backend.repository.UserRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class DropdownControllerTest {
|
||||
|
||||
@Test
|
||||
void getStoreEmployeesReturnsOnlyStaffLinkedEmployees() {
|
||||
PetRepository petRepository = mock(PetRepository.class);
|
||||
CustomerRepository customerRepository = mock(CustomerRepository.class);
|
||||
CustomerPetRepository customerPetRepository = mock(CustomerPetRepository.class);
|
||||
ServiceRepository serviceRepository = mock(ServiceRepository.class);
|
||||
ProductRepository productRepository = mock(ProductRepository.class);
|
||||
CategoryRepository categoryRepository = mock(CategoryRepository.class);
|
||||
StoreRepository storeRepository = mock(StoreRepository.class);
|
||||
SupplierRepository supplierRepository = mock(SupplierRepository.class);
|
||||
EmployeeStoreRepository employeeStoreRepository = mock(EmployeeStoreRepository.class);
|
||||
UserRepository userRepository = mock(UserRepository.class);
|
||||
|
||||
DropdownController controller = new DropdownController(
|
||||
petRepository,
|
||||
customerRepository,
|
||||
customerPetRepository,
|
||||
serviceRepository,
|
||||
productRepository,
|
||||
categoryRepository,
|
||||
storeRepository,
|
||||
supplierRepository,
|
||||
employeeStoreRepository,
|
||||
userRepository
|
||||
);
|
||||
|
||||
StoreLocation store = new StoreLocation();
|
||||
store.setStoreId(1L);
|
||||
|
||||
Employee staffEmployee = new Employee();
|
||||
staffEmployee.setEmployeeId(7L);
|
||||
staffEmployee.setUserId(7L);
|
||||
staffEmployee.setFirstName("Alex");
|
||||
staffEmployee.setLastName("Jones");
|
||||
staffEmployee.setIsActive(true);
|
||||
|
||||
Employee adminEmployee = new Employee();
|
||||
adminEmployee.setEmployeeId(8L);
|
||||
adminEmployee.setUserId(8L);
|
||||
adminEmployee.setFirstName("Admin");
|
||||
adminEmployee.setLastName("Helper");
|
||||
adminEmployee.setIsActive(true);
|
||||
|
||||
User staffUser = new User();
|
||||
staffUser.setId(7L);
|
||||
staffUser.setRole(User.Role.STAFF);
|
||||
|
||||
User adminUser = new User();
|
||||
adminUser.setId(8L);
|
||||
adminUser.setRole(User.Role.ADMIN);
|
||||
|
||||
when(employeeStoreRepository.findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(1L))
|
||||
.thenReturn(List.of(new EmployeeStore(staffEmployee, store), new EmployeeStore(adminEmployee, store)));
|
||||
when(userRepository.findById(7L)).thenReturn(Optional.of(staffUser));
|
||||
when(userRepository.findById(8L)).thenReturn(Optional.of(adminUser));
|
||||
|
||||
var response = controller.getStoreEmployees(1L);
|
||||
|
||||
assertEquals(1, response.getBody().size());
|
||||
assertEquals(Long.valueOf(7L), response.getBody().get(0).getId());
|
||||
assertEquals("Alex Jones", response.getBody().get(0).getLabel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.petshop.backend.service;
|
||||
|
||||
import com.petshop.backend.dto.adoption.AdoptionRequest;
|
||||
import com.petshop.backend.entity.Adoption;
|
||||
import com.petshop.backend.entity.Customer;
|
||||
import com.petshop.backend.entity.Employee;
|
||||
import com.petshop.backend.entity.Pet;
|
||||
import com.petshop.backend.entity.User;
|
||||
import com.petshop.backend.repository.AdoptionRepository;
|
||||
import com.petshop.backend.repository.CustomerRepository;
|
||||
import com.petshop.backend.repository.EmployeeRepository;
|
||||
import com.petshop.backend.repository.PetRepository;
|
||||
import com.petshop.backend.repository.UserRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class AdoptionServiceTest {
|
||||
|
||||
@Mock private AdoptionRepository adoptionRepository;
|
||||
@Mock private PetRepository petRepository;
|
||||
@Mock private CustomerRepository customerRepository;
|
||||
@Mock private EmployeeRepository employeeRepository;
|
||||
@Mock private UserRepository userRepository;
|
||||
|
||||
@InjectMocks
|
||||
private AdoptionService adoptionService;
|
||||
|
||||
private Pet pet;
|
||||
private Customer customer;
|
||||
private Employee staffEmployee;
|
||||
private Employee adminEmployee;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
pet = new Pet();
|
||||
pet.setPetId(1L);
|
||||
pet.setPetName("Buddy");
|
||||
|
||||
customer = new Customer();
|
||||
customer.setCustomerId(1L);
|
||||
customer.setFirstName("Pat");
|
||||
customer.setLastName("Owner");
|
||||
|
||||
staffEmployee = new Employee();
|
||||
staffEmployee.setEmployeeId(7L);
|
||||
staffEmployee.setUserId(7L);
|
||||
staffEmployee.setFirstName("Alex");
|
||||
staffEmployee.setLastName("Jones");
|
||||
staffEmployee.setIsActive(true);
|
||||
|
||||
adminEmployee = new Employee();
|
||||
adminEmployee.setEmployeeId(8L);
|
||||
adminEmployee.setUserId(8L);
|
||||
adminEmployee.setFirstName("Admin");
|
||||
adminEmployee.setLastName("Helper");
|
||||
adminEmployee.setIsActive(true);
|
||||
|
||||
User staffUser = new User();
|
||||
staffUser.setId(7L);
|
||||
staffUser.setRole(User.Role.STAFF);
|
||||
when(userRepository.findById(7L)).thenReturn(Optional.of(staffUser));
|
||||
|
||||
User adminUser = new User();
|
||||
adminUser.setId(8L);
|
||||
adminUser.setRole(User.Role.ADMIN);
|
||||
when(userRepository.findById(8L)).thenReturn(Optional.of(adminUser));
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAdoptionAutoAssignsFirstStaffEmployee() {
|
||||
when(petRepository.findById(1L)).thenReturn(Optional.of(pet));
|
||||
when(customerRepository.findById(1L)).thenReturn(Optional.of(customer));
|
||||
when(employeeRepository.findAllByIsActiveTrueOrderByEmployeeIdAsc()).thenReturn(List.of(adminEmployee, staffEmployee));
|
||||
when(adoptionRepository.save(any(Adoption.class))).thenAnswer(invocation -> {
|
||||
Adoption adoption = invocation.getArgument(0);
|
||||
adoption.setAdoptionId(10L);
|
||||
return adoption;
|
||||
});
|
||||
|
||||
AdoptionRequest request = new AdoptionRequest();
|
||||
request.setPetId(1L);
|
||||
request.setCustomerId(1L);
|
||||
request.setAdoptionDate(LocalDate.now());
|
||||
request.setAdoptionStatus("Pending");
|
||||
|
||||
var response = adoptionService.createAdoption(request);
|
||||
|
||||
assertEquals(7L, response.getEmployeeId());
|
||||
assertEquals("Alex Jones", response.getEmployeeName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAdoptionRejectsAdminEmployeeSelection() {
|
||||
when(petRepository.findById(1L)).thenReturn(Optional.of(pet));
|
||||
when(customerRepository.findById(1L)).thenReturn(Optional.of(customer));
|
||||
when(employeeRepository.findById(8L)).thenReturn(Optional.of(adminEmployee));
|
||||
|
||||
AdoptionRequest request = new AdoptionRequest();
|
||||
request.setPetId(1L);
|
||||
request.setCustomerId(1L);
|
||||
request.setEmployeeId(8L);
|
||||
request.setAdoptionDate(LocalDate.now());
|
||||
request.setAdoptionStatus("Pending");
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> adoptionService.createAdoption(request));
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.petshop.backend.service;
|
||||
import com.petshop.backend.entity.Appointment;
|
||||
import com.petshop.backend.entity.Customer;
|
||||
import com.petshop.backend.entity.CustomerPet;
|
||||
import com.petshop.backend.entity.Employee;
|
||||
import com.petshop.backend.entity.EmployeeStore;
|
||||
import com.petshop.backend.entity.Pet;
|
||||
import com.petshop.backend.entity.Service;
|
||||
import com.petshop.backend.entity.StoreLocation;
|
||||
@@ -22,7 +24,9 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@@ -41,6 +45,7 @@ import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class AppointmentServiceTest {
|
||||
|
||||
@Mock
|
||||
@@ -79,6 +84,7 @@ class AppointmentServiceTest {
|
||||
private Service nailTrim;
|
||||
private Pet pet;
|
||||
private CustomerPet customerPet;
|
||||
private Employee employee;
|
||||
private LocalDate date;
|
||||
|
||||
@BeforeEach
|
||||
@@ -111,6 +117,18 @@ class AppointmentServiceTest {
|
||||
customerPet.setPetName("Milo Jr");
|
||||
customerPet.setCustomer(customer);
|
||||
|
||||
employee = new Employee();
|
||||
employee.setEmployeeId(7L);
|
||||
employee.setUserId(7L);
|
||||
employee.setFirstName("Alex");
|
||||
employee.setLastName("Jones");
|
||||
employee.setIsActive(true);
|
||||
|
||||
User staffUser = new User();
|
||||
staffUser.setId(7L);
|
||||
staffUser.setRole(User.Role.STAFF);
|
||||
when(userRepository.findById(7L)).thenReturn(Optional.of(staffUser));
|
||||
|
||||
date = LocalDate.now().plusDays(1);
|
||||
|
||||
}
|
||||
@@ -171,6 +189,8 @@ class AppointmentServiceTest {
|
||||
when(storeRepository.findById(1L)).thenReturn(Optional.of(store));
|
||||
when(serviceRepository.findById(1L)).thenReturn(Optional.of(grooming));
|
||||
when(petRepository.findById(1L)).thenReturn(Optional.of(pet));
|
||||
when(employeeStoreRepository.findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(1L))
|
||||
.thenReturn(List.of(new EmployeeStore(employee, store)));
|
||||
when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of(existing));
|
||||
when(appointmentRepository.save(any(Appointment.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
@@ -210,6 +230,8 @@ class AppointmentServiceTest {
|
||||
when(customerRepository.findById(1L)).thenReturn(Optional.of(customer));
|
||||
when(storeRepository.findById(1L)).thenReturn(Optional.of(store));
|
||||
when(serviceRepository.findById(1L)).thenReturn(Optional.of(grooming));
|
||||
when(employeeStoreRepository.findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(1L))
|
||||
.thenReturn(List.of(new EmployeeStore(employee, store)));
|
||||
when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of());
|
||||
when(customerPetRepository.findById(22L)).thenReturn(Optional.of(otherCustomerPet));
|
||||
|
||||
@@ -238,6 +260,8 @@ class AppointmentServiceTest {
|
||||
when(customerRepository.findById(1L)).thenReturn(Optional.of(customer));
|
||||
when(storeRepository.findById(1L)).thenReturn(Optional.of(store));
|
||||
when(serviceRepository.findById(1L)).thenReturn(Optional.of(grooming));
|
||||
when(employeeStoreRepository.findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(1L))
|
||||
.thenReturn(List.of(new EmployeeStore(employee, store)));
|
||||
when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of());
|
||||
when(customerPetRepository.findById(11L)).thenReturn(Optional.of(customerPet));
|
||||
when(appointmentRepository.save(any(Appointment.class))).thenAnswer(invocation -> {
|
||||
@@ -259,6 +283,51 @@ class AppointmentServiceTest {
|
||||
|
||||
assertEquals(99L, response.getAppointmentId());
|
||||
assertEquals(1L, response.getCustomerId());
|
||||
assertEquals(7L, response.getEmployeeId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAppointmentRejectsAdminEmployeeSelection() {
|
||||
User adminUser = new User();
|
||||
adminUser.setId(99L);
|
||||
adminUser.setUsername("admin");
|
||||
adminUser.setRole(User.Role.ADMIN);
|
||||
adminUser.setTokenVersion(0);
|
||||
when(userRepository.findById(99L)).thenReturn(Optional.of(adminUser));
|
||||
setAuthentication(99L, User.Role.ADMIN);
|
||||
|
||||
Employee adminEmployee = new Employee();
|
||||
adminEmployee.setEmployeeId(8L);
|
||||
adminEmployee.setUserId(8L);
|
||||
adminEmployee.setFirstName("Admin");
|
||||
adminEmployee.setLastName("Helper");
|
||||
adminEmployee.setIsActive(true);
|
||||
|
||||
User adminLinkedUser = new User();
|
||||
adminLinkedUser.setId(8L);
|
||||
adminLinkedUser.setRole(User.Role.ADMIN);
|
||||
|
||||
when(userRepository.findById(8L)).thenReturn(Optional.of(adminLinkedUser));
|
||||
when(customerRepository.findById(1L)).thenReturn(Optional.of(customer));
|
||||
when(storeRepository.findById(1L)).thenReturn(Optional.of(store));
|
||||
when(serviceRepository.findById(1L)).thenReturn(Optional.of(grooming));
|
||||
when(employeeRepository.findById(8L)).thenReturn(Optional.of(adminEmployee));
|
||||
when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of());
|
||||
when(customerPetRepository.findById(11L)).thenReturn(Optional.of(customerPet));
|
||||
when(employeeStoreRepository.findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(1L))
|
||||
.thenReturn(List.of(new EmployeeStore(adminEmployee, store), new EmployeeStore(employee, store)));
|
||||
|
||||
var request = new com.petshop.backend.dto.appointment.AppointmentRequest();
|
||||
request.setCustomerId(1L);
|
||||
request.setStoreId(1L);
|
||||
request.setServiceId(1L);
|
||||
request.setEmployeeId(8L);
|
||||
request.setAppointmentDate(date);
|
||||
request.setAppointmentTime(LocalTime.of(10, 0));
|
||||
request.setAppointmentStatus("Booked");
|
||||
request.setCustomerPetIds(List.of(11L));
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> appointmentService.createAppointment(request));
|
||||
}
|
||||
|
||||
private Appointment appointment(Long id, LocalDate date, LocalTime time, Service service, StoreLocation storeLocation) {
|
||||
@@ -269,6 +338,7 @@ class AppointmentServiceTest {
|
||||
appointment.setAppointmentStatus("Booked");
|
||||
appointment.setService(service);
|
||||
appointment.setStore(storeLocation);
|
||||
appointment.setEmployee(employee);
|
||||
appointment.setCustomer(customer);
|
||||
appointment.setPets(Set.of());
|
||||
return appointment;
|
||||
|
||||
@@ -15,6 +15,8 @@ public class AppointmentDTO {
|
||||
|
||||
private SimpleIntegerProperty serviceId;
|
||||
private SimpleStringProperty serviceName;
|
||||
private SimpleIntegerProperty employeeId;
|
||||
private SimpleStringProperty employeeName;
|
||||
|
||||
private SimpleStringProperty appointmentDate;
|
||||
private SimpleStringProperty appointmentTime;
|
||||
@@ -25,6 +27,8 @@ public class AppointmentDTO {
|
||||
int customerId, String customerName,
|
||||
int petId, String petName,
|
||||
int serviceId, String serviceName,
|
||||
int employeeId,
|
||||
String employeeName,
|
||||
String appointmentDate,
|
||||
String appointmentTime,
|
||||
String appointmentStatus) {
|
||||
@@ -36,6 +40,8 @@ public class AppointmentDTO {
|
||||
this.petName = new SimpleStringProperty(petName);
|
||||
this.serviceId = new SimpleIntegerProperty(serviceId);
|
||||
this.serviceName = new SimpleStringProperty(serviceName);
|
||||
this.employeeId = new SimpleIntegerProperty(employeeId);
|
||||
this.employeeName = new SimpleStringProperty(employeeName);
|
||||
this.appointmentDate = new SimpleStringProperty(appointmentDate);
|
||||
this.appointmentTime = new SimpleStringProperty(appointmentTime);
|
||||
this.appointmentStatus = new SimpleStringProperty(appointmentStatus);
|
||||
@@ -52,8 +58,10 @@ public class AppointmentDTO {
|
||||
|
||||
public int getServiceId() { return serviceId.get(); }
|
||||
public String getServiceName() { return serviceName.get(); }
|
||||
public int getEmployeeId() { return employeeId.get(); }
|
||||
public String getEmployeeName() { return employeeName.get(); }
|
||||
|
||||
public String getAppointmentDate() { return appointmentDate.get(); }
|
||||
public String getAppointmentTime() { return appointmentTime.get(); }
|
||||
public String getAppointmentStatus() { return appointmentStatus.get(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.time.LocalDate;
|
||||
public class AdoptionRequest {
|
||||
private Long petId;
|
||||
private Long customerId;
|
||||
private Long employeeId;
|
||||
private LocalDate adoptionDate;
|
||||
private String adoptionStatus;
|
||||
|
||||
@@ -27,6 +28,14 @@ public class AdoptionRequest {
|
||||
this.customerId = customerId;
|
||||
}
|
||||
|
||||
public Long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public void setEmployeeId(Long employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
public LocalDate getAdoptionDate() {
|
||||
return adoptionDate;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ public class AdoptionResponse {
|
||||
private Long adoptionId;
|
||||
private Long petId;
|
||||
private Long customerId;
|
||||
private Long employeeId;
|
||||
private String petName;
|
||||
private String customerName;
|
||||
private String employeeName;
|
||||
private LocalDate adoptionDate;
|
||||
private java.math.BigDecimal adoptionFee;
|
||||
private String adoptionStatus;
|
||||
@@ -39,6 +41,14 @@ public class AdoptionResponse {
|
||||
this.customerId = customerId;
|
||||
}
|
||||
|
||||
public Long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public void setEmployeeId(Long employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
public String getPetName() {
|
||||
return petName;
|
||||
}
|
||||
@@ -55,6 +65,14 @@ public class AdoptionResponse {
|
||||
this.customerName = customerName;
|
||||
}
|
||||
|
||||
public String getEmployeeName() {
|
||||
return employeeName;
|
||||
}
|
||||
|
||||
public void setEmployeeName(String employeeName) {
|
||||
this.employeeName = employeeName;
|
||||
}
|
||||
|
||||
public LocalDate getAdoptionDate() {
|
||||
return adoptionDate;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ public class AppointmentRequest {
|
||||
private Long customerId;
|
||||
private Long storeId;
|
||||
private Long serviceId;
|
||||
private Long employeeId;
|
||||
private LocalDate appointmentDate;
|
||||
private LocalTime appointmentTime;
|
||||
private String appointmentStatus;
|
||||
@@ -57,6 +58,14 @@ public class AppointmentRequest {
|
||||
this.serviceId = serviceId;
|
||||
}
|
||||
|
||||
public Long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public void setEmployeeId(Long employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
public LocalDate getAppointmentDate() {
|
||||
return appointmentDate;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ public class AppointmentResponse {
|
||||
private java.util.List<String> customerPetNames;
|
||||
private java.util.List<Long> customerPetIds;
|
||||
private String serviceName;
|
||||
private Long employeeId;
|
||||
private String employeeName;
|
||||
private LocalDate appointmentDate;
|
||||
private LocalTime appointmentTime;
|
||||
private String appointmentStatus;
|
||||
@@ -110,6 +112,22 @@ public class AppointmentResponse {
|
||||
this.serviceName = serviceName;
|
||||
}
|
||||
|
||||
public Long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public void setEmployeeId(Long employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
public String getEmployeeName() {
|
||||
return employeeName;
|
||||
}
|
||||
|
||||
public void setEmployeeName(String employeeName) {
|
||||
this.employeeName = employeeName;
|
||||
}
|
||||
|
||||
public LocalDate getAppointmentDate() {
|
||||
return appointmentDate;
|
||||
}
|
||||
|
||||
@@ -97,4 +97,12 @@ public class DropdownApi {
|
||||
}
|
||||
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
|
||||
}
|
||||
|
||||
public List<DropdownOption> getStoreEmployees(Long storeId) throws Exception {
|
||||
String response = apiClient.getRawResponse("/api/v1/dropdowns/stores/" + storeId + "/employees");
|
||||
if (response == null || response.isEmpty()) {
|
||||
throw new IllegalStateException("Empty response from store employees endpoint");
|
||||
}
|
||||
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@ public class AdoptionController {
|
||||
@FXML
|
||||
private TableColumn<Adoption, String> colCustomerName;
|
||||
|
||||
@FXML
|
||||
private TableColumn<Adoption, String> colEmployeeName;
|
||||
|
||||
@FXML
|
||||
private TableColumn<Adoption, String> colAdoptionDate;
|
||||
|
||||
@@ -71,6 +74,7 @@ public class AdoptionController {
|
||||
colAdoptionId.setCellValueFactory(new PropertyValueFactory<>("adoptionId"));
|
||||
colPetId.setCellValueFactory(new PropertyValueFactory<>("petName"));
|
||||
colCustomerName.setCellValueFactory(new PropertyValueFactory<>("customerName"));
|
||||
colEmployeeName.setCellValueFactory(new PropertyValueFactory<>("employeeName"));
|
||||
colAdoptionDate.setCellValueFactory(new PropertyValueFactory<>("adoptionDate"));
|
||||
colAdoptionFee.setCellValueFactory(new PropertyValueFactory<>("adoptionFee"));
|
||||
colAdoptionStatus.setCellValueFactory(new PropertyValueFactory<>("adoptionStatus"));
|
||||
@@ -252,8 +256,10 @@ public class AdoptionController {
|
||||
response.getAdoptionId().intValue(),
|
||||
response.getPetId() != null ? response.getPetId().intValue() : 0,
|
||||
response.getCustomerId() != null ? response.getCustomerId().intValue() : 0,
|
||||
response.getEmployeeId() != null ? response.getEmployeeId().intValue() : 0,
|
||||
response.getPetName(),
|
||||
response.getCustomerName(),
|
||||
response.getEmployeeName(),
|
||||
response.getAdoptionDate() != null ? response.getAdoptionDate().toString() : "",
|
||||
response.getAdoptionFee() != null ? response.getAdoptionFee().doubleValue() : 0.0,
|
||||
response.getAdoptionStatus()
|
||||
|
||||
@@ -33,6 +33,7 @@ public class AppointmentController {
|
||||
@FXML private TableColumn<AppointmentDTO,String> colAppointmentDate;
|
||||
@FXML private TableColumn<AppointmentDTO,String> colAppointmentTime;
|
||||
@FXML private TableColumn<AppointmentDTO,String> colCustomerName;
|
||||
@FXML private TableColumn<AppointmentDTO,String> colEmployeeName;
|
||||
@FXML private TableColumn<AppointmentDTO,String> colAppointmentStatus;
|
||||
|
||||
@FXML private Button btnAdd;
|
||||
@@ -55,6 +56,7 @@ public class AppointmentController {
|
||||
colAppointmentDate.setCellValueFactory(new PropertyValueFactory<>("appointmentDate"));
|
||||
colAppointmentTime.setCellValueFactory(new PropertyValueFactory<>("appointmentTime"));
|
||||
colCustomerName.setCellValueFactory(new PropertyValueFactory<>("customerName"));
|
||||
colEmployeeName.setCellValueFactory(new PropertyValueFactory<>("employeeName"));
|
||||
colAppointmentStatus.setCellValueFactory(new PropertyValueFactory<>("appointmentStatus"));
|
||||
|
||||
filtered = new FilteredList<>(appointments, a -> true);
|
||||
@@ -247,6 +249,8 @@ public class AppointmentController {
|
||||
petName,
|
||||
response.getServiceId() != null ? response.getServiceId().intValue() : 0,
|
||||
response.getServiceName(),
|
||||
response.getEmployeeId() != null ? response.getEmployeeId().intValue() : 0,
|
||||
response.getEmployeeName(),
|
||||
response.getAppointmentDate().toString(),
|
||||
response.getAppointmentTime().toString(),
|
||||
response.getAppointmentStatus()
|
||||
|
||||
@@ -11,6 +11,7 @@ import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest;
|
||||
@@ -38,6 +39,9 @@ public class AdoptionDialogController {
|
||||
@FXML
|
||||
private ComboBox<DropdownOption> cbCustomer;
|
||||
|
||||
@FXML
|
||||
private ComboBox<DropdownOption> cbEmployee;
|
||||
|
||||
@FXML
|
||||
private ComboBox<DropdownOption> cbPet;
|
||||
|
||||
@@ -62,6 +66,7 @@ public class AdoptionDialogController {
|
||||
void initialize() {
|
||||
|
||||
cbAdoptionStatus.setItems(statusList);
|
||||
cbEmployee.setPromptText("Select an employee");
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
@@ -83,6 +88,38 @@ public class AdoptionDialogController {
|
||||
}
|
||||
}).start();
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Long storeId = org.example.petshopdesktop.auth.UserSession.getInstance().getStoreId();
|
||||
List<DropdownOption> employees = storeId != null && storeId > 0 ? DropdownApi.getInstance().getStoreEmployees(storeId) : List.of();
|
||||
Platform.runLater(() -> cbEmployee.setItems(FXCollections.observableArrayList(employees)));
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionDialogController.initialize",
|
||||
e,
|
||||
"Loading employees for combo box");
|
||||
cbEmployee.setDisable(true);
|
||||
cbEmployee.setPromptText("Unable to load employees");
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
|
||||
cbEmployee.setCellFactory(param -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption option, boolean empty) {
|
||||
super.updateItem(option, empty);
|
||||
setText(empty || option == null ? null : option.getLabel());
|
||||
}
|
||||
});
|
||||
cbEmployee.setButtonCell(new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption option, boolean empty) {
|
||||
super.updateItem(option, empty);
|
||||
setText(empty || option == null ? null : option.getLabel());
|
||||
}
|
||||
});
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
|
||||
@@ -129,6 +166,10 @@ public class AdoptionDialogController {
|
||||
errorMsg += "Customer is required.\n";
|
||||
}
|
||||
|
||||
if (cbEmployee.getSelectionModel().getSelectedItem() == null) {
|
||||
errorMsg += "Employee is required.\n";
|
||||
}
|
||||
|
||||
if (dpAdoptionDate.getValue() == null) {
|
||||
errorMsg += "Adoption Date is required.\n";
|
||||
}
|
||||
@@ -142,6 +183,7 @@ public class AdoptionDialogController {
|
||||
AdoptionRequest request = new AdoptionRequest();
|
||||
request.setPetId(cbPet.getSelectionModel().getSelectedItem().getId());
|
||||
request.setCustomerId(cbCustomer.getSelectionModel().getSelectedItem().getId());
|
||||
request.setEmployeeId(cbEmployee.getSelectionModel().getSelectedItem().getId());
|
||||
request.setAdoptionDate(dpAdoptionDate.getValue());
|
||||
request.setAdoptionStatus(cbAdoptionStatus.getValue());
|
||||
|
||||
@@ -204,6 +246,15 @@ public class AdoptionDialogController {
|
||||
}
|
||||
}
|
||||
|
||||
if (adoption.getEmployeeId() > 0) {
|
||||
for (DropdownOption employee : cbEmployee.getItems()) {
|
||||
if (employee.getId() != null && employee.getId().equals(adoption.getEmployeeId())) {
|
||||
cbEmployee.getSelectionModel().select(employee);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) {
|
||||
try {
|
||||
dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate()));
|
||||
|
||||
@@ -35,6 +35,7 @@ public class AppointmentDialogController {
|
||||
@FXML private ComboBox<DropdownOption> cbService;
|
||||
@FXML private ComboBox<DropdownOption> cbCustomer;
|
||||
@FXML private ComboBox<DropdownOption> cbPet;
|
||||
@FXML private ComboBox<DropdownOption> cbEmployee;
|
||||
|
||||
@FXML private ComboBox<Integer> cbHour;
|
||||
@FXML private ComboBox<Integer> cbMinute;
|
||||
@@ -94,14 +95,32 @@ public class AppointmentDialogController {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentDialogController.initialize",
|
||||
e,
|
||||
"Loading combo box data for services, customers, and pets");
|
||||
"Loading services/customers for appointment dialog");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Long storeId = UserSession.getInstance().getStoreId();
|
||||
List<DropdownOption> employees = storeId != null && storeId > 0 ? DropdownApi.getInstance().getStoreEmployees(storeId) : List.of();
|
||||
Platform.runLater(() -> cbEmployee.setItems(FXCollections.observableArrayList(employees)));
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentDialogController.initialize",
|
||||
e,
|
||||
"Loading employees for appointment dialog");
|
||||
cbEmployee.setDisable(true);
|
||||
cbEmployee.setPromptText("Unable to load employees");
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
|
||||
cbAppointmentStatus.setItems(statusList);
|
||||
cbPet.setDisable(true);
|
||||
cbEmployee.setPromptText("Select an employee");
|
||||
cbPet.setPromptText("Select a customer first");
|
||||
cbCustomer.setPromptText("Select a customer");
|
||||
cbService.setPromptText("Select a service");
|
||||
@@ -161,6 +180,21 @@ public class AppointmentDialogController {
|
||||
}
|
||||
});
|
||||
|
||||
cbEmployee.setCellFactory(param -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption option, boolean empty) {
|
||||
super.updateItem(option, empty);
|
||||
setText(empty || option == null ? null : option.getLabel());
|
||||
}
|
||||
});
|
||||
cbEmployee.setButtonCell(new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption option, boolean empty) {
|
||||
super.updateItem(option, empty);
|
||||
setText(empty || option == null ? null : option.getLabel());
|
||||
}
|
||||
});
|
||||
|
||||
cbCustomer.valueProperty().addListener((obs, oldValue, newValue) -> {
|
||||
Long customerId = newValue != null ? newValue.getId() : null;
|
||||
cbPet.setValue(null);
|
||||
@@ -222,6 +256,14 @@ public class AppointmentDialogController {
|
||||
cbCustomer.setValue(c);
|
||||
}
|
||||
});
|
||||
|
||||
if (appt.getEmployeeId() > 0) {
|
||||
cbEmployee.getItems().forEach(employee -> {
|
||||
if (employee.getId() != null && employee.getId().longValue() == appt.getEmployeeId()) {
|
||||
cbEmployee.setValue(employee);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -233,6 +275,7 @@ public class AppointmentDialogController {
|
||||
if (cbService.getValue() == null ||
|
||||
cbCustomer.getValue() == null ||
|
||||
cbPet.getValue() == null ||
|
||||
cbEmployee.getValue() == null ||
|
||||
dpAppointmentDate.getValue() == null ||
|
||||
cbHour.getValue() == null ||
|
||||
cbMinute.getValue() == null ||
|
||||
@@ -254,6 +297,7 @@ public class AppointmentDialogController {
|
||||
request.setCustomerId(cbCustomer.getValue().getId());
|
||||
request.setStoreId(storeId);
|
||||
request.setServiceId(cbService.getValue().getId());
|
||||
request.setEmployeeId(cbEmployee.getValue().getId());
|
||||
request.setAppointmentDate(dpAppointmentDate.getValue());
|
||||
request.setAppointmentTime(appointmentTime);
|
||||
request.setAppointmentStatus(cbAppointmentStatus.getValue());
|
||||
|
||||
@@ -8,18 +8,22 @@ public class Adoption {
|
||||
private SimpleIntegerProperty adoptionId;
|
||||
private SimpleIntegerProperty petId;
|
||||
private SimpleIntegerProperty customerId;
|
||||
private SimpleIntegerProperty employeeId;
|
||||
private SimpleStringProperty petName;
|
||||
private SimpleStringProperty customerName;
|
||||
private SimpleStringProperty employeeName;
|
||||
private SimpleStringProperty adoptionDate;
|
||||
private SimpleDoubleProperty adoptionFee;
|
||||
private SimpleStringProperty adoptionStatus;
|
||||
|
||||
public Adoption(int adoptionId, int petId, int customerId, String petName, String customerName, String adoptionDate, double adoptionFee, String adoptionStatus) {
|
||||
public Adoption(int adoptionId, int petId, int customerId, int employeeId, String petName, String customerName, String employeeName, String adoptionDate, double adoptionFee, String adoptionStatus) {
|
||||
this.adoptionId = new SimpleIntegerProperty(adoptionId);
|
||||
this.petId = new SimpleIntegerProperty(petId);
|
||||
this.customerId = new SimpleIntegerProperty(customerId);
|
||||
this.employeeId = new SimpleIntegerProperty(employeeId);
|
||||
this.petName = new SimpleStringProperty(petName);
|
||||
this.customerName = new SimpleStringProperty(customerName);
|
||||
this.employeeName = new SimpleStringProperty(employeeName);
|
||||
this.adoptionDate = new SimpleStringProperty(adoptionDate);
|
||||
this.adoptionFee = new SimpleDoubleProperty(adoptionFee);
|
||||
this.adoptionStatus = new SimpleStringProperty(adoptionStatus);
|
||||
@@ -43,6 +47,12 @@ public class Adoption {
|
||||
|
||||
public SimpleIntegerProperty customerIdProperty() { return customerId; }
|
||||
|
||||
public int getEmployeeId() { return employeeId.get(); }
|
||||
|
||||
public void setEmployeeId(int employeeId) { this.employeeId.set(employeeId); }
|
||||
|
||||
public SimpleIntegerProperty employeeIdProperty() { return employeeId; }
|
||||
|
||||
public String getPetName() { return petName.get(); }
|
||||
|
||||
public void setPetName(String petName) { this.petName.set(petName); }
|
||||
@@ -55,6 +65,12 @@ public class Adoption {
|
||||
|
||||
public SimpleStringProperty customerNameProperty() { return customerName; }
|
||||
|
||||
public String getEmployeeName() { return employeeName.get(); }
|
||||
|
||||
public void setEmployeeName(String employeeName) { this.employeeName.set(employeeName); }
|
||||
|
||||
public SimpleStringProperty employeeNameProperty() { return employeeName; }
|
||||
|
||||
public String getAdoptionDate() { return adoptionDate.get(); }
|
||||
|
||||
public void setAdoptionDate(String adoptionDate) { this.adoptionDate.set(adoptionDate); }
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0">
|
||||
@@ -131,6 +132,20 @@
|
||||
</ComboBox>
|
||||
</children>
|
||||
</VBox>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<Label text="Employee:" textFill="#2c3e50">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<ComboBox fx:id="cbEmployee" prefHeight="29.0" prefWidth="336.0" promptText="Select Employee" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10; -fx-background-color: white;">
|
||||
<padding>
|
||||
<Insets bottom="3.0" left="10.0" right="10.0" top="3.0" />
|
||||
</padding>
|
||||
</ComboBox>
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
<VBox.margin>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" />
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0">
|
||||
@@ -190,9 +191,9 @@
|
||||
</children>
|
||||
|
||||
</VBox>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<Label text="Pet:" textFill="#2c3e50">
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<Label text="Pet:" textFill="#2c3e50">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
@@ -201,9 +202,23 @@
|
||||
<padding>
|
||||
<Insets bottom="3.0" left="10.0" right="10.0" top="3.0" />
|
||||
</padding>
|
||||
</ComboBox>
|
||||
</children>
|
||||
</VBox>
|
||||
</ComboBox>
|
||||
</children>
|
||||
</VBox>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1" GridPane.rowIndex="3">
|
||||
<children>
|
||||
<Label text="Employee:" textFill="#2c3e50">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<ComboBox fx:id="cbEmployee" prefHeight="29.0" prefWidth="336.0" promptText="Select Employee" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10; -fx-background-color: white;">
|
||||
<padding>
|
||||
<Insets bottom="3.0" left="10.0" right="10.0" top="3.0" />
|
||||
</padding>
|
||||
</ComboBox>
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
<VBox.margin>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" />
|
||||
|
||||
@@ -68,11 +68,12 @@
|
||||
<TableView fx:id="tvAdoptions" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="colAdoptionId" prefWidth="60.0" text="ID" />
|
||||
<TableColumn fx:id="colPetId" prefWidth="66.2857666015625" text="Pet ID" />
|
||||
<TableColumn fx:id="colCustomerName" prefWidth="200.57147216796875" text="Customer Name" />
|
||||
<TableColumn fx:id="colAdoptionDate" prefWidth="190.85711669921875" text="Adoption Date" />
|
||||
<TableColumn fx:id="colAdoptionFee" prefWidth="91.4285888671875" text="Fee" />
|
||||
<TableColumn fx:id="colAdoptionStatus" prefWidth="142.28570556640625" text="Status" />
|
||||
<TableColumn fx:id="colPetId" prefWidth="66.2857666015625" text="Pet ID" />
|
||||
<TableColumn fx:id="colCustomerName" prefWidth="200.57147216796875" text="Customer Name" />
|
||||
<TableColumn fx:id="colEmployeeName" prefWidth="160.0" text="Employee" />
|
||||
<TableColumn fx:id="colAdoptionDate" prefWidth="190.85711669921875" text="Adoption Date" />
|
||||
<TableColumn fx:id="colAdoptionFee" prefWidth="91.4285888671875" text="Fee" />
|
||||
<TableColumn fx:id="colAdoptionStatus" prefWidth="120.0" text="Status" />
|
||||
</columns>
|
||||
</TableView>
|
||||
</children>
|
||||
|
||||
@@ -68,12 +68,13 @@
|
||||
<TableView fx:id="tvAppointments" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="colAppointmentId" prefWidth="53.14288330078125" text="ID" />
|
||||
<TableColumn fx:id="colPetName" prefWidth="108.00003051757812" text="Pet Name" />
|
||||
<TableColumn fx:id="colServiceName" prefWidth="132.0" text="Service" />
|
||||
<TableColumn fx:id="colAppointmentDate" prefWidth="101.14288330078125" text="Date" />
|
||||
<TableColumn fx:id="colAppointmentTime" prefWidth="89.7142333984375" text="Time" />
|
||||
<TableColumn fx:id="colCustomerName" prefWidth="168.57147216796875" text="Customer" />
|
||||
<TableColumn fx:id="colAppointmentStatus" prefWidth="98.28570556640625" text="Status" />
|
||||
<TableColumn fx:id="colPetName" prefWidth="108.00003051757812" text="Pet Name" />
|
||||
<TableColumn fx:id="colServiceName" prefWidth="132.0" text="Service" />
|
||||
<TableColumn fx:id="colEmployeeName" prefWidth="132.0" text="Employee" />
|
||||
<TableColumn fx:id="colAppointmentDate" prefWidth="101.14288330078125" text="Date" />
|
||||
<TableColumn fx:id="colAppointmentTime" prefWidth="89.7142333984375" text="Time" />
|
||||
<TableColumn fx:id="colCustomerName" prefWidth="140.0" text="Customer" />
|
||||
<TableColumn fx:id="colAppointmentStatus" prefWidth="98.28570556640625" text="Status" />
|
||||
</columns>
|
||||
</TableView>
|
||||
</children>
|
||||
|
||||
@@ -203,6 +203,7 @@ function AppointmentsPage() {
|
||||
const didPreselectRef = useRef(false);
|
||||
|
||||
const [stores, setStores] = useState([]);
|
||||
const [employees, setEmployees] = useState([]);
|
||||
const [services, setServices] = useState([]);
|
||||
const [allPets, setAllPets] = useState([]);
|
||||
const [customerPets, setCustomerPets] = useState([]);
|
||||
@@ -210,6 +211,7 @@ function AppointmentsPage() {
|
||||
|
||||
const [storeId, setStoreId] = useState("");
|
||||
const [serviceId, setServiceId] = useState("");
|
||||
const [employeeId, setEmployeeId] = useState("");
|
||||
const [appointmentDate, setAppointmentDate] = useState("");
|
||||
const [appointmentTime, setAppointmentTime] = useState("");
|
||||
const [selectedPetIds, setSelectedPetIds] = useState([]);
|
||||
@@ -302,6 +304,33 @@ function AppointmentsPage() {
|
||||
loadAppointments();
|
||||
}, [loadAppointments]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!token || !storeId) {
|
||||
setEmployees([]);
|
||||
setEmployeeId("");
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`${API_BASE}/api/v1/dropdowns/stores/${storeId}/employees`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
})
|
||||
.then((r) => r.json())
|
||||
.then((data) => setEmployees(Array.isArray(data) ? data : []))
|
||||
.catch(() => setEmployees([]));
|
||||
}, [token, storeId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!employees.length) {
|
||||
setEmployeeId("");
|
||||
return;
|
||||
}
|
||||
|
||||
const currentExists = employees.some((employee) => String(employee.id) === String(employeeId));
|
||||
if (!currentExists) {
|
||||
setEmployeeId(String(employees[0].id));
|
||||
}
|
||||
}, [employees, employeeId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!storeId || !serviceId || !appointmentDate) {
|
||||
setAvailableSlots([]);
|
||||
@@ -401,6 +430,7 @@ function AppointmentsPage() {
|
||||
customerId: user.customerId,
|
||||
storeId: Number(storeId),
|
||||
serviceId: Number(serviceId),
|
||||
employeeId: employeeId ? Number(employeeId) : undefined,
|
||||
appointmentDate,
|
||||
appointmentTime: appointmentTime + ":00",
|
||||
appointmentStatus: "Booked",
|
||||
@@ -513,6 +543,21 @@ function AppointmentsPage() {
|
||||
</select>
|
||||
</label>
|
||||
|
||||
{employees.length > 0 && (
|
||||
<label className="appt-label">
|
||||
Employee
|
||||
<select
|
||||
className="appt-select"
|
||||
value={employeeId}
|
||||
onChange={(e) => setEmployeeId(e.target.value)}
|
||||
>
|
||||
{employees.map((employee) => (
|
||||
<option key={employee.id} value={employee.id}>{employee.label}</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
)}
|
||||
|
||||
{selectedService && (
|
||||
<div className="appt-service-info">
|
||||
<p>{selectedService.serviceDesc}</p>
|
||||
|
||||
Reference in New Issue
Block a user