Merge branch 'main' into AttachmentsToChat
This commit is contained in:
@@ -11,7 +11,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -25,12 +27,14 @@ public class DropdownController {
|
|||||||
private final StoreRepository storeRepository;
|
private final StoreRepository storeRepository;
|
||||||
private final SupplierRepository supplierRepository;
|
private final SupplierRepository supplierRepository;
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
|
private final AdoptionRepository adoptionRepository;
|
||||||
|
|
||||||
public DropdownController(PetRepository petRepository,
|
public DropdownController(PetRepository petRepository,
|
||||||
ServiceRepository serviceRepository, ProductRepository productRepository,
|
ServiceRepository serviceRepository, ProductRepository productRepository,
|
||||||
CategoryRepository categoryRepository, StoreRepository storeRepository,
|
CategoryRepository categoryRepository, StoreRepository storeRepository,
|
||||||
SupplierRepository supplierRepository,
|
SupplierRepository supplierRepository,
|
||||||
UserRepository userRepository) {
|
UserRepository userRepository,
|
||||||
|
AdoptionRepository adoptionRepository) {
|
||||||
this.petRepository = petRepository;
|
this.petRepository = petRepository;
|
||||||
this.serviceRepository = serviceRepository;
|
this.serviceRepository = serviceRepository;
|
||||||
this.productRepository = productRepository;
|
this.productRepository = productRepository;
|
||||||
@@ -38,6 +42,7 @@ public class DropdownController {
|
|||||||
this.storeRepository = storeRepository;
|
this.storeRepository = storeRepository;
|
||||||
this.supplierRepository = supplierRepository;
|
this.supplierRepository = supplierRepository;
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
|
this.adoptionRepository = adoptionRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/pets")
|
@GetMapping("/pets")
|
||||||
@@ -74,8 +79,19 @@ public class DropdownController {
|
|||||||
@GetMapping("/appointment-customers")
|
@GetMapping("/appointment-customers")
|
||||||
@PreAuthorize("hasAnyRole('STAFF', 'ADMIN')")
|
@PreAuthorize("hasAnyRole('STAFF', 'ADMIN')")
|
||||||
public ResponseEntity<List<DropdownOption>> getAppointmentCustomers() {
|
public ResponseEntity<List<DropdownOption>> getAppointmentCustomers() {
|
||||||
|
Set<Long> ownersWithPets = petRepository.findAll().stream()
|
||||||
|
.filter(p -> p.getOwner() != null)
|
||||||
|
.map(p -> p.getOwner().getId())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Set<Long> customersWithAdoptions = adoptionRepository.findAll().stream()
|
||||||
|
.filter(a -> "Completed".equalsIgnoreCase(a.getAdoptionStatus()))
|
||||||
|
.map(a -> a.getCustomer().getId())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Set<Long> customersWithPets = new HashSet<>(ownersWithPets);
|
||||||
|
customersWithPets.addAll(customersWithAdoptions);
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
userRepository.findByRoleAndActiveTrue(User.Role.CUSTOMER).stream()
|
userRepository.findByRoleAndActiveTrue(User.Role.CUSTOMER).stream()
|
||||||
|
.filter(u -> customersWithPets.contains(u.getId()))
|
||||||
.map(u -> new DropdownOption(u.getId(), u.getFirstName() + " " + u.getLastName()))
|
.map(u -> new DropdownOption(u.getId(), u.getFirstName() + " " + u.getLastName()))
|
||||||
.sorted(Comparator.comparing(DropdownOption::getLabel, String.CASE_INSENSITIVE_ORDER))
|
.sorted(Comparator.comparing(DropdownOption::getLabel, String.CASE_INSENSITIVE_ORDER))
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
@@ -166,11 +182,16 @@ public class DropdownController {
|
|||||||
@GetMapping("/customers/{customerId}/pets")
|
@GetMapping("/customers/{customerId}/pets")
|
||||||
@PreAuthorize("hasAnyRole('STAFF', 'ADMIN')")
|
@PreAuthorize("hasAnyRole('STAFF', 'ADMIN')")
|
||||||
public ResponseEntity<List<DropdownOption>> getCustomerPets(@PathVariable Long customerId) {
|
public ResponseEntity<List<DropdownOption>> getCustomerPets(@PathVariable Long customerId) {
|
||||||
return ResponseEntity.ok(
|
Set<Long> seen = new HashSet<>();
|
||||||
petRepository.findAllByOwner_IdOrderByPetNameAsc(customerId).stream()
|
List<DropdownOption> pets = new java.util.ArrayList<>();
|
||||||
|
petRepository.findAllByOwner_IdOrderByPetNameAsc(customerId).stream()
|
||||||
.map(p -> new DropdownOption(p.getPetId(), p.getPetName()))
|
.map(p -> new DropdownOption(p.getPetId(), p.getPetName()))
|
||||||
.collect(Collectors.toList())
|
.forEach(o -> { if (seen.add(o.getId())) pets.add(o); });
|
||||||
);
|
adoptionRepository.findByCustomer_IdAndAdoptionStatusIgnoreCase(customerId, "Completed").stream()
|
||||||
|
.map(a -> new DropdownOption(a.getPet().getPetId(), a.getPet().getPetName()))
|
||||||
|
.forEach(o -> { if (seen.add(o.getId())) pets.add(o); });
|
||||||
|
pets.sort(java.util.Comparator.comparing(DropdownOption::getLabel, String.CASE_INSENSITIVE_ORDER));
|
||||||
|
return ResponseEntity.ok(pets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/suppliers")
|
@GetMapping("/suppliers")
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ public class AdoptionRequest {
|
|||||||
|
|
||||||
private Long sourceStoreId;
|
private Long sourceStoreId;
|
||||||
|
|
||||||
|
private String paymentMethod;
|
||||||
|
|
||||||
public Long getPetId() {
|
public Long getPetId() {
|
||||||
return petId;
|
return petId;
|
||||||
}
|
}
|
||||||
@@ -70,6 +72,14 @@ public class AdoptionRequest {
|
|||||||
this.sourceStoreId = sourceStoreId;
|
this.sourceStoreId = sourceStoreId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPaymentMethod() {
|
||||||
|
return paymentMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaymentMethod(String paymentMethod) {
|
||||||
|
this.paymentMethod = paymentMethod;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.springframework.data.repository.query.Param;
|
|||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
@@ -37,4 +38,6 @@ public interface AdoptionRepository extends JpaRepository<Adoption, Long> {
|
|||||||
boolean existsByPet_IdAndAdoptionStatusIgnoreCaseAndAdoptionIdNot(Long petId, String adoptionStatus, Long adoptionId);
|
boolean existsByPet_IdAndAdoptionStatusIgnoreCaseAndAdoptionIdNot(Long petId, String adoptionStatus, Long adoptionId);
|
||||||
|
|
||||||
boolean existsByPet_IdAndAdoptionStatusIgnoreCase(Long petId, String adoptionStatus);
|
boolean existsByPet_IdAndAdoptionStatusIgnoreCase(Long petId, String adoptionStatus);
|
||||||
|
|
||||||
|
List<Adoption> findByCustomer_IdAndAdoptionStatusIgnoreCase(Long customerId, String adoptionStatus);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ import com.petshop.backend.dto.adoption.AdoptionResponse;
|
|||||||
import com.petshop.backend.dto.common.BulkDeleteRequest;
|
import com.petshop.backend.dto.common.BulkDeleteRequest;
|
||||||
import com.petshop.backend.entity.Adoption;
|
import com.petshop.backend.entity.Adoption;
|
||||||
import com.petshop.backend.entity.Pet;
|
import com.petshop.backend.entity.Pet;
|
||||||
|
import com.petshop.backend.entity.Sale;
|
||||||
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.ResourceNotFoundException;
|
import com.petshop.backend.exception.ResourceNotFoundException;
|
||||||
import com.petshop.backend.repository.AdoptionRepository;
|
import com.petshop.backend.repository.AdoptionRepository;
|
||||||
import com.petshop.backend.repository.PetRepository;
|
import com.petshop.backend.repository.PetRepository;
|
||||||
|
import com.petshop.backend.repository.SaleRepository;
|
||||||
import com.petshop.backend.repository.StoreRepository;
|
import com.petshop.backend.repository.StoreRepository;
|
||||||
import com.petshop.backend.repository.UserRepository;
|
import com.petshop.backend.repository.UserRepository;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
@@ -17,7 +19,9 @@ import org.springframework.data.domain.Pageable;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class AdoptionService {
|
public class AdoptionService {
|
||||||
@@ -32,12 +36,14 @@ public class AdoptionService {
|
|||||||
private final PetRepository petRepository;
|
private final PetRepository petRepository;
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final StoreRepository storeRepository;
|
private final StoreRepository storeRepository;
|
||||||
|
private final SaleRepository saleRepository;
|
||||||
|
|
||||||
public AdoptionService(AdoptionRepository adoptionRepository, PetRepository petRepository, UserRepository userRepository, StoreRepository storeRepository) {
|
public AdoptionService(AdoptionRepository adoptionRepository, PetRepository petRepository, UserRepository userRepository, StoreRepository storeRepository, SaleRepository saleRepository) {
|
||||||
this.adoptionRepository = adoptionRepository;
|
this.adoptionRepository = adoptionRepository;
|
||||||
this.petRepository = petRepository;
|
this.petRepository = petRepository;
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
this.storeRepository = storeRepository;
|
this.storeRepository = storeRepository;
|
||||||
|
this.saleRepository = saleRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Page<AdoptionResponse> getAllAdoptions(String query, Long customerId, String status, Long storeId, LocalDate date, Pageable pageable) {
|
public Page<AdoptionResponse> getAllAdoptions(String query, Long customerId, String status, Long storeId, LocalDate date, Pageable pageable) {
|
||||||
@@ -81,6 +87,9 @@ public class AdoptionService {
|
|||||||
: null;
|
: null;
|
||||||
String adoptionStatus = normalizeAdoptionStatus(request.getAdoptionStatus());
|
String adoptionStatus = normalizeAdoptionStatus(request.getAdoptionStatus());
|
||||||
validatePetAvailability(pet, null, null);
|
validatePetAvailability(pet, null, null);
|
||||||
|
if (ADOPTION_STATUS_COMPLETED.equalsIgnoreCase(adoptionStatus) && request.getAdoptionDate() != null && request.getAdoptionDate().isAfter(LocalDate.now())) {
|
||||||
|
throw new IllegalArgumentException("Cannot mark a future-dated adoption as Completed");
|
||||||
|
}
|
||||||
|
|
||||||
Adoption adoption = new Adoption();
|
Adoption adoption = new Adoption();
|
||||||
adoption.setPet(pet);
|
adoption.setPet(pet);
|
||||||
@@ -91,7 +100,10 @@ public class AdoptionService {
|
|||||||
adoption.setAdoptionStatus(adoptionStatus);
|
adoption.setAdoptionStatus(adoptionStatus);
|
||||||
|
|
||||||
adoption = adoptionRepository.save(adoption);
|
adoption = adoptionRepository.save(adoption);
|
||||||
syncPetStatus(pet, adoptionStatus, adoption.getAdoptionId());
|
syncPetStatus(pet, adoptionStatus, adoption.getAdoptionId(), customer);
|
||||||
|
if (ADOPTION_STATUS_COMPLETED.equalsIgnoreCase(adoptionStatus)) {
|
||||||
|
createSaleForAdoption(adoption, request.getPaymentMethod());
|
||||||
|
}
|
||||||
return mapToResponse(adoption);
|
return mapToResponse(adoption);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,9 +122,13 @@ public class AdoptionService {
|
|||||||
? storeRepository.findById(request.getSourceStoreId())
|
? storeRepository.findById(request.getSourceStoreId())
|
||||||
.orElseThrow(() -> new ResourceNotFoundException("Store not found with id: " + request.getSourceStoreId()))
|
.orElseThrow(() -> new ResourceNotFoundException("Store not found with id: " + request.getSourceStoreId()))
|
||||||
: null;
|
: null;
|
||||||
|
boolean wasCompleted = ADOPTION_STATUS_COMPLETED.equalsIgnoreCase(adoption.getAdoptionStatus());
|
||||||
String adoptionStatus = normalizeAdoptionStatus(request.getAdoptionStatus());
|
String adoptionStatus = normalizeAdoptionStatus(request.getAdoptionStatus());
|
||||||
Long currentPetId = adoption.getPet() != null ? adoption.getPet().getPetId() : null;
|
Long currentPetId = adoption.getPet() != null ? adoption.getPet().getPetId() : null;
|
||||||
validatePetAvailability(pet, adoption.getAdoptionId(), currentPetId);
|
validatePetAvailability(pet, adoption.getAdoptionId(), currentPetId);
|
||||||
|
if (ADOPTION_STATUS_COMPLETED.equalsIgnoreCase(adoptionStatus) && request.getAdoptionDate() != null && request.getAdoptionDate().isAfter(LocalDate.now())) {
|
||||||
|
throw new IllegalArgumentException("Cannot mark a future-dated adoption as Completed");
|
||||||
|
}
|
||||||
|
|
||||||
adoption.setPet(pet);
|
adoption.setPet(pet);
|
||||||
adoption.setCustomer(customer);
|
adoption.setCustomer(customer);
|
||||||
@@ -122,7 +138,10 @@ public class AdoptionService {
|
|||||||
adoption.setAdoptionStatus(adoptionStatus);
|
adoption.setAdoptionStatus(adoptionStatus);
|
||||||
|
|
||||||
adoption = adoptionRepository.save(adoption);
|
adoption = adoptionRepository.save(adoption);
|
||||||
syncPetStatus(pet, adoptionStatus, adoption.getAdoptionId());
|
syncPetStatus(pet, adoptionStatus, adoption.getAdoptionId(), customer);
|
||||||
|
if (!wasCompleted && ADOPTION_STATUS_COMPLETED.equalsIgnoreCase(adoptionStatus)) {
|
||||||
|
createSaleForAdoption(adoption, request.getPaymentMethod());
|
||||||
|
}
|
||||||
return mapToResponse(adoption);
|
return mapToResponse(adoption);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,13 +235,37 @@ public class AdoptionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncPetStatus(Pet pet, String adoptionStatus, Long adoptionId) {
|
private void createSaleForAdoption(Adoption adoption, String paymentMethod) {
|
||||||
|
if (adoption.getEmployee() == null || adoption.getSourceStore() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BigDecimal amount = adoption.getPet().getPetPrice();
|
||||||
|
if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
amount = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
Sale sale = new Sale();
|
||||||
|
sale.setSaleDate(LocalDateTime.now());
|
||||||
|
sale.setEmployee(adoption.getEmployee());
|
||||||
|
sale.setStore(adoption.getSourceStore());
|
||||||
|
sale.setCustomer(adoption.getCustomer());
|
||||||
|
sale.setTotalAmount(amount);
|
||||||
|
sale.setSubtotalAmount(amount);
|
||||||
|
sale.setPaymentMethod(paymentMethod != null && !paymentMethod.isBlank() ? paymentMethod : "Cash");
|
||||||
|
sale.setIsRefund(false);
|
||||||
|
sale.setChannel("ADOPTION");
|
||||||
|
saleRepository.save(sale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncPetStatus(Pet pet, String adoptionStatus, Long adoptionId, User customer) {
|
||||||
boolean completedElsewhere = adoptionId != null
|
boolean completedElsewhere = adoptionId != null
|
||||||
&& adoptionRepository.existsByPet_IdAndAdoptionStatusIgnoreCaseAndAdoptionIdNot(pet.getPetId(), ADOPTION_STATUS_COMPLETED, adoptionId);
|
&& adoptionRepository.existsByPet_IdAndAdoptionStatusIgnoreCaseAndAdoptionIdNot(pet.getPetId(), ADOPTION_STATUS_COMPLETED, adoptionId);
|
||||||
if (ADOPTION_STATUS_COMPLETED.equalsIgnoreCase(adoptionStatus) || completedElsewhere) {
|
if (ADOPTION_STATUS_COMPLETED.equalsIgnoreCase(adoptionStatus) || completedElsewhere) {
|
||||||
pet.setPetStatus(PET_STATUS_ADOPTED);
|
pet.setPetStatus(PET_STATUS_ADOPTED);
|
||||||
|
pet.setOwner(customer);
|
||||||
|
pet.setStore(null);
|
||||||
} else {
|
} else {
|
||||||
pet.setPetStatus(PET_STATUS_AVAILABLE);
|
pet.setPetStatus(PET_STATUS_AVAILABLE);
|
||||||
|
pet.setOwner(null);
|
||||||
}
|
}
|
||||||
petRepository.save(pet);
|
petRepository.save(pet);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ public class AdoptionRequest {
|
|||||||
private Long sourceStoreId;
|
private Long sourceStoreId;
|
||||||
private LocalDate adoptionDate;
|
private LocalDate adoptionDate;
|
||||||
private String adoptionStatus;
|
private String adoptionStatus;
|
||||||
|
private String paymentMethod;
|
||||||
|
|
||||||
public AdoptionRequest() {
|
public AdoptionRequest() {
|
||||||
}
|
}
|
||||||
@@ -60,4 +61,12 @@ public class AdoptionRequest {
|
|||||||
public void setAdoptionStatus(String adoptionStatus) {
|
public void setAdoptionStatus(String adoptionStatus) {
|
||||||
this.adoptionStatus = adoptionStatus;
|
this.adoptionStatus = adoptionStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPaymentMethod() {
|
||||||
|
return paymentMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaymentMethod(String paymentMethod) {
|
||||||
|
this.paymentMethod = paymentMethod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,16 +241,16 @@ public class AppointmentController {
|
|||||||
return new AppointmentDTO(
|
return new AppointmentDTO(
|
||||||
response.getAppointmentId().intValue(),
|
response.getAppointmentId().intValue(),
|
||||||
response.getCustomerId() != null ? response.getCustomerId().intValue() : 0,
|
response.getCustomerId() != null ? response.getCustomerId().intValue() : 0,
|
||||||
response.getCustomerName(),
|
response.getCustomerName() != null ? response.getCustomerName() : "",
|
||||||
response.getPetId() != null ? response.getPetId().intValue() : 0,
|
response.getPetId() != null ? response.getPetId().intValue() : 0,
|
||||||
response.getPetName(),
|
response.getPetName() != null ? response.getPetName() : "",
|
||||||
response.getServiceId() != null ? response.getServiceId().intValue() : 0,
|
response.getServiceId() != null ? response.getServiceId().intValue() : 0,
|
||||||
response.getServiceName(),
|
response.getServiceName() != null ? response.getServiceName() : "",
|
||||||
response.getEmployeeId() != null ? response.getEmployeeId().intValue() : 0,
|
response.getEmployeeId() != null ? response.getEmployeeId().intValue() : 0,
|
||||||
response.getEmployeeName(),
|
response.getEmployeeName() != null ? response.getEmployeeName() : "",
|
||||||
response.getAppointmentDate().toString(),
|
response.getAppointmentDate() != null ? response.getAppointmentDate().toString() : "",
|
||||||
response.getAppointmentTime().toString(),
|
response.getAppointmentTime() != null ? response.getAppointmentTime().toString() : "",
|
||||||
response.getAppointmentStatus()
|
response.getAppointmentStatus() != null ? response.getAppointmentStatus() : ""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,12 @@ public class ChatController {
|
|||||||
});
|
});
|
||||||
|
|
||||||
realtimeClient.setConversationListener(conversation -> Platform.runLater(() -> upsertConversation(conversation)));
|
realtimeClient.setConversationListener(conversation -> Platform.runLater(() -> upsertConversation(conversation)));
|
||||||
realtimeClient.setMessageListener(message -> Platform.runLater(() -> appendMessageIfSelected(message)));
|
realtimeClient.setMessageListener(message -> Platform.runLater(() -> {
|
||||||
|
Long myId = UserSession.getInstance().getUserId();
|
||||||
|
if (message.getSenderId() == null || !message.getSenderId().equals(myId)) {
|
||||||
|
appendMessageIfSelected(message);
|
||||||
|
}
|
||||||
|
}));
|
||||||
realtimeClient.setStatusListener(status -> Platform.runLater(() -> lblChatStatus.setText(status)));
|
realtimeClient.setStatusListener(status -> Platform.runLater(() -> lblChatStatus.setText(status)));
|
||||||
realtimeClient.subscribeToConversations();
|
realtimeClient.subscribeToConversations();
|
||||||
|
|
||||||
@@ -208,9 +213,7 @@ public class ChatController {
|
|||||||
MessageResponse response = ChatApi.getInstance().sendMessage(conversationId, new MessageRequest(content));
|
MessageResponse response = ChatApi.getInstance().sendMessage(conversationId, new MessageRequest(content));
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
btnSend.setDisable(false);
|
btnSend.setDisable(false);
|
||||||
if (!realtimeClient.isConnected()) {
|
appendMessageIfSelected(response);
|
||||||
appendMessageIfSelected(response);
|
|
||||||
}
|
|
||||||
if (selectedConversation != null && selectedConversation.getId().equals(conversationId)) {
|
if (selectedConversation != null && selectedConversation.getId().equals(conversationId)) {
|
||||||
lblChatStatus.setText("Message sent");
|
lblChatStatus.setText("Message sent");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,12 +327,12 @@ public class PetController {
|
|||||||
private Pet mapToPet(PetResponse response) {
|
private Pet mapToPet(PetResponse response) {
|
||||||
Pet pet = new Pet(
|
Pet pet = new Pet(
|
||||||
response.getPetId().intValue(),
|
response.getPetId().intValue(),
|
||||||
response.getPetName(),
|
response.getPetName() != null ? response.getPetName() : "",
|
||||||
response.getPetSpecies(),
|
response.getPetSpecies() != null ? response.getPetSpecies() : "",
|
||||||
response.getPetBreed(),
|
response.getPetBreed() != null ? response.getPetBreed() : "",
|
||||||
response.getPetAge() != null ? response.getPetAge() : 0,
|
response.getPetAge() != null ? response.getPetAge() : 0,
|
||||||
response.getPetStatus(),
|
response.getPetStatus() != null ? response.getPetStatus() : "",
|
||||||
response.getPetPrice().doubleValue(),
|
response.getPetPrice() != null ? response.getPetPrice().doubleValue() : 0.0,
|
||||||
response.getImageUrl()
|
response.getImageUrl()
|
||||||
);
|
);
|
||||||
pet.setCustomerName(response.getCustomerName());
|
pet.setCustomerName(response.getCustomerName());
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import javafx.fxml.FXML;
|
|||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.ChoiceDialog;
|
||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.DatePicker;
|
import javafx.scene.control.DatePicker;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
@@ -57,6 +58,8 @@ public class AdoptionDialogController {
|
|||||||
|
|
||||||
private String mode = null;
|
private String mode = null;
|
||||||
private Adoption selectedAdoption = null;
|
private Adoption selectedAdoption = null;
|
||||||
|
private String selectedPaymentMethod = null;
|
||||||
|
private boolean suppressPaymentDialog = false;
|
||||||
|
|
||||||
private ObservableList<String> statusList = FXCollections.observableArrayList(
|
private ObservableList<String> statusList = FXCollections.observableArrayList(
|
||||||
"Pending", "Completed", "Cancelled"
|
"Pending", "Completed", "Cancelled"
|
||||||
@@ -66,6 +69,23 @@ public class AdoptionDialogController {
|
|||||||
void initialize() {
|
void initialize() {
|
||||||
|
|
||||||
cbAdoptionStatus.setItems(statusList);
|
cbAdoptionStatus.setItems(statusList);
|
||||||
|
cbAdoptionStatus.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||||
|
if ("Completed".equals(newVal) && !"Completed".equals(oldVal) && !suppressPaymentDialog) {
|
||||||
|
ChoiceDialog<String> dialog = new ChoiceDialog<>("Cash", "Cash", "Credit Card", "Debit Card", "E-Transfer");
|
||||||
|
dialog.setTitle("Payment Method");
|
||||||
|
dialog.setHeaderText("Confirm payment received");
|
||||||
|
dialog.setContentText("Select payment method:");
|
||||||
|
dialog.showAndWait().ifPresentOrElse(
|
||||||
|
method -> selectedPaymentMethod = method,
|
||||||
|
() -> {
|
||||||
|
selectedPaymentMethod = null;
|
||||||
|
cbAdoptionStatus.setValue(oldVal);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if (!"Completed".equals(newVal)) {
|
||||||
|
selectedPaymentMethod = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
cbEmployee.setPromptText("Select an employee");
|
cbEmployee.setPromptText("Select an employee");
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
@@ -92,15 +112,11 @@ public class AdoptionDialogController {
|
|||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Long storeId = UserSession.getInstance().getStoreId();
|
List<DropdownOption> employees = DropdownApi.getInstance().getEmployees();
|
||||||
List<DropdownOption> employees;
|
|
||||||
if (storeId != null && storeId > 0) {
|
|
||||||
employees = DropdownApi.getInstance().getStoreEmployees(storeId);
|
|
||||||
} else {
|
|
||||||
employees = DropdownApi.getInstance().getEmployees();
|
|
||||||
}
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
cbEmployee.setItems(FXCollections.observableArrayList(employees));
|
ObservableList<DropdownOption> employeesObs = FXCollections.observableArrayList(employees);
|
||||||
|
ensureSelectedEmployeeOption(employeesObs);
|
||||||
|
cbEmployee.setItems(employeesObs);
|
||||||
applySelectedEmployee();
|
applySelectedEmployee();
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -203,6 +219,7 @@ public class AdoptionDialogController {
|
|||||||
request.setSourceStoreId(storeId);
|
request.setSourceStoreId(storeId);
|
||||||
request.setAdoptionDate(dpAdoptionDate.getValue());
|
request.setAdoptionDate(dpAdoptionDate.getValue());
|
||||||
request.setAdoptionStatus(cbAdoptionStatus.getValue());
|
request.setAdoptionStatus(cbAdoptionStatus.getValue());
|
||||||
|
request.setPaymentMethod(selectedPaymentMethod);
|
||||||
|
|
||||||
if (mode.equals("Add")) {
|
if (mode.equals("Add")) {
|
||||||
AdoptionApi.getInstance().createAdoption(request);
|
AdoptionApi.getInstance().createAdoption(request);
|
||||||
@@ -263,12 +280,14 @@ public class AdoptionDialogController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suppressPaymentDialog = true;
|
||||||
for (String status : cbAdoptionStatus.getItems()) {
|
for (String status : cbAdoptionStatus.getItems()) {
|
||||||
if (status.equals(adoption.getAdoptionStatus())) {
|
if (status.equals(adoption.getAdoptionStatus())) {
|
||||||
cbAdoptionStatus.getSelectionModel().select(status);
|
cbAdoptionStatus.getSelectionModel().select(status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
suppressPaymentDialog = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,6 +339,19 @@ public class AdoptionDialogController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ensureSelectedEmployeeOption(ObservableList<DropdownOption> options) {
|
||||||
|
if (selectedAdoption == null || selectedAdoption.getEmployeeId() <= 0 || options == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DropdownOption existing = findOptionById(options, (long) selectedAdoption.getEmployeeId());
|
||||||
|
if (existing == null) {
|
||||||
|
DropdownOption option = new DropdownOption();
|
||||||
|
option.setId((long) selectedAdoption.getEmployeeId());
|
||||||
|
option.setLabel(selectedAdoption.getEmployeeName() != null ? selectedAdoption.getEmployeeName() : "Employee #" + selectedAdoption.getEmployeeId());
|
||||||
|
options.add(0, option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ensureSelectedPetOption(ObservableList<DropdownOption> options) {
|
private void ensureSelectedPetOption(ObservableList<DropdownOption> options) {
|
||||||
if (selectedAdoption == null || selectedAdoption.getPetId() <= 0 || options == null) {
|
if (selectedAdoption == null || selectedAdoption.getPetId() <= 0 || options == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
|||||||
import org.example.petshopdesktop.auth.UserSession;
|
import org.example.petshopdesktop.auth.UserSession;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
|
import java.time.DayOfWeek;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -65,7 +66,15 @@ public class AppointmentDialogController {
|
|||||||
cbPet.setPromptText("Select a customer first");
|
cbPet.setPromptText("Select a customer first");
|
||||||
cbCustomer.setPromptText("Select a customer");
|
cbCustomer.setPromptText("Select a customer");
|
||||||
cbService.setPromptText("Select a service");
|
cbService.setPromptText("Select a service");
|
||||||
dpAppointmentDate.setValue(LocalDate.now().plusDays(1));
|
LocalDate minDate = minAppointmentDate();
|
||||||
|
dpAppointmentDate.setValue(minDate);
|
||||||
|
dpAppointmentDate.setDayCellFactory(picker -> new javafx.scene.control.DateCell() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(LocalDate item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
setDisable(empty || item.isBefore(minDate));
|
||||||
|
}
|
||||||
|
});
|
||||||
cbAppointmentStatus.setValue("Booked");
|
cbAppointmentStatus.setValue("Booked");
|
||||||
|
|
||||||
for (int i = 9; i <= 17; i++) {
|
for (int i = 9; i <= 17; i++) {
|
||||||
@@ -315,9 +324,20 @@ public class AppointmentDialogController {
|
|||||||
try {
|
try {
|
||||||
List<DropdownOption> pets = DropdownApi.getInstance().getCustomerPets(customerId);
|
List<DropdownOption> pets = DropdownApi.getInstance().getCustomerPets(customerId);
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
cbPet.setItems(FXCollections.observableArrayList(pets));
|
ObservableList<DropdownOption> petOptions = FXCollections.observableArrayList(pets != null ? pets : List.of());
|
||||||
cbPet.setDisable(pets == null || pets.isEmpty());
|
if (pendingPetSelectionId != null) {
|
||||||
cbPet.setPromptText(pets == null || pets.isEmpty() ? "No pets for selected customer" : "Select a pet");
|
boolean found = petOptions.stream().anyMatch(p -> pendingPetSelectionId.equals(p.getId()));
|
||||||
|
if (!found && selectedAppointment != null && selectedAppointment.getPetId() > 0) {
|
||||||
|
DropdownOption placeholder = new DropdownOption();
|
||||||
|
placeholder.setId((long) selectedAppointment.getPetId());
|
||||||
|
placeholder.setLabel(selectedAppointment.getPetName() != null && !selectedAppointment.getPetName().isBlank()
|
||||||
|
? selectedAppointment.getPetName() : "Pet #" + selectedAppointment.getPetId());
|
||||||
|
petOptions.add(0, placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cbPet.setItems(petOptions);
|
||||||
|
cbPet.setDisable(petOptions.isEmpty());
|
||||||
|
cbPet.setPromptText(petOptions.isEmpty() ? "No pets for selected customer" : "Select a pet");
|
||||||
if (pendingPetSelectionId != null) {
|
if (pendingPetSelectionId != null) {
|
||||||
for (DropdownOption pet : cbPet.getItems()) {
|
for (DropdownOption pet : cbPet.getItems()) {
|
||||||
if (pet.getId() != null && pet.getId().equals(pendingPetSelectionId)) {
|
if (pet.getId() != null && pet.getId().equals(pendingPetSelectionId)) {
|
||||||
@@ -392,6 +412,19 @@ public class AppointmentDialogController {
|
|||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LocalDate minAppointmentDate() {
|
||||||
|
LocalDate date = LocalDate.now();
|
||||||
|
int businessDaysAdded = 0;
|
||||||
|
while (businessDaysAdded < 2) {
|
||||||
|
date = date.plusDays(1);
|
||||||
|
DayOfWeek dow = date.getDayOfWeek();
|
||||||
|
if (dow != DayOfWeek.SATURDAY && dow != DayOfWeek.SUNDAY) {
|
||||||
|
businessDaysAdded++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
private void loadEmployees() {
|
private void loadEmployees() {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ public class PetDialogController {
|
|||||||
@FXML
|
@FXML
|
||||||
private VBox vbStoreField;
|
private VBox vbStoreField;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private VBox vbPriceField;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label lblMode;
|
private Label lblMode;
|
||||||
|
|
||||||
@@ -80,7 +83,7 @@ public class PetDialogController {
|
|||||||
private TextField txtPetPrice;
|
private TextField txtPetPrice;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TextField txtPetSpecies;
|
private ComboBox<String> cbPetSpecies;
|
||||||
|
|
||||||
private String mode = null;
|
private String mode = null;
|
||||||
private File selectedImageFile;
|
private File selectedImageFile;
|
||||||
@@ -127,6 +130,9 @@ public class PetDialogController {
|
|||||||
|
|
||||||
setFieldVisibility(vbCustomerField, false);
|
setFieldVisibility(vbCustomerField, false);
|
||||||
setFieldVisibility(vbStoreField, false);
|
setFieldVisibility(vbStoreField, false);
|
||||||
|
setFieldVisibility(vbPriceField, true);
|
||||||
|
|
||||||
|
loadSpecies();
|
||||||
|
|
||||||
cbPetStatus.valueProperty().addListener((obs, oldVal, newVal) -> {
|
cbPetStatus.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||||
updateStatusFieldVisibility(newVal);
|
updateStatusFieldVisibility(newVal);
|
||||||
@@ -161,28 +167,37 @@ public class PetDialogController {
|
|||||||
errorMsg += Validator.isPresent(txtPetName.getText(), "Pet Name");
|
errorMsg += Validator.isPresent(txtPetName.getText(), "Pet Name");
|
||||||
errorMsg += Validator.isPresent(txtPetAge.getText(), "Age");
|
errorMsg += Validator.isPresent(txtPetAge.getText(), "Age");
|
||||||
errorMsg += Validator.isPresent(txtPetBreed.getText(), "Breed");
|
errorMsg += Validator.isPresent(txtPetBreed.getText(), "Breed");
|
||||||
errorMsg += Validator.isPresent(txtPetSpecies.getText(), "Species");
|
String speciesValue = cbPetSpecies.getValue() != null ? cbPetSpecies.getValue().trim() : "";
|
||||||
errorMsg += Validator.isPresent(txtPetPrice.getText(), "Price");
|
if (speciesValue.isEmpty()) errorMsg += "Species is required\n";
|
||||||
|
String selectedStatus = cbPetStatus.getValue();
|
||||||
|
boolean needsPrice = !("Owned".equalsIgnoreCase(selectedStatus) || "Adopted".equalsIgnoreCase(selectedStatus));
|
||||||
|
if (needsPrice) {
|
||||||
|
errorMsg += Validator.isPresent(txtPetPrice.getText(), "Price");
|
||||||
|
}
|
||||||
if (cbPetStatus.getSelectionModel().getSelectedItem() == null){
|
if (cbPetStatus.getSelectionModel().getSelectedItem() == null){
|
||||||
errorMsg += "Status is required";
|
errorMsg += "Status is required";
|
||||||
}
|
}
|
||||||
String selectedStatus = cbPetStatus.getValue();
|
|
||||||
if ("Owned".equalsIgnoreCase(selectedStatus) && cbCustomer.getValue() == null) {
|
if ("Owned".equalsIgnoreCase(selectedStatus) && cbCustomer.getValue() == null) {
|
||||||
errorMsg += "Customer is required for Owned status\n";
|
errorMsg += "Customer is required for Owned status\n";
|
||||||
}
|
}
|
||||||
if (requiresStore(selectedStatus) && cbStore.getValue() == null) {
|
boolean storeRequired = requiresStore(selectedStatus) && !"Adopted".equalsIgnoreCase(selectedStatus);
|
||||||
|
if (storeRequired && cbStore.getValue() == null) {
|
||||||
errorMsg += "Store is required for " + selectedStatus + " status\n";
|
errorMsg += "Store is required for " + selectedStatus + " status\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check validation (length size)
|
//Check validation (length size)
|
||||||
errorMsg += Validator.isLessThanVarChars(txtPetName.getText(), "Pet Name", 50);
|
errorMsg += Validator.isLessThanVarChars(txtPetName.getText(), "Pet Name", 50);
|
||||||
errorMsg += Validator.isLessThanVarChars(txtPetSpecies.getText(), "Species", 50);
|
errorMsg += Validator.isLessThanVarChars(speciesValue, "Species", 50);
|
||||||
errorMsg += Validator.isLessThanVarChars(txtPetBreed.getText(), "Breed", 50);
|
errorMsg += Validator.isLessThanVarChars(txtPetBreed.getText(), "Breed", 50);
|
||||||
errorMsg += Validator.isLessThanVarChars(txtPetPrice.getText(), "Price", 12);
|
if (needsPrice) {
|
||||||
|
errorMsg += Validator.isLessThanVarChars(txtPetPrice.getText(), "Price", 12);
|
||||||
|
}
|
||||||
errorMsg += Validator.isLessThanVarChars(txtPetAge.getText(), "Age", 11);
|
errorMsg += Validator.isLessThanVarChars(txtPetAge.getText(), "Age", 11);
|
||||||
|
|
||||||
//Check validation (format)
|
//Check validation (format)
|
||||||
errorMsg += Validator.isNonNegativeDouble(txtPetPrice.getText(), "Price");
|
if (needsPrice) {
|
||||||
|
errorMsg += Validator.isNonNegativeDouble(txtPetPrice.getText(), "Price");
|
||||||
|
}
|
||||||
errorMsg += Validator.isPositiveInteger(txtPetAge.getText(), "Age");
|
errorMsg += Validator.isPositiveInteger(txtPetAge.getText(), "Age");
|
||||||
|
|
||||||
if(errorMsg.isEmpty()){
|
if(errorMsg.isEmpty()){
|
||||||
@@ -229,13 +244,17 @@ public class PetDialogController {
|
|||||||
private PetRequest buildPetRequest() {
|
private PetRequest buildPetRequest() {
|
||||||
PetRequest request = new PetRequest();
|
PetRequest request = new PetRequest();
|
||||||
request.setPetName(txtPetName.getText());
|
request.setPetName(txtPetName.getText());
|
||||||
request.setPetSpecies(txtPetSpecies.getText());
|
request.setPetSpecies(cbPetSpecies.getValue() != null ? cbPetSpecies.getValue().trim() : "");
|
||||||
request.setPetBreed(txtPetBreed.getText());
|
request.setPetBreed(txtPetBreed.getText());
|
||||||
request.setPetStatus(cbPetStatus.getValue());
|
request.setPetStatus(cbPetStatus.getValue());
|
||||||
try {
|
String buildStatus = cbPetStatus.getValue();
|
||||||
request.setPetPrice(new BigDecimal(txtPetPrice.getText()));
|
boolean buildNeedsPrice = !("Owned".equalsIgnoreCase(buildStatus) || "Adopted".equalsIgnoreCase(buildStatus));
|
||||||
} catch (NumberFormatException e) {
|
if (buildNeedsPrice && txtPetPrice.getText() != null && !txtPetPrice.getText().isBlank()) {
|
||||||
throw new IllegalArgumentException("Invalid price format");
|
try {
|
||||||
|
request.setPetPrice(new BigDecimal(txtPetPrice.getText()));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid price format");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int age;
|
int age;
|
||||||
@@ -247,7 +266,7 @@ public class PetDialogController {
|
|||||||
request.setPetAge(age);
|
request.setPetAge(age);
|
||||||
|
|
||||||
String status = cbPetStatus.getValue();
|
String status = cbPetStatus.getValue();
|
||||||
if ("Owned".equalsIgnoreCase(status) && cbCustomer.getValue() != null) {
|
if (("Owned".equalsIgnoreCase(status) || "Adopted".equalsIgnoreCase(status)) && cbCustomer.getValue() != null) {
|
||||||
request.setCustomerId(cbCustomer.getValue().getId());
|
request.setCustomerId(cbCustomer.getValue().getId());
|
||||||
}
|
}
|
||||||
if (requiresStore(status) && cbStore.getValue() != null) {
|
if (requiresStore(status) && cbStore.getValue() != null) {
|
||||||
@@ -257,6 +276,27 @@ public class PetDialogController {
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadSpecies() {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<DropdownOption> options = DropdownApi.getInstance().getPetSpecies();
|
||||||
|
List<String> species = options.stream()
|
||||||
|
.map(DropdownOption::getLabel)
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
String current = cbPetSpecies.getValue();
|
||||||
|
cbPetSpecies.setItems(FXCollections.observableArrayList(species));
|
||||||
|
if (current != null && !current.isBlank()) {
|
||||||
|
cbPetSpecies.setValue(current);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> ActivityLogger.getInstance().logException(
|
||||||
|
"PetDialogController.loadSpecies", e, "Loading species dropdown"));
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
private void loadCustomers() {
|
private void loadCustomers() {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
@@ -331,7 +371,7 @@ public class PetDialogController {
|
|||||||
if (pet!=null){
|
if (pet!=null){
|
||||||
lblPetId.setText("ID: " + pet.getPetId());
|
lblPetId.setText("ID: " + pet.getPetId());
|
||||||
txtPetName.setText(pet.getPetName());
|
txtPetName.setText(pet.getPetName());
|
||||||
txtPetSpecies.setText(pet.getPetSpecies());
|
cbPetSpecies.setValue(pet.getPetSpecies());
|
||||||
txtPetBreed.setText(pet.getPetBreed());
|
txtPetBreed.setText(pet.getPetBreed());
|
||||||
txtPetAge.setText(pet.getPetAge() + "");
|
txtPetAge.setText(pet.getPetAge() + "");
|
||||||
txtPetPrice.setText(pet.getPetPrice() + "");
|
txtPetPrice.setText(pet.getPetPrice() + "");
|
||||||
@@ -432,16 +472,19 @@ public class PetDialogController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateStatusFieldVisibility(String status) {
|
private void updateStatusFieldVisibility(String status) {
|
||||||
boolean owned = "Owned".equalsIgnoreCase(status);
|
boolean needsCustomer = "Owned".equalsIgnoreCase(status) || "Adopted".equalsIgnoreCase(status);
|
||||||
boolean storeBased = requiresStore(status);
|
boolean storeBased = requiresStore(status);
|
||||||
setFieldVisibility(vbCustomerField, owned);
|
boolean needsPrice = !needsCustomer;
|
||||||
|
setFieldVisibility(vbCustomerField, needsCustomer);
|
||||||
setFieldVisibility(vbStoreField, storeBased);
|
setFieldVisibility(vbStoreField, storeBased);
|
||||||
|
setFieldVisibility(vbPriceField, needsPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean requiresStore(String status) {
|
private boolean requiresStore(String status) {
|
||||||
return "Available".equalsIgnoreCase(status)
|
return "Available".equalsIgnoreCase(status)
|
||||||
|| "Pending".equalsIgnoreCase(status)
|
|| "Pending".equalsIgnoreCase(status)
|
||||||
|| "Unadopted".equalsIgnoreCase(status);
|
|| "Unadopted".equalsIgnoreCase(status)
|
||||||
|
|| "Adopted".equalsIgnoreCase(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setFieldVisibility(VBox field, boolean visible) {
|
private void setFieldVisibility(VBox field, boolean visible) {
|
||||||
|
|||||||
@@ -91,11 +91,11 @@
|
|||||||
<Font name="System Bold" size="16.0" />
|
<Font name="System Bold" size="16.0" />
|
||||||
</font>
|
</font>
|
||||||
</Label>
|
</Label>
|
||||||
<TextField fx:id="txtPetSpecies" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10;">
|
<ComboBox fx:id="cbPetSpecies" editable="true" prefHeight="29.0" prefWidth="336.0" promptText="Select or enter species" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10; -fx-background-color: white;">
|
||||||
<padding>
|
<padding>
|
||||||
<Insets bottom="7.0" left="10.0" right="10.0" top="7.0" />
|
<Insets bottom="3.0" left="10.0" right="10.0" top="3.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</TextField>
|
</ComboBox>
|
||||||
</children>
|
</children>
|
||||||
</VBox>
|
</VBox>
|
||||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="1">
|
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="1">
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
</padding>
|
</padding>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</children></VBox>
|
</children></VBox>
|
||||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
<VBox fx:id="vbPriceField" prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
||||||
<children>
|
<children>
|
||||||
<Label text="Price:" textFill="#2c3e50">
|
<Label text="Price:" textFill="#2c3e50">
|
||||||
<font>
|
<font>
|
||||||
|
|||||||
@@ -91,7 +91,7 @@
|
|||||||
</padding>
|
</padding>
|
||||||
</Label>
|
</Label>
|
||||||
|
|
||||||
<Button fx:id="btnAnalytics" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnAnalyticsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="📊 Analytics" textFill="#cbd5e1">
|
<Button fx:id="btnAnalytics" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnAnalyticsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Analytics" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="btnSalesHistory" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnSalesHistoryClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="💰 Sales History" textFill="#cbd5e1">
|
<Button fx:id="btnSalesHistory" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnSalesHistoryClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Sales History" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="btnAppointments" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnAppointmentsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="📅 Appointments" textFill="#cbd5e1">
|
<Button fx:id="btnAppointments" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnAppointmentsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Appointments" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="btnServices" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnServicesClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="✂️ Services" textFill="#cbd5e1">
|
<Button fx:id="btnServices" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnServicesClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Services" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="btnChat" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnChatClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="💬 Chat" textFill="#cbd5e1">
|
<Button fx:id="btnChat" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnChatClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Chat" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -143,7 +143,7 @@
|
|||||||
</padding>
|
</padding>
|
||||||
</Label>
|
</Label>
|
||||||
|
|
||||||
<Button fx:id="btnPets" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnPetsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="🐾 Pets" textFill="#cbd5e1">
|
<Button fx:id="btnPets" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnPetsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Pets" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -151,7 +151,7 @@
|
|||||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="btnAdoptions" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnAdoptionsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="🏠 Adoptions" textFill="#cbd5e1">
|
<Button fx:id="btnAdoptions" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnAdoptionsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Adoptions" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -159,7 +159,7 @@
|
|||||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="btnProducts" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnProductsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="📦 Products" textFill="#cbd5e1">
|
<Button fx:id="btnProducts" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnProductsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Products" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -179,7 +179,7 @@
|
|||||||
</padding>
|
</padding>
|
||||||
</Label>
|
</Label>
|
||||||
|
|
||||||
<Button fx:id="btnInventory" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnInventoryClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="📋 Inventory" textFill="#cbd5e1">
|
<Button fx:id="btnInventory" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnInventoryClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Inventory" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -187,7 +187,7 @@
|
|||||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="btnSuppliers" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnSuppliersClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="🚛 Suppliers" textFill="#cbd5e1">
|
<Button fx:id="btnSuppliers" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnSuppliersClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Suppliers" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -195,7 +195,7 @@
|
|||||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="btnProductSuppliers" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnProductSuppliersClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="🔗 Product-Suppliers" textFill="#cbd5e1">
|
<Button fx:id="btnProductSuppliers" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnProductSuppliersClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Product-Suppliers" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -203,7 +203,7 @@
|
|||||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="btnPurchaseOrders" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnPurchaseOrdersClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="📝 Purchase Orders" textFill="#cbd5e1">
|
<Button fx:id="btnPurchaseOrders" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnPurchaseOrdersClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Purchase Orders" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -211,7 +211,7 @@
|
|||||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="btnStaffAccounts" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnStaffAccountsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="👥 Staff Accounts" textFill="#cbd5e1">
|
<Button fx:id="btnStaffAccounts" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnStaffAccountsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Staff Accounts" textFill="#cbd5e1">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
@@ -220,7 +220,7 @@
|
|||||||
</padding>
|
</padding>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button fx:id="btnLogout" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnLogoutClicked" style="-fx-background-color: rgba(255,255,255,0.08); -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="🚪 Logout" textFill="#e2e8f0">
|
<Button fx:id="btnLogout" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnLogoutClicked" style="-fx-background-color: rgba(255,255,255,0.08); -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Logout" textFill="#e2e8f0">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System" size="12.0" />
|
<Font name="System" size="12.0" />
|
||||||
</font>
|
</font>
|
||||||
|
|||||||
Reference in New Issue
Block a user