diff --git a/src/main/java/org/example/petshopdesktop/DTOs/AppointmentDTO.java b/src/main/java/org/example/petshopdesktop/DTOs/AppointmentDTO.java new file mode 100644 index 00000000..f749b5b5 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/DTOs/AppointmentDTO.java @@ -0,0 +1,59 @@ +package org.example.petshopdesktop.DTOs; + +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleStringProperty; + +public class AppointmentDTO { + + private SimpleIntegerProperty appointmentId; + + private SimpleIntegerProperty customerId; + private SimpleStringProperty customerName; + + private SimpleIntegerProperty petId; + private SimpleStringProperty petName; + + private SimpleIntegerProperty serviceId; + private SimpleStringProperty serviceName; + + private SimpleStringProperty appointmentDate; + private SimpleStringProperty appointmentTime; + private SimpleStringProperty appointmentStatus; + + // Constructor + public AppointmentDTO(int appointmentId, + int customerId, String customerName, + int petId, String petName, + int serviceId, String serviceName, + String appointmentDate, + String appointmentTime, + String appointmentStatus) { + + this.appointmentId = new SimpleIntegerProperty(appointmentId); + this.customerId = new SimpleIntegerProperty(customerId); + this.customerName = new SimpleStringProperty(customerName); + this.petId = new SimpleIntegerProperty(petId); + this.petName = new SimpleStringProperty(petName); + this.serviceId = new SimpleIntegerProperty(serviceId); + this.serviceName = new SimpleStringProperty(serviceName); + this.appointmentDate = new SimpleStringProperty(appointmentDate); + this.appointmentTime = new SimpleStringProperty(appointmentTime); + this.appointmentStatus = new SimpleStringProperty(appointmentStatus); + } + + // Getters + public int getAppointmentId() { return appointmentId.get(); } + + public int getCustomerId() { return customerId.get(); } + public String getCustomerName() { return customerName.get(); } + + public int getPetId() { return petId.get(); } + public String getPetName() { return petName.get(); } + + public int getServiceId() { return serviceId.get(); } + public String getServiceName() { return serviceName.get(); } + + public String getAppointmentDate() { return appointmentDate.get(); } + public String getAppointmentTime() { return appointmentTime.get(); } + public String getAppointmentStatus() { return appointmentStatus.get(); } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/DTOs/PurchaseOrderDTO.java b/src/main/java/org/example/petshopdesktop/DTOs/PurchaseOrderDTO.java new file mode 100644 index 00000000..11c5d330 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/DTOs/PurchaseOrderDTO.java @@ -0,0 +1,25 @@ +package org.example.petshopdesktop.DTOs; + +import javafx.beans.property.*; + +public class PurchaseOrderDTO { + + private IntegerProperty purchaseOrderId; + private StringProperty supplierName; + private StringProperty orderDate; + private StringProperty status; + + public PurchaseOrderDTO(int id, String supplierName, + String orderDate, String status) { + + this.purchaseOrderId = new SimpleIntegerProperty(id); + this.supplierName = new SimpleStringProperty(supplierName); + this.orderDate = new SimpleStringProperty(orderDate); + this.status = new SimpleStringProperty(status); + } + + public int getPurchaseOrderId() { return purchaseOrderId.get(); } + public String getSupplierName() { return supplierName.get(); } + public String getOrderDate() { return orderDate.get(); } + public String getStatus() { return status.get(); } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/DTOs/ServiceDTO.java b/src/main/java/org/example/petshopdesktop/DTOs/ServiceDTO.java new file mode 100644 index 00000000..c876cd3f --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/DTOs/ServiceDTO.java @@ -0,0 +1,110 @@ +package org.example.petshopdesktop.DTOs; + +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleStringProperty; +import org.example.petshopdesktop.models.Service; + +/** + * The class for ServiceDTO, all service data stored here + */ +public class ServiceDTO { + + private SimpleIntegerProperty serviceId; + private SimpleStringProperty serviceName; + private SimpleStringProperty serviceDesc; + private SimpleIntegerProperty serviceDuration; + private SimpleDoubleProperty servicePrice; + + // constructor + public ServiceDTO(int serviceId, + String serviceName, + String serviceDesc, + int serviceDuration, + double servicePrice) { + + this.serviceId = new SimpleIntegerProperty(serviceId); + this.serviceName = new SimpleStringProperty(serviceName); + this.serviceDesc = new SimpleStringProperty(serviceDesc); + this.serviceDuration = new SimpleIntegerProperty(serviceDuration); + this.servicePrice = new SimpleDoubleProperty(servicePrice); + } + + // getters & setters + + public int getServiceId() { + return serviceId.get(); + } + + public SimpleIntegerProperty serviceIdProperty() { + return serviceId; + } + + public void setServiceId(int serviceId) { + this.serviceId.set(serviceId); + } + + public String getServiceName() { + return serviceName.get(); + } + + public SimpleStringProperty serviceNameProperty() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName.set(serviceName); + } + + public String getServiceDesc() { + return serviceDesc.get(); + } + + public SimpleStringProperty serviceDescProperty() { + return serviceDesc; + } + + public void setServiceDesc(String serviceDesc) { + this.serviceDesc.set(serviceDesc); + } + + public int getServiceDuration() { + return serviceDuration.get(); + } + + public SimpleIntegerProperty serviceDurationProperty() { + return serviceDuration; + } + + public void setServiceDuration(int serviceDuration) { + this.serviceDuration.set(serviceDuration); + } + + public double getServicePrice() { + return servicePrice.get(); + } + + public SimpleDoubleProperty servicePriceProperty() { + return servicePrice; + } + + public void setServicePrice(double servicePrice) { + this.servicePrice.set(servicePrice); + } + + /** + * Converts DTO into Service model (for edit/delete) + */ + public Service toService() { + + Service service = new Service( + getServiceId(), + getServiceName(), + getServiceDesc(), + getServiceDuration(), + getServicePrice() + ); + + return service; + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java b/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java index 9eb6dfce..4616abcf 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java @@ -1,63 +1,135 @@ package org.example.petshopdesktop.controllers; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.scene.control.Button; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; -import javafx.scene.control.TextField; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.stage.Modality; +import javafx.stage.Stage; + +import org.example.petshopdesktop.DTOs.AppointmentDTO; +import org.example.petshopdesktop.controllers.dialogcontrollers.AppointmentDialogController; +import org.example.petshopdesktop.database.AppointmentDB; public class AppointmentController { - @FXML - private Button btnAdd; + @FXML private TableView tvAppointments; + + @FXML private TableColumn colAppointmentId; + @FXML private TableColumn colPetName; + @FXML private TableColumn colServiceName; + @FXML private TableColumn colAppointmentDate; + @FXML private TableColumn colAppointmentTime; + @FXML private TableColumn colCustomerName; + @FXML private TableColumn colAppointmentStatus; + + @FXML private Button btnAdd; + @FXML private Button btnEdit; + @FXML private Button btnDelete; + + @FXML private TextField txtSearch; + + private ObservableList data = FXCollections.observableArrayList(); @FXML - private Button btnDelete; + public void initialize(){ - @FXML - private Button btnEdit; + colAppointmentId.setCellValueFactory(new PropertyValueFactory<>("appointmentId")); + colPetName.setCellValueFactory(new PropertyValueFactory<>("petName")); + colServiceName.setCellValueFactory(new PropertyValueFactory<>("serviceName")); + colAppointmentDate.setCellValueFactory(new PropertyValueFactory<>("appointmentDate")); + colAppointmentTime.setCellValueFactory(new PropertyValueFactory<>("appointmentTime")); + colCustomerName.setCellValueFactory(new PropertyValueFactory<>("customerName")); + colAppointmentStatus.setCellValueFactory(new PropertyValueFactory<>("appointmentStatus")); - @FXML - private TableColumn colAppointmentDate; - - @FXML - private TableColumn colAppointmentId; - - @FXML - private TableColumn colAppointmentStatus; - - @FXML - private TableColumn colAppointmentTime; - - @FXML - private TableColumn colCustomerName; - - @FXML - private TableColumn colPetName; - - @FXML - private TableColumn colServiceName; - - @FXML - private TableView tvAppointments; - - @FXML - private TextField txtSearch; - - @FXML - void btnAddClicked(ActionEvent event) { + loadAppointments(); + } + private void loadAppointments(){ + try{ + data = AppointmentDB.getAppointmentDTOs(); + tvAppointments.setItems(data); + }catch(Exception e){ + e.printStackTrace(); + } } @FXML - void btnDeleteClicked(ActionEvent event) { - + void btnAddClicked(ActionEvent event){ + openDialog(null, "Add"); } @FXML - void btnEditClicked(ActionEvent event) { + void btnEditClicked(ActionEvent event){ + AppointmentDTO selected = + tvAppointments.getSelectionModel().getSelectedItem(); + + if(selected == null){ + showAlert("Select Appointment", "Please select appointment to edit."); + return; + } + + openDialog(selected, "Edit"); } + @FXML + void btnDeleteClicked(ActionEvent event){ + + AppointmentDTO selected = + tvAppointments.getSelectionModel().getSelectedItem(); + + if(selected == null) return; + + try{ + AppointmentDB.deleteAppointment(selected.getAppointmentId()); + loadAppointments(); + }catch(Exception e){ + e.printStackTrace(); + } + } + + private void openDialog(AppointmentDTO appt, String mode){ + + try{ + FXMLLoader loader = new FXMLLoader( + getClass().getResource( + "/org/example/petshopdesktop/dialogviews/appointment-dialog-view.fxml" + ) + ); + + Scene scene = new Scene(loader.load()); + + AppointmentDialogController controller = + loader.getController(); + + controller.setMode(mode); + + if(mode.equals("Edit")){ + controller.displayAppointmentDetails(appt); + } + + Stage stage = new Stage(); + stage.initModality(Modality.APPLICATION_MODAL); + stage.setScene(scene); + stage.showAndWait(); + + loadAppointments(); + + }catch(Exception e){ + e.printStackTrace(); + } + } + + private void showAlert(String title, String msg){ + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle(title); + alert.setHeaderText(null); + alert.setContentText(msg); + alert.showAndWait(); + } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java b/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java index a910432e..8198d517 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java @@ -41,6 +41,9 @@ public class MainLayoutController { @FXML private Button btnSalesHistory; + @FXML + private Button btnPurchaseOrders; + @FXML private Button btnServices; @@ -98,6 +101,12 @@ public class MainLayoutController { updateButtons(btnSalesHistory); } + @FXML + void btnPurchaseOrdersClicked() { + loadView("purchase-order-view.fxml"); + updateButtons(btnPurchaseOrders); + } + @FXML void btnServicesClicked(ActionEvent event) { loadView("service-view.fxml"); @@ -108,8 +117,11 @@ public class MainLayoutController { void btnSuppliersClicked(ActionEvent event) { loadView("supplier-view.fxml"); updateButtons(btnSuppliers); + } + + @FXML void btnLogoutClicked(ActionEvent event) { // Logout clears session state before returning to the login view. diff --git a/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java b/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java new file mode 100644 index 00000000..0f0246bd --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java @@ -0,0 +1,54 @@ +package org.example.petshopdesktop.controllers; + +import javafx.fxml.FXML; +import javafx.scene.control.*; +import javafx.scene.control.cell.PropertyValueFactory; +import org.example.petshopdesktop.DTOs.PurchaseOrderDTO; +import org.example.petshopdesktop.database.PurchaseOrderDB; + +public class PurchaseOrderController { + + @FXML private Button btnRefresh; + + @FXML private TableView tvPurchaseOrders; + + @FXML private TableColumn colOrderId; + @FXML private TableColumn colSupplier; + @FXML private TableColumn colOrderDate; + @FXML private TableColumn colStatus; + + @FXML + public void initialize() { + + colOrderId.setCellValueFactory( + new PropertyValueFactory<>("purchaseOrderId")); + + colSupplier.setCellValueFactory( + new PropertyValueFactory<>("supplierName")); + + colOrderDate.setCellValueFactory( + new PropertyValueFactory<>("orderDate")); + + colStatus.setCellValueFactory( + new PropertyValueFactory<>("status")); + + loadPurchaseOrders(); + } + + private void loadPurchaseOrders() { + try { + tvPurchaseOrders.setItems( + PurchaseOrderDB.getPurchaseOrders() + ); + } catch (Exception e) { + e.printStackTrace(); + new Alert(Alert.AlertType.ERROR, + "Unable to load purchase orders").showAndWait(); + } + } + + @FXML + void btnRefresh() { + loadPurchaseOrders(); + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java b/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java index 65f73c7d..c227fbbc 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java @@ -2,56 +2,123 @@ package org.example.petshopdesktop.controllers; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.scene.control.Button; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; -import javafx.scene.control.TextField; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.input.MouseEvent; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.stage.Stage; +import org.example.petshopdesktop.database.ServiceDB; +import org.example.petshopdesktop.models.Service; +import org.example.petshopdesktop.controllers.dialogcontrollers.ServiceDialogController; +import javafx.stage.Modality; + public class ServiceController { - @FXML - private Button btnAdd; + @FXML private Button btnAdd; + @FXML private Button btnDelete; + @FXML private Button btnEdit; + + @FXML private TableColumn colServiceId; + @FXML private TableColumn colServiceName; + @FXML private TableColumn colServiceDesc; + @FXML private TableColumn colServiceDuration; + @FXML private TableColumn colServicePrice; + + @FXML private TableView tvServices; + + @FXML private TextField txtSearch; @FXML - private Button btnDelete; + public void initialize() { - @FXML - private Button btnEdit; + colServiceId.setCellValueFactory(new PropertyValueFactory<>("serviceId")); + colServiceName.setCellValueFactory(new PropertyValueFactory<>("serviceName")); + colServiceDesc.setCellValueFactory(new PropertyValueFactory<>("serviceDesc")); + colServiceDuration.setCellValueFactory(new PropertyValueFactory<>("serviceDuration")); + colServicePrice.setCellValueFactory(new PropertyValueFactory<>("servicePrice")); - @FXML - private TableColumn colServiceDesc; + loadServices(); + } - @FXML - private TableColumn colServiceDuration; + private void loadServices() { + try { + tvServices.setItems(ServiceDB.getServices()); + } catch (Exception e) { + showAlert("Database Error", "Unable to load services."); + e.printStackTrace(); + } + } - @FXML - private TableColumn colServiceId; - - @FXML - private TableColumn colServiceName; - - @FXML - private TableColumn colServicePrice; - - @FXML - private TableView tvServices; - - @FXML - private TextField txtSearch; @FXML void btnAddClicked(ActionEvent event) { - - } - - @FXML - void btnDeleteClicked(ActionEvent event) { - + openDialog(null, "Add"); + loadServices(); } @FXML void btnEditClicked(ActionEvent event) { + Service selected = tvServices.getSelectionModel().getSelectedItem(); + + if (selected == null) { + showAlert("Select Service", "Please select a service to edit."); + return; + } + + openDialog(selected, "Edit"); + loadServices(); } -} + @FXML + void btnDeleteClicked(ActionEvent e) { + + Service service = tvServices.getSelectionModel().getSelectedItem(); + if (service == null) return; + + try { + ServiceDB.deleteService(service.getServiceId()); + loadServices(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + private void openDialog(Service service, String mode) { + + try { + FXMLLoader loader = new FXMLLoader( + getClass().getResource("/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml") + ); + + Stage stage = new Stage(); + stage.setScene(new Scene(loader.load())); + + ServiceDialogController controller = loader.getController(); + controller.setMode(mode); + + if (mode.equals("Edit")) { + controller.setService(service); + } + + stage.initModality(Modality.APPLICATION_MODAL); + stage.showAndWait(); + + loadServices(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + private void showAlert(String title, String msg) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle(title); + alert.setHeaderText(null); + alert.setContentText(msg); + alert.showAndWait(); + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java new file mode 100644 index 00000000..61fa04e8 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java @@ -0,0 +1,209 @@ +package org.example.petshopdesktop.controllers.dialogcontrollers; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.input.MouseEvent; +import javafx.stage.Stage; +import javafx.scene.control.ListCell; + +import org.example.petshopdesktop.DTOs.AppointmentDTO; +import org.example.petshopdesktop.database.*; +import org.example.petshopdesktop.models.*; + +import java.sql.Time; + +public class AppointmentDialogController { + + // ============================ + // FXML + // ============================ + + @FXML private Button btnCancel; + @FXML private Button btnSave; + + @FXML private ComboBox cbService; + @FXML private ComboBox cbCustomer; + @FXML private ComboBox cbPet; + + @FXML private ComboBox cbHour; + @FXML private ComboBox cbMinute; + + @FXML private ComboBox cbAppointmentStatus; + @FXML private DatePicker dpAppointmentDate; + + @FXML private Label lblAppointmentId; + @FXML private Label lblMode; + + // ============================ + // DATA + // ============================ + + private String mode = null; // Add | Edit + private AppointmentDTO selectedAppointment = null; + + private ObservableList statusList = + FXCollections.observableArrayList( + "Booked", "Completed", "Cancelled" + ); + + // + // MODE + // + + public void setMode(String mode) { + this.mode = mode; + lblMode.setText(mode + " Appointment"); + lblAppointmentId.setVisible(!mode.equals("Add")); + } + + // + // INITIALIZE + // + + @FXML + public void initialize() { + + try { + cbService.setItems(ServiceDB.getServices()); + cbCustomer.setItems(CustomerDB.getCustomers()); + cbPet.setItems(PetDB.getPets()); + } catch (Exception e) { + e.printStackTrace(); + } + + cbAppointmentStatus.setItems(statusList); + + // Hours 9 AM - 5 PM + for (int i = 9; i <= 17; i++) { + cbHour.getItems().add(i); + } + + cbMinute.getItems().addAll(0, 15, 30, 45); + + // Show pet name + cbPet.setCellFactory(param -> new ListCell<>() { + @Override + protected void updateItem(Pet pet, boolean empty) { + super.updateItem(pet, empty); + setText(empty || pet == null ? null : pet.getPetName()); + } + }); + + cbPet.setButtonCell(new ListCell<>() { + @Override + protected void updateItem(Pet pet, boolean empty) { + super.updateItem(pet, empty); + setText(empty || pet == null ? null : pet.getPetName()); + } + }); + + btnSave.setOnMouseClicked(this::buttonSaveClicked); + btnCancel.setOnMouseClicked(this::closeStage); + } + + // + // DISPLAY FOR EDIT + // + + public void displayAppointmentDetails(AppointmentDTO appt) { + + selectedAppointment = appt; + lblAppointmentId.setText("ID: " + appt.getAppointmentId()); + + dpAppointmentDate.setValue( + java.time.LocalDate.parse(appt.getAppointmentDate()) + ); + + cbAppointmentStatus.setValue(appt.getAppointmentStatus()); + + Time time = Time.valueOf(appt.getAppointmentTime()); + cbHour.setValue(time.toLocalTime().getHour()); + cbMinute.setValue(time.toLocalTime().getMinute()); + + cbService.getItems().forEach(s -> { + if (s.getServiceId() == appt.getServiceId()) cbService.setValue(s); + }); + + cbCustomer.getItems().forEach(c -> { + if (c.getCustomerId() == appt.getCustomerId()) cbCustomer.setValue(c); + }); + + cbPet.getItems().forEach(p -> { + if (p.getPetId() == appt.getPetId()) cbPet.setValue(p); + }); + } + + // + // SAVE + // + + private void buttonSaveClicked(MouseEvent e) { + + if (cbService.getValue() == null || + cbCustomer.getValue() == null || + cbPet.getValue() == null || + dpAppointmentDate.getValue() == null || + cbHour.getValue() == null || + cbMinute.getValue() == null || + cbAppointmentStatus.getValue() == null) { + + showError("All fields are required"); + return; + } + + Time appointmentTime = + Time.valueOf(String.format( + "%02d:%02d:00", + cbHour.getValue(), + cbMinute.getValue() + )); + + Appointment appt = new Appointment( + selectedAppointment == null ? 0 : selectedAppointment.getAppointmentId(), + cbService.getValue().getServiceId(), + cbCustomer.getValue().getCustomerId(), + dpAppointmentDate.getValue().toString(), + appointmentTime.toString(), + cbAppointmentStatus.getValue() + ); + + try { + + if (mode.equals("Add")) { + int newId = AppointmentDB.insertAppointment(appt); + AppointmentDB.insertAppointmentPet(newId, cbPet.getValue().getPetId()); + } else { + AppointmentDB.updateAppointment( + selectedAppointment.getAppointmentId(), + appt, + cbPet.getValue().getPetId() + ); + } + + closeStage(e); + + } catch (Exception ex) { + ex.printStackTrace(); + showError("Error saving appointment"); + } + } + + // + // UTIL + // + + private void closeStage(MouseEvent e) { + Stage stage = (Stage) ((Node) e.getSource()).getScene().getWindow(); + stage.close(); + } + + private void showError(String msg) { + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Input Error"); + alert.setContentText(msg); + alert.showAndWait(); + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java new file mode 100644 index 00000000..4d878324 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java @@ -0,0 +1,153 @@ +package org.example.petshopdesktop.controllers.dialogcontrollers; + + +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.input.MouseEvent; +import javafx.stage.Stage; +import org.example.petshopdesktop.database.ServiceDB; +import org.example.petshopdesktop.models.Service; +import javafx.scene.control.Alert; +import javafx.scene.control.ComboBox; + + +public class ServiceDialogController { + + @FXML + private Button btnCancel; + + @FXML + private Button btnSave; + + @FXML + private Label lblMode; + + @FXML + private Label lblServiceId; + + @FXML + private TextField txtServiceDesc; + + @FXML + private TextField txtServiceName; + + @FXML + private TextField txtServicePrice; + + @FXML + private ComboBox cbHours; + + @FXML + private ComboBox cbMinutes; + + private String mode; + private Service selectedService; + + + + @FXML + public void initialize() { + cbHours.getItems().addAll(0, 1, 2, 3, 4); + cbMinutes.getItems().addAll(0, 15, 30, 45); + btnSave.setOnAction(e -> saveService()); + btnCancel.setOnAction(e -> close()); + } + + public void setMode(String mode) { + this.mode = mode; + lblMode.setText(mode + " Service"); + + if (mode.equals("Add")) { + lblServiceId.setVisible(false); + } else { + lblServiceId.setVisible(true); + } + } + + public void setService(Service service) { + this.selectedService = service; + + lblServiceId.setText("ID: " + service.getServiceId()); + txtServiceName.setText(service.getServiceName()); + txtServiceDesc.setText(service.getServiceDesc()); + int totalMinutes = service.getServiceDuration(); + cbHours.setValue(totalMinutes / 60); + cbMinutes.setValue(totalMinutes % 60); + txtServicePrice.setText(String.valueOf(service.getServicePrice())); + } + + private void saveService() { + + String name = txtServiceName.getText(); + String desc = txtServiceDesc.getText(); + String priceText = txtServicePrice.getText(); + + Integer hours = cbHours.getValue(); + Integer minutes = cbMinutes.getValue(); + + // -------- VALIDATION -------- + if (name == null || name.isBlank()) { + showError("Service name is required."); + return; + } + + if (priceText == null || priceText.isBlank()) { + showError("Price is required."); + return; + } + + if (hours == null || minutes == null) { + showError("Please select duration."); + return; + } + + double price; + + try { + price = Double.parseDouble(priceText); + } catch (NumberFormatException e) { + showError("Price must be numeric."); + return; + } + + int duration = (hours * 60) + minutes; + + Service service = new Service( + selectedService == null ? 0 : selectedService.getServiceId(), + name, + desc, + duration, + price + ); + + try { + + if (mode.equals("Add")) { + ServiceDB.insertService(service); + } else { + ServiceDB.updateService(selectedService.getServiceId(), service); + } + + close(); + + } catch (Exception e) { + e.printStackTrace(); + showError("Database error while saving service."); + } + } + + private void showError(String msg) { + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Invalid Input"); + alert.setContentText(msg); + alert.showAndWait(); + } + + private void close() { + Stage stage = (Stage) btnSave.getScene().getWindow(); + stage.close(); + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/database/AppointmentDB.java b/src/main/java/org/example/petshopdesktop/database/AppointmentDB.java new file mode 100644 index 00000000..773957ed --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/database/AppointmentDB.java @@ -0,0 +1,193 @@ +package org.example.petshopdesktop.database; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import org.example.petshopdesktop.DTOs.AppointmentDTO; +import org.example.petshopdesktop.models.Appointment; + +import java.sql.*; + +public class AppointmentDB { + + // ============================ + // GET ALL APPOINTMENTS + // ============================ + public static ObservableList getAppointmentDTOs() + throws SQLException { + + ObservableList list = + FXCollections.observableArrayList(); + + Connection conn = ConnectionDB.getConnection(); + + String sql = """ + SELECT a.appointmentId, + c.customerId, + CONCAT(c.firstName,' ',c.lastName) AS customerName, + p.petId, + p.petName, + s.serviceId, + s.serviceName, + a.appointmentDate, + a.appointmentTime, + a.appointmentStatus + FROM appointment a + JOIN customer c ON a.customerId = c.customerId + JOIN appointmentPet ap ON a.appointmentId = ap.appointmentId + JOIN pet p ON ap.petId = p.petId + JOIN service s ON a.serviceId = s.serviceId + """; + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql); + + while (rs.next()) { + + AppointmentDTO dto = new AppointmentDTO( + rs.getInt("appointmentId"), + + rs.getInt("customerId"), + rs.getString("customerName"), + + rs.getInt("petId"), + rs.getString("petName"), + + rs.getInt("serviceId"), + rs.getString("serviceName"), + + rs.getString("appointmentDate"), + rs.getString("appointmentTime"), + rs.getString("appointmentStatus") + ); + + list.add(dto); + } + + conn.close(); + return list; + } + + // ============================ + // INSERT APPOINTMENT + // ============================ + public static int insertAppointment(Appointment appt) + throws SQLException { + + Connection conn = ConnectionDB.getConnection(); + + String sql = """ + INSERT INTO appointment + (serviceId, customerId, appointmentDate, + appointmentTime, appointmentStatus) + VALUES (?,?,?,?,?) + """; + + PreparedStatement ps = + conn.prepareStatement(sql, + Statement.RETURN_GENERATED_KEYS); + + ps.setInt(1, appt.getServiceId()); + ps.setInt(2, appt.getCustomerId()); + ps.setString(3, appt.getAppointmentDate()); + ps.setString(4, appt.getAppointmentTime()); + ps.setString(5, appt.getAppointmentStatus()); + + ps.executeUpdate(); + + ResultSet keys = ps.getGeneratedKeys(); + int newId = 0; + + if (keys.next()) { + newId = keys.getInt(1); + } + + conn.close(); + return newId; + } + + // + // LINK PET TO APPOINTMENT + // + public static void insertAppointmentPet(int appointmentId, + int petId) + throws SQLException { + + Connection conn = ConnectionDB.getConnection(); + + String sql = + "INSERT INTO appointmentPet (appointmentId, petId) VALUES (?,?)"; + + PreparedStatement ps = conn.prepareStatement(sql); + ps.setInt(1, appointmentId); + ps.setInt(2, petId); + ps.executeUpdate(); + + conn.close(); + } + + // + // UPDATE APPOINTMENT + // + public static int updateAppointment(int id, + Appointment appt, + int petId) + throws SQLException { + + Connection conn = ConnectionDB.getConnection(); + + String sql = + "UPDATE appointment SET serviceId=?, customerId=?, " + + "appointmentDate=?, appointmentTime=?, appointmentStatus=? " + + "WHERE appointmentId=?"; + + PreparedStatement ps = conn.prepareStatement(sql); + + ps.setInt(1, appt.getServiceId()); + ps.setInt(2, appt.getCustomerId()); + ps.setString(3, appt.getAppointmentDate()); + ps.setString(4, appt.getAppointmentTime()); + ps.setString(5, appt.getAppointmentStatus()); + ps.setInt(6, id); + + ps.executeUpdate(); + + String sql2 = + "UPDATE appointmentPet SET petId=? WHERE appointmentId=?"; + + PreparedStatement ps2 = conn.prepareStatement(sql2); + ps2.setInt(1, petId); + ps2.setInt(2, id); + ps2.executeUpdate(); + + conn.close(); + return 1; + } + + // + // DELETE APPOINTMENT + // + public static int deleteAppointment(int id) + throws SQLException { + + Connection conn = ConnectionDB.getConnection(); + + PreparedStatement ps1 = + conn.prepareStatement( + "DELETE FROM appointmentPet WHERE appointmentId=?" + ); + ps1.setInt(1, id); + ps1.executeUpdate(); + + PreparedStatement ps2 = + conn.prepareStatement( + "DELETE FROM appointment WHERE appointmentId=?" + ); + ps2.setInt(1, id); + + int rows = ps2.executeUpdate(); + + conn.close(); + return rows; + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/database/CustomerDB.java b/src/main/java/org/example/petshopdesktop/database/CustomerDB.java new file mode 100644 index 00000000..abe47004 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/database/CustomerDB.java @@ -0,0 +1,43 @@ +package org.example.petshopdesktop.database; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import org.example.petshopdesktop.models.Customer; + +import java.sql.*; + +public class CustomerDB { + + // + // GET ALL CUSTOMERS + // + public static ObservableList getCustomers() + throws SQLException { + + ObservableList list = + FXCollections.observableArrayList(); + + Connection conn = ConnectionDB.getConnection(); + + String sql = "SELECT * FROM customer"; + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql); + + while(rs.next()) { + + Customer c = new Customer( + rs.getInt("customerId"), + rs.getString("firstName"), + rs.getString("lastName"), + rs.getString("email"), + rs.getString("phone") + ); + + list.add(c); + } + + conn.close(); + return list; + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/database/PurchaseOrderDB.java b/src/main/java/org/example/petshopdesktop/database/PurchaseOrderDB.java new file mode 100644 index 00000000..2dea4de4 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/database/PurchaseOrderDB.java @@ -0,0 +1,45 @@ +package org.example.petshopdesktop.database; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import org.example.petshopdesktop.DTOs.PurchaseOrderDTO; + +import java.sql.*; + +public class PurchaseOrderDB { + + public static ObservableList getPurchaseOrders() + throws SQLException { + + ObservableList list = + FXCollections.observableArrayList(); + + Connection conn = ConnectionDB.getConnection(); + + String sql = """ + SELECT po.purchaseOrderId, + s.supCompany, + po.orderDate, + po.status + FROM purchaseOrder po + JOIN supplier s ON po.supId = s.supId + ORDER BY po.purchaseOrderId + """; + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql); + + while (rs.next()) { + + list.add(new PurchaseOrderDTO( + rs.getInt("purchaseOrderId"), + rs.getString("supCompany"), + rs.getString("orderDate"), + rs.getString("status") + )); + } + + conn.close(); + return list; + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/database/ServiceDB.java b/src/main/java/org/example/petshopdesktop/database/ServiceDB.java new file mode 100644 index 00000000..c5ca9ff7 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/database/ServiceDB.java @@ -0,0 +1,107 @@ +package org.example.petshopdesktop.database; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import org.example.petshopdesktop.models.Service; + +import java.sql.*; + +public class ServiceDB { + + // + // GET ALL SERVICES + // + public static ObservableList getServices() throws SQLException { + + ObservableList list = FXCollections.observableArrayList(); + Connection conn = ConnectionDB.getConnection(); + + String sql = "SELECT * FROM service"; + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql); + + while (rs.next()) { + + Service service = new Service( + rs.getInt("serviceId"), + rs.getString("serviceName"), + rs.getString("serviceDesc"), + rs.getInt("serviceDuration"), + rs.getDouble("servicePrice") + ); + + list.add(service); + } + + conn.close(); + return list; + } + + // + // INSERT SERVICE + // + public static int insertService(Service service) throws SQLException { + + Connection conn = ConnectionDB.getConnection(); + + String sql = + "INSERT INTO service (serviceName, serviceDesc, serviceDuration, servicePrice) " + + "VALUES (?, ?, ?, ?)"; + + PreparedStatement stmt = conn.prepareStatement(sql); + + stmt.setString(1, service.getServiceName()); + stmt.setString(2, service.getServiceDesc()); + stmt.setInt(3, service.getServiceDuration()); + stmt.setDouble(4, service.getServicePrice()); + + int rows = stmt.executeUpdate(); + conn.close(); + + return rows; + } + + // + // UPDATE SERVICE + // + public static int updateService(int id, Service service) throws SQLException { + + Connection conn = ConnectionDB.getConnection(); + + String sql = + "UPDATE service SET " + + "serviceName=?, serviceDesc=?, serviceDuration=?, servicePrice=? " + + "WHERE serviceId=?"; + + PreparedStatement stmt = conn.prepareStatement(sql); + + stmt.setString(1, service.getServiceName()); + stmt.setString(2, service.getServiceDesc()); + stmt.setInt(3, service.getServiceDuration()); + stmt.setDouble(4, service.getServicePrice()); + stmt.setInt(5, id); + + int rows = stmt.executeUpdate(); + conn.close(); + + return rows; + } + + // + // DELETE SERVICE + // + public static int deleteService(int id) throws SQLException { + + Connection conn = ConnectionDB.getConnection(); + + String sql = "DELETE FROM service WHERE serviceId=?"; + + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setInt(1, id); + + int rows = stmt.executeUpdate(); + conn.close(); + + return rows; + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/models/Appointment.java b/src/main/java/org/example/petshopdesktop/models/Appointment.java new file mode 100644 index 00000000..7ab54292 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/models/Appointment.java @@ -0,0 +1,46 @@ +package org.example.petshopdesktop.models; + +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleStringProperty; + +public class Appointment { + + private SimpleIntegerProperty appointmentId; + private SimpleIntegerProperty serviceId; + private SimpleIntegerProperty customerId; + private SimpleStringProperty appointmentDate; + private SimpleStringProperty appointmentTime; + private SimpleStringProperty appointmentStatus; + + // Constructor + public Appointment(int appointmentId, + int serviceId, + int customerId, + String appointmentDate, + String appointmentTime, + String appointmentStatus) { + + this.appointmentId = new SimpleIntegerProperty(appointmentId); + this.serviceId = new SimpleIntegerProperty(serviceId); + this.customerId = new SimpleIntegerProperty(customerId); + this.appointmentDate = new SimpleStringProperty(appointmentDate); + this.appointmentTime = new SimpleStringProperty(appointmentTime); + this.appointmentStatus = new SimpleStringProperty(appointmentStatus); + } + + // Getters + public int getAppointmentId() { return appointmentId.get(); } + public int getServiceId() { return serviceId.get(); } + public int getCustomerId() { return customerId.get(); } + public String getAppointmentDate() { return appointmentDate.get(); } + public String getAppointmentTime() { return appointmentTime.get(); } + public String getAppointmentStatus() { return appointmentStatus.get(); } + + // Properties + public SimpleIntegerProperty appointmentIdProperty() { return appointmentId; } + public SimpleIntegerProperty serviceIdProperty() { return serviceId; } + public SimpleIntegerProperty customerIdProperty() { return customerId; } + public SimpleStringProperty appointmentDateProperty() { return appointmentDate; } + public SimpleStringProperty appointmentTimeProperty() { return appointmentTime; } + public SimpleStringProperty appointmentStatusProperty() { return appointmentStatus; } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/models/Customer.java b/src/main/java/org/example/petshopdesktop/models/Customer.java new file mode 100644 index 00000000..657bcfd9 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/models/Customer.java @@ -0,0 +1,75 @@ +package org.example.petshopdesktop.models; + +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleStringProperty; + +public class Customer { + + private SimpleIntegerProperty customerId; + private SimpleStringProperty firstName; + private SimpleStringProperty lastName; + private SimpleStringProperty email; + private SimpleStringProperty phone; + + // Constructor + public Customer(int customerId, + String firstName, + String lastName, + String email, + String phone) { + + this.customerId = new SimpleIntegerProperty(customerId); + this.firstName = new SimpleStringProperty(firstName); + this.lastName = new SimpleStringProperty(lastName); + this.email = new SimpleStringProperty(email); + this.phone = new SimpleStringProperty(phone); + } + + // Getters + public int getCustomerId() { + return customerId.get(); + } + + public String getFirstName() { + return firstName.get(); + } + + public String getLastName() { + return lastName.get(); + } + + public String getEmail() { + return email.get(); + } + + public String getPhone() { + return phone.get(); + } + + // Properties (optional but useful later) + public SimpleIntegerProperty customerIdProperty() { + return customerId; + } + + public SimpleStringProperty firstNameProperty() { + return firstName; + } + + public SimpleStringProperty lastNameProperty() { + return lastName; + } + + public SimpleStringProperty emailProperty() { + return email; + } + + public SimpleStringProperty phoneProperty() { + return phone; + } + + // This controls how customer appears in ComboBox + @Override + public String toString() { + return getFirstName() + " " + getLastName(); + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/models/PurchaseOrder.java b/src/main/java/org/example/petshopdesktop/models/PurchaseOrder.java new file mode 100644 index 00000000..3b1cf838 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/models/PurchaseOrder.java @@ -0,0 +1,35 @@ +package org.example.petshopdesktop.models; + +public class PurchaseOrder { + + private int purchaseOrderId; + private int supId; + private String orderDate; + private String status; + + public PurchaseOrder(int purchaseOrderId, + int supId, + String orderDate, + String status) { + this.purchaseOrderId = purchaseOrderId; + this.supId = supId; + this.orderDate = orderDate; + this.status = status; + } + + public int getPurchaseOrderId() { + return purchaseOrderId; + } + + public int getSupId() { + return supId; + } + + public String getOrderDate() { + return orderDate; + } + + public String getStatus() { + return status; + } +} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/models/Service.java b/src/main/java/org/example/petshopdesktop/models/Service.java new file mode 100644 index 00000000..b259fc21 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/models/Service.java @@ -0,0 +1,98 @@ +package org.example.petshopdesktop.models; + +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleStringProperty; + +/** + * The class for the entity of services (contains all data relating to services) + */ +public class Service { + + private SimpleIntegerProperty serviceId; + private SimpleStringProperty serviceName; + private SimpleStringProperty serviceDesc; + private SimpleIntegerProperty serviceDuration; + private SimpleDoubleProperty servicePrice; + + // constructor + public Service(int serviceId, + String serviceName, + String serviceDesc, + int serviceDuration, + double servicePrice) { + + this.serviceId = new SimpleIntegerProperty(serviceId); + this.serviceName = new SimpleStringProperty(serviceName); + this.serviceDesc = new SimpleStringProperty(serviceDesc); + this.serviceDuration = new SimpleIntegerProperty(serviceDuration); + this.servicePrice = new SimpleDoubleProperty(servicePrice); + } + + // getters & setters + + public int getServiceId() { + return serviceId.get(); + } + + public SimpleIntegerProperty serviceIdProperty() { + return serviceId; + } + + public void setServiceId(int serviceId) { + this.serviceId.set(serviceId); + } + + public String getServiceName() { + return serviceName.get(); + } + + public SimpleStringProperty serviceNameProperty() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName.set(serviceName); + } + + public String getServiceDesc() { + return serviceDesc.get(); + } + + public SimpleStringProperty serviceDescProperty() { + return serviceDesc; + } + + public void setServiceDesc(String serviceDesc) { + this.serviceDesc.set(serviceDesc); + } + + public int getServiceDuration() { + return serviceDuration.get(); + } + + public SimpleIntegerProperty serviceDurationProperty() { + return serviceDuration; + } + + public void setServiceDuration(int serviceDuration) { + this.serviceDuration.set(serviceDuration); + } + + public double getServicePrice() { + return servicePrice.get(); + } + + public SimpleDoubleProperty servicePriceProperty() { + return servicePrice; + } + + public void setServicePrice(double servicePrice) { + this.servicePrice.set(servicePrice); + } + + @Override + public String toString() { + return getServiceName(); + } +} \ No newline at end of file diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/appointment-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/appointment-dialog-view.fxml new file mode 100644 index 00000000..b12bc777 --- /dev/null +++ b/src/main/resources/org/example/petshopdesktop/dialogviews/appointment-dialog-view.fxml @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml new file mode 100644 index 00000000..327ce2d0 --- /dev/null +++ b/src/main/resources/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/example/petshopdesktop/main-layout-view.fxml b/src/main/resources/org/example/petshopdesktop/main-layout-view.fxml index 983d07a9..a1471b98 100644 --- a/src/main/resources/org/example/petshopdesktop/main-layout-view.fxml +++ b/src/main/resources/org/example/petshopdesktop/main-layout-view.fxml @@ -106,6 +106,21 @@ + +