Harden assignment rules

This commit is contained in:
2026-04-05 15:51:11 -06:00
parent 5d95613786
commit 1f343f4132
15 changed files with 546 additions and 120 deletions

View File

@@ -74,6 +74,14 @@ public class DropdownApi {
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
}
public List<DropdownOption> getAppointmentCustomers() throws Exception {
String response = apiClient.getRawResponse("/api/v1/dropdowns/appointment-customers");
if (response == null || response.isEmpty()) {
throw new IllegalStateException("Empty response from appointment customers endpoint");
}
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
}
public List<DropdownOption> getPets() throws Exception {
String response = apiClient.getRawResponse("/api/v1/dropdowns/pets");
if (response == null || response.isEmpty()) {
@@ -82,6 +90,14 @@ public class DropdownApi {
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
}
public List<DropdownOption> getAdoptionPets() throws Exception {
String response = apiClient.getRawResponse("/api/v1/dropdowns/adoption-pets");
if (response == null || response.isEmpty()) {
throw new IllegalStateException("Empty response from adoption pets endpoint");
}
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
}
public List<DropdownOption> getCustomerPets(Long customerId) throws Exception {
String response = apiClient.getRawResponse("/api/v1/dropdowns/customers/" + customerId + "/pets");
if (response == null || response.isEmpty()) {

View File

@@ -18,11 +18,13 @@ import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest;
import org.example.petshopdesktop.api.dto.common.DropdownOption;
import org.example.petshopdesktop.api.endpoints.AdoptionApi;
import org.example.petshopdesktop.api.endpoints.DropdownApi;
import org.example.petshopdesktop.auth.UserSession;
import org.example.petshopdesktop.models.Adoption;
import org.example.petshopdesktop.util.ActivityLogger;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
public class AdoptionDialogController {
@@ -56,6 +58,7 @@ public class AdoptionDialogController {
//Stores if the dialog view is in add/edit mode
private String mode = null;
private Adoption selectedAdoption = null;
//Adoption statuses
private ObservableList<String> statusList = FXCollections.observableArrayList(
@@ -70,11 +73,12 @@ public class AdoptionDialogController {
new Thread(() -> {
try {
List<DropdownOption> pets = DropdownApi.getInstance().getPets();
List<DropdownOption> pets = DropdownApi.getInstance().getAdoptionPets();
Platform.runLater(() -> {
if (pets != null) {
ObservableList<DropdownOption> petsObs = FXCollections.observableArrayList(pets);
cbPet.setItems(petsObs);
applySelectedPet();
}
});
} catch (Exception e) {
@@ -90,9 +94,12 @@ public class AdoptionDialogController {
new Thread(() -> {
try {
Long storeId = org.example.petshopdesktop.auth.UserSession.getInstance().getStoreId();
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)));
Platform.runLater(() -> {
cbEmployee.setItems(FXCollections.observableArrayList(employees));
applySelectedEmployee();
});
} catch (Exception e) {
Platform.runLater(() -> {
ActivityLogger.getInstance().logException(
@@ -127,6 +134,7 @@ public class AdoptionDialogController {
if (customers != null) {
ObservableList<DropdownOption> customersObs = FXCollections.observableArrayList(customers);
cbCustomer.setItems(customersObs);
applySelectedCustomer();
}
});
} catch (Exception e) {
@@ -230,30 +238,11 @@ public class AdoptionDialogController {
public void displayAdoptionDetails(Adoption adoption) {
if (adoption != null) {
selectedAdoption = adoption;
lblAdoptionId.setText("ID: " + adoption.getAdoptionId());
for (DropdownOption pet : cbPet.getItems()) {
if (pet.getLabel().equals(adoption.getPetName())) {
cbPet.getSelectionModel().select(pet);
break;
}
}
for (DropdownOption customer : cbCustomer.getItems()) {
if (customer.getLabel().equals(adoption.getCustomerName())) {
cbCustomer.getSelectionModel().select(customer);
break;
}
}
if (adoption.getEmployeeId() > 0) {
for (DropdownOption employee : cbEmployee.getItems()) {
if (employee.getId() != null && employee.getId().equals(adoption.getEmployeeId())) {
cbEmployee.getSelectionModel().select(employee);
break;
}
}
}
applySelectedPet();
applySelectedCustomer();
applySelectedEmployee();
if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) {
try {
@@ -280,4 +269,46 @@ public class AdoptionDialogController {
lblMode.setText(mode + " Adoption");
lblAdoptionId.setVisible(mode.equals("Edit"));
}
private void applySelectedPet() {
if (selectedAdoption == null || selectedAdoption.getPetId() <= 0) {
return;
}
DropdownOption selected = findOptionById(cbPet.getItems(), (long) selectedAdoption.getPetId());
if (selected != null && !Objects.equals(cbPet.getValue(), selected)) {
cbPet.setValue(selected);
}
}
private void applySelectedCustomer() {
if (selectedAdoption == null || selectedAdoption.getCustomerId() <= 0) {
return;
}
DropdownOption selected = findOptionById(cbCustomer.getItems(), (long) selectedAdoption.getCustomerId());
if (selected != null && !Objects.equals(cbCustomer.getValue(), selected)) {
cbCustomer.setValue(selected);
}
}
private void applySelectedEmployee() {
if (selectedAdoption == null || selectedAdoption.getEmployeeId() <= 0) {
return;
}
DropdownOption selected = findOptionById(cbEmployee.getItems(), (long) selectedAdoption.getEmployeeId());
if (selected != null && !Objects.equals(cbEmployee.getValue(), selected)) {
cbEmployee.setValue(selected);
}
}
private DropdownOption findOptionById(List<DropdownOption> options, Long id) {
if (id == null || options == null) {
return null;
}
for (DropdownOption option : options) {
if (option.getId() != null && option.getId().equals(id)) {
return option;
}
}
return null;
}
}

View File

@@ -20,8 +20,9 @@ import org.example.petshopdesktop.util.ActivityLogger;
import java.time.LocalTime;
import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.Collections;
import java.util.Objects;
public class AppointmentDialogController {
@@ -75,49 +76,6 @@ public class AppointmentDialogController {
@FXML
public void initialize() {
new Thread(() -> {
try {
List<DropdownOption> services = DropdownApi.getInstance().getServices();
List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
Platform.runLater(() -> {
if (services != null) {
cbService.setItems(FXCollections.observableArrayList(services));
}
if (customers != null) {
cbCustomer.setItems(FXCollections.observableArrayList(customers));
}
syncSelectedAppointment();
});
} catch (Exception e) {
Platform.runLater(() -> {
ActivityLogger.getInstance().logException(
"AppointmentDialogController.initialize",
e,
"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");
@@ -211,6 +169,10 @@ public class AppointmentDialogController {
btnSave.setOnMouseClicked(this::buttonSaveClicked);
btnCancel.setOnMouseClicked(this::closeStage);
loadServices();
loadAppointmentCustomers();
loadEmployees();
}
//
@@ -221,6 +183,7 @@ public class AppointmentDialogController {
selectedAppointment = appt;
lblAppointmentId.setText("ID: " + appt.getAppointmentId());
pendingPetSelectionId = appt.getPetId() > 0 ? (long) appt.getPetId() : null;
try {
dpAppointmentDate.setValue(
@@ -246,24 +209,9 @@ public class AppointmentDialogController {
"Parsing appointment time");
}
cbService.getItems().forEach(s -> {
if (s.getId() != null && s.getId().longValue() == appt.getServiceId()) cbService.setValue(s);
});
cbCustomer.getItems().forEach(c -> {
if (c.getId() != null && c.getId().longValue() == appt.getCustomerId()) {
pendingPetSelectionId = (long) appt.getPetId();
cbCustomer.setValue(c);
}
});
if (appt.getEmployeeId() > 0) {
cbEmployee.getItems().forEach(employee -> {
if (employee.getId() != null && employee.getId().longValue() == appt.getEmployeeId()) {
cbEmployee.setValue(employee);
}
});
}
applySelectedService();
applySelectedCustomer();
applySelectedEmployee();
}
//
@@ -350,6 +298,49 @@ public class AppointmentDialogController {
}
}
private void applySelectedService() {
if (selectedAppointment == null || selectedAppointment.getServiceId() <= 0) {
return;
}
DropdownOption selected = findOptionById(cbService.getItems(), (long) selectedAppointment.getServiceId());
if (selected != null && !Objects.equals(cbService.getValue(), selected)) {
cbService.setValue(selected);
}
}
private void applySelectedCustomer() {
if (selectedAppointment == null || selectedAppointment.getCustomerId() <= 0) {
return;
}
DropdownOption selected = findOptionById(cbCustomer.getItems(), (long) selectedAppointment.getCustomerId());
if (selected != null && !Objects.equals(cbCustomer.getValue(), selected)) {
cbCustomer.setValue(selected);
}
}
private void applySelectedEmployee() {
if (selectedAppointment == null || selectedAppointment.getEmployeeId() <= 0) {
return;
}
DropdownOption selected = findOptionById(cbEmployee.getItems(), (long) selectedAppointment.getEmployeeId());
if (selected != null && !Objects.equals(cbEmployee.getValue(), selected)) {
cbEmployee.setValue(selected);
}
}
private DropdownOption findOptionById(List<DropdownOption> options, Long id) {
if (id == null || options == null) {
return null;
}
for (DropdownOption option : options) {
if (option.getId() != null && option.getId().equals(id)) {
return option;
}
}
return null;
}
private void loadCustomerPets(Long customerId) {
new Thread(() -> {
try {
@@ -359,22 +350,12 @@ public class AppointmentDialogController {
cbPet.setDisable(pets == null || pets.isEmpty());
cbPet.setPromptText(pets == null || pets.isEmpty() ? "No pets for selected customer" : "Select a pet");
if (pendingPetSelectionId != null) {
boolean matched = false;
for (DropdownOption pet : cbPet.getItems()) {
if (pet.getId() != null && pet.getId().equals(pendingPetSelectionId)) {
cbPet.setValue(pet);
matched = true;
break;
}
}
if (!matched && selectedAppointment != null && selectedAppointment.getPetName() != null && !selectedAppointment.getPetName().isBlank()) {
DropdownOption legacy = new DropdownOption();
legacy.setId(pendingPetSelectionId);
legacy.setLabel(selectedAppointment.getPetName() + " (legacy appointment pet)");
cbPet.getItems().add(0, legacy);
cbPet.setValue(legacy);
cbPet.setDisable(false);
}
pendingPetSelectionId = null;
}
});
@@ -391,4 +372,78 @@ public class AppointmentDialogController {
}
}).start();
}
private void loadServices() {
new Thread(() -> {
try {
List<DropdownOption> services = DropdownApi.getInstance().getServices();
Platform.runLater(() -> {
cbService.setItems(FXCollections.observableArrayList(services));
applySelectedService();
});
} catch (Exception e) {
Platform.runLater(() -> {
ActivityLogger.getInstance().logException(
"AppointmentDialogController.loadServices",
e,
"Loading services for appointment dialog");
cbService.setDisable(true);
cbService.setPromptText("Unable to load services");
});
}
}).start();
}
private void loadAppointmentCustomers() {
new Thread(() -> {
try {
List<DropdownOption> customers = DropdownApi.getInstance().getAppointmentCustomers();
Platform.runLater(() -> {
cbCustomer.setItems(FXCollections.observableArrayList(customers));
boolean hasCustomers = customers != null && !customers.isEmpty();
cbCustomer.setDisable(!hasCustomers);
cbPet.setDisable(true);
cbPet.setItems(FXCollections.observableArrayList());
cbCustomer.setPromptText(hasCustomers ? "Select a customer" : "No customers with pets yet");
cbPet.setPromptText(hasCustomers ? "Select a customer first" : "No customer pets available");
applySelectedCustomer();
});
} catch (Exception e) {
Platform.runLater(() -> {
ActivityLogger.getInstance().logException(
"AppointmentDialogController.loadAppointmentCustomers",
e,
"Loading appointment customers for appointment dialog");
cbCustomer.setDisable(true);
cbPet.setDisable(true);
cbCustomer.setPromptText("Unable to load customers");
cbPet.setPromptText("Unable to load pets");
});
}
}).start();
}
private void loadEmployees() {
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));
applySelectedEmployee();
});
} catch (Exception e) {
Platform.runLater(() -> {
ActivityLogger.getInstance().logException(
"AppointmentDialogController.loadEmployees",
e,
"Loading employees for appointment dialog");
cbEmployee.setDisable(true);
cbEmployee.setPromptText("Unable to load employees");
});
}
}).start();
}
}