From 310b66329f3184eb66f87056f9ad748736a1b097 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 1 Feb 2026 18:43:35 -0700 Subject: [PATCH] Added CRUD to Suppliers --- src/main/java/module-info.java | 4 +- .../controllers/ProductController.java | 3 + .../controllers/SupplierController.java | 134 +++++++++++++- .../SupplierDialogController.java | 173 ++++++++++++++++++ .../petshopdesktop/database/SupplierDB.java | 91 ++++++++- .../dialogviews/supplier-dialog-view.fxml | 161 ++++++++++++++++ 6 files changed, 556 insertions(+), 10 deletions(-) create mode 100644 src/main/resources/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 0c7ee955..7459e876 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -6,7 +6,9 @@ module org.example.petshopdesktop { opens org.example.petshopdesktop.DTOs to javafx.base; opens org.example.petshopdesktop.models to javafx.base; opens org.example.petshopdesktop to javafx.fxml; + opens org.example.petshopdesktop.controllers.dialogcontrollers to javafx.fxml; + opens org.example.petshopdesktop.controllers to javafx.fxml; + exports org.example.petshopdesktop; exports org.example.petshopdesktop.controllers; - opens org.example.petshopdesktop.controllers to javafx.fxml; } \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java index c79110fd..d8811cc0 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java @@ -62,6 +62,9 @@ public class ProductController { */ @FXML void initialize() { + //Disable buttons until a row is selected + btnEdit.setDisable(true); + btnDelete.setDisable(true); //set up table columns colProductId.setCellValueFactory(new PropertyValueFactory("prodId")); colProductName.setCellValueFactory(new PropertyValueFactory("prodName")); diff --git a/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java b/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java index 6ac02698..c64eff6c 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java @@ -4,15 +4,20 @@ 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.controllers.dialogcontrollers.SupplierDialogController; import org.example.petshopdesktop.database.SupplierDB; import org.example.petshopdesktop.models.Supplier; +import java.io.IOException; import java.sql.SQLException; +import java.sql.SQLIntegrityConstraintViolationException; +import java.util.Optional; /** * The controller for any operations in the supplier view @@ -50,12 +55,17 @@ public class SupplierController { private TextField txtSearch; private ObservableList data = FXCollections.observableArrayList(); + private String mode = null; /** * Set up the table view for suppliers and display it when starting up */ @FXML void initialize(){ + //Disable buttons until a row is selected + btnEdit.setDisable(true); + btnDelete.setDisable(true); + //set columns for table view colSupplierId.setCellValueFactory(new PropertyValueFactory("supId")); colSupplierName.setCellValueFactory(new PropertyValueFactory("supCompany")); colContactPerson.setCellValueFactory(new PropertyValueFactory("supFullName")); @@ -64,6 +74,15 @@ public class SupplierController { displaySupplier(); + // Enable buttons when a row is selected + tvSuppliers.getSelectionModel().selectedItemProperty().addListener( + (observable, oldValue, newValue) -> { + btnEdit.setDisable(false); + btnDelete.setDisable(false); + } + ); + + } /** @@ -82,19 +101,124 @@ public class SupplierController { } + /** + * open a new dialog for adding a supplier + * @param event + */ @FXML void btnAddClicked(ActionEvent event) { - + mode = "Add"; + openDialog(null,mode); } + /** + * + * @param event + */ @FXML void btnDeleteClicked(ActionEvent event) { + int numRows = 0; + //set selected supplier + Supplier selectedSupplier = tvSuppliers.getSelectionModel().getSelectedItem(); + //ask user to confirm + Alert question = new Alert(Alert.AlertType.CONFIRMATION); + question.setHeaderText("Please confirm delete"); + question.setContentText("Are you sure you want to delete this supplier?"); + Optional result = question.showAndWait(); //show alert and wait for response + + //if confirmed, start deletion + if (result.isPresent() && result.get() == ButtonType.OK){ + int supId = selectedSupplier.getSupId(); + + //Try deleting supplier + try{ + numRows = SupplierDB.deleteSupplier(supId); + } + catch (SQLIntegrityConstraintViolationException e){ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText("Delete failed\n" + + "the selected supplier is being referred in another table"); + alert.showAndWait(); + return; + } + catch (SQLException e) { + throw new RuntimeException(e); + } + + //prompt user of any errors + if (numRows == 0){ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText("Delete failed"); + alert.showAndWait(); + } + else{ + //prompt user of delete conformation + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setHeaderText("Database Operation Confirmed"); + alert.setContentText("Delete successful"); + alert.showAndWait(); + //refresh display + displaySupplier(); + } + } } + /** + * Open a new dialog for editing a supplier + * @param event click event + */ @FXML void btnEditClicked(ActionEvent event) { + //set selected supplier + Supplier selectedSupplier = tvSuppliers.getSelectionModel().getSelectedItem(); + if (selectedSupplier != null) { + mode = "Edit"; + openDialog(selectedSupplier, mode); + } + } + + /** + * Function to open the new Dialog for edit or adding + * depending on the mode given + * @param supplier the supplier entity fo editing, null if adding + * @param mode the mode the dialog should be in + */ + private void openDialog(Supplier supplier, String mode){ + //Get new view + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml")); //CHECK + Scene scene = null; + try{ + scene = new Scene(fxmlLoader.load()); + } catch (IOException e) { + throw new RuntimeException(e); + } + SupplierDialogController dialogController = fxmlLoader.getController(); //controller associated with this view + dialogController.setMode(mode); + + //Open the dialog depending on the mode + if(mode.equals("Edit")){ + //Make it display suppliers details in dialog + dialogController.displaySupplierDetails(supplier); + } + Stage dialogStage = new Stage(); + dialogStage.initModality(Modality.APPLICATION_MODAL); //make it modal + if(mode.equals("Add")){ + dialogStage.setTitle("Add Supplier"); + } + else { + dialogStage.setTitle("Edit Supplier"); + } + dialogStage.setScene(scene); + dialogStage.showAndWait(); + + //When dialog closes update table view and disable edit and delete buttons + displaySupplier(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java index de8c1f6d..fe6e06c2 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java @@ -1,5 +1,178 @@ package org.example.petshopdesktop.controllers.dialogcontrollers; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Alert; +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.SupplierDB; +import org.example.petshopdesktop.models.Supplier; + +import java.sql.SQLException; + public class SupplierDialogController { + @FXML + private Button btnCancel; + + @FXML + private Button btnSave; + + @FXML + private Label lblMode; + + @FXML + private Label lblSupId; + + @FXML + private TextField txtCompanyName; + + @FXML + private TextField txtContactFirstName; + + @FXML + private TextField txtContactLastName; + + @FXML + private TextField txtEmail; + + @FXML + private TextField txtPhone; + + private String mode = null; + + @FXML + void initialize() { + //Set up mouse handlers for buttons + btnSave.setOnMouseClicked(new EventHandler() { + @Override + public void handle(MouseEvent mouseEvent) { + buttonSaveClicked(mouseEvent); + } + }); + + btnCancel.setOnMouseClicked(new EventHandler() { + @Override + public void handle(MouseEvent mouseEvent) { + closeStage(mouseEvent); + } + }); + } + + private void buttonSaveClicked(MouseEvent mouseEvent) { + int numRow = 0; //how many rows affected + String errorMsg = ""; //error message for validation + + //TODO: Import validation class and validate text fields here + + if(errorMsg.isEmpty()){ //no validation errors detected + Supplier supplier = collectSupplier(); //get supplier info + if (mode.equals("Add")) { //add mode + try{ + numRow = SupplierDB.insertSupplier(supplier); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + else{ //edit mode + try{ + numRow = SupplierDB.updateSupplier(supplier.getSupId(),supplier); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + //if no rows were affected then there was an error (prompt user of error) + if (numRow == 0){ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText(mode + " failed"); + alert.showAndWait(); + closeStage(mouseEvent); + } + else { + //tell the user operation was successful + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setHeaderText("Database Operation Confirmed"); + alert.setContentText(mode + " succeeded"); + alert.showAndWait(); + closeStage(mouseEvent); + } + } + else{ //Display validation errors + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Input Error"); + alert.setContentText(errorMsg); + alert.showAndWait(); + } + } + + /** + * Close the window + * @param mouseEvent mouse event to close + */ + private void closeStage(MouseEvent mouseEvent) { + Node node = (Node) mouseEvent.getSource(); + Stage stage = (Stage) node.getScene().getWindow(); + stage.close(); + } + + /** + * Collect the supplier info + * @return supplier info with the id or the new supplier + */ + private Supplier collectSupplier(){ + int supId = 0; + Supplier supplier = null; + + if(lblSupId.isVisible()){ //Edit mode + //get supplier id from lblId (split the string so we only get the int) + supId = Integer.parseInt(lblSupId.getText().split(": ")[1]); + } + supplier = new Supplier( + supId, + txtCompanyName.getText(), + txtContactFirstName.getText(), + txtContactLastName.getText(), + txtEmail.getText(), + txtPhone.getText() + ); + return supplier; + } + + /** + * Display the supplier data in text fields + * @param supplier the supplier entity containing data to display + */ + public void displaySupplierDetails(Supplier supplier){ + if (supplier!=null){ + lblSupId.setText("ID: " + supplier.getSupId()); + txtCompanyName.setText(supplier.getSupCompany()); + txtContactFirstName.setText(supplier.getSupContactFirstName()); + txtContactLastName.setText(supplier.getSupContactLastName()); + txtEmail.setText(supplier.getSupEmail()); + txtPhone.setText(supplier.getSupPhone()); + } + } + + + /** + * Set the mode of the dialog + * @param mode the mode to for the dialog + */ + public void setMode(String mode) { + this.mode = mode; + lblMode.setText(mode + " Supplier"); + if(mode.equals("Add")) { + lblSupId.setVisible(false); + } + else if(mode.equals("Edit")) { + lblSupId.setVisible(true); + } + } + } diff --git a/src/main/java/org/example/petshopdesktop/database/SupplierDB.java b/src/main/java/org/example/petshopdesktop/database/SupplierDB.java index ca41bc30..cc186081 100644 --- a/src/main/java/org/example/petshopdesktop/database/SupplierDB.java +++ b/src/main/java/org/example/petshopdesktop/database/SupplierDB.java @@ -5,10 +5,7 @@ import javafx.collections.ObservableList; import org.example.petshopdesktop.models.Product; import org.example.petshopdesktop.models.Supplier; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; +import java.sql.*; /** * A class containing all the methods relating to CRUD on Suppliers table @@ -44,4 +41,90 @@ public class SupplierDB { conn.close(); return suppliers; } + + /** + * Inserts a new supplier to the database + * @param supplier supplier entity to be inserted + * @return number of rows affected in the database + * @throws SQLException if insertion failed + */ + public static int insertSupplier(Supplier supplier) throws SQLException { + int numRows = 0; + + Connection conn = ConnectionDB.getConnection(); + String sql = "INSERT INTO supplier (supId, supCompany, supContactFirstName, supContactLastName, supEmail, supPhone)" + + "VALUES (?, ?, ?, ?, ?, ?)"; + + //These are the values from supplier to put into the query above + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setInt(1, supplier.getSupId()); + stmt.setString(2, supplier.getSupCompany()); + stmt.setString(3, supplier.getSupContactFirstName()); + stmt.setString(4, supplier.getSupContactLastName()); + stmt.setString(5, supplier.getSupEmail()); + stmt.setString(6, supplier.getSupPhone()); + + //update the number of rows affected, return and close connection + numRows = stmt.executeUpdate(); + conn.close(); + + return numRows; + } + + /** + * Update an existing supplier to the database + * @param supId id of supplier + * @param supplier new supplier data + * @return number of rows affected in the database + * @throws SQLException if update failed + */ + public static int updateSupplier(int supId, Supplier supplier) throws SQLException { + int numRows = 0; + + Connection conn = ConnectionDB.getConnection(); + String sql = "UPDATE supplier SET " + + " supCompany = ?, " + + " supContactFirstName = ?, " + + " supContactLastName = ?, " + + " supEmail = ?, " + + " supPhone = ? " + + " WHERE supId = ?"; + + //updated values to update the supplier with the query above + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setString(1, supplier.getSupCompany()); + stmt.setString(2, supplier.getSupContactFirstName()); + stmt.setString(3, supplier.getSupContactLastName()); + stmt.setString(4, supplier.getSupEmail()); + stmt.setString(5, supplier.getSupPhone()); + stmt.setInt(6, supId); + + //Update the rows and close connection + numRows = stmt.executeUpdate(); + conn.close(); + + return numRows; + } + + /** + * Delete a supplier form the database + * @param supId supplier id to be deleted + * @return number of rows affected in the database + * @throws SQLException if delete failed + */ + public static int deleteSupplier(int supId) throws SQLException { + int numRows = 0; + Connection conn = ConnectionDB.getConnection(); + + String sql = "DELETE FROM supplier WHERE supId = ?"; + PreparedStatement stmt = conn.prepareStatement(sql); + //The supplier id to be deleted for the query above + stmt.setInt(1, supId); + + //close connection and update rows affected + numRows = stmt.executeUpdate(); + conn.close(); + + return numRows; + } } diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml new file mode 100644 index 00000000..e26557c8 --- /dev/null +++ b/src/main/resources/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +