From b53dcf10a7c5a306610b810fafbe211f206cfa25 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 4 Feb 2026 19:05:41 -0700 Subject: [PATCH] Added CRUD to productSuppliers -add CRUD to productSupplier and changed sqlDatabase so cost is in productSuppliers table --- Petstoredata.sql | 19 +- .../DTOs/ProductSupplierDTO.java | 83 ++++++ .../controllers/ProductController.java | 6 +- .../ProductSupplierController.java | 221 +++++++++++++++- .../controllers/SupplierController.java | 4 +- .../ProductDialogController.java | 9 +- .../ProductSupplierDialogController.java | 245 ++++++++++++++++++ .../SupplierDialogController.java | 5 + .../database/ProductSupplierDB.java | 197 ++++++++++++++ .../petshopdesktop/models/Product.java | 5 + .../models/ProductSupplier.java | 54 ++++ .../petshopdesktop/models/Supplier.java | 5 + .../product-supplier-dialog-view.fxml | 136 ++++++++++ 13 files changed, 962 insertions(+), 27 deletions(-) create mode 100644 src/main/java/org/example/petshopdesktop/DTOs/ProductSupplierDTO.java create mode 100644 src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java create mode 100644 src/main/java/org/example/petshopdesktop/database/ProductSupplierDB.java create mode 100644 src/main/java/org/example/petshopdesktop/models/ProductSupplier.java create mode 100644 src/main/resources/org/example/petshopdesktop/dialogviews/product-supplier-dialog-view.fxml diff --git a/Petstoredata.sql b/Petstoredata.sql index c1d1046b..1b968e23 100644 --- a/Petstoredata.sql +++ b/Petstoredata.sql @@ -85,6 +85,7 @@ CREATE TABLE product ( CREATE TABLE productSupplier ( supId INT NOT NULL, prodId INT NOT NULL, + cost DECIMAL(10, 2) NOT NULL, PRIMARY KEY (supId, prodId), FOREIGN KEY (supId) REFERENCES supplier(supId), FOREIGN KEY (prodId) REFERENCES product(prodId) @@ -234,16 +235,16 @@ VALUES ('Hamster Wheel', 15.00, 5, 'Exercise wheel for small pets'), ('Organic Dog Treats', 25.00, 1, 'Natural dog treats'); -INSERT INTO productSupplier (supId, prodId) +INSERT INTO productSupplier (supId, prodId, cost) VALUES -(1, 1), -(1, 2), -(2, 2), -(3, 3), -(3, 4), -(4, 5), -(5, 6), -(1, 6); +(1, 1, 35.00), +(1, 2, 6.50), +(2, 2, 7.00), +(3, 3, 90.00), +(3, 4, 60.00), +(4, 5, 10.00), +(5, 6, 18.00), +(1, 6, 17.50); INSERT INTO inventory (prodId, quantity) VALUES diff --git a/src/main/java/org/example/petshopdesktop/DTOs/ProductSupplierDTO.java b/src/main/java/org/example/petshopdesktop/DTOs/ProductSupplierDTO.java new file mode 100644 index 00000000..8fb481b0 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/DTOs/ProductSupplierDTO.java @@ -0,0 +1,83 @@ +package org.example.petshopdesktop.DTOs; + +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleStringProperty; + +public class ProductSupplierDTO { + private SimpleIntegerProperty supId; + private SimpleIntegerProperty prodId; + private SimpleStringProperty supCompany; + private SimpleStringProperty prodName; + private SimpleDoubleProperty cost; + + //constructor + public ProductSupplierDTO(int supId, int prodId, String supCompany, String prodName, double cost) { + this.supId = new SimpleIntegerProperty(supId); + this.prodId = new SimpleIntegerProperty(prodId); + this.supCompany = new SimpleStringProperty(supCompany); + this.prodName = new SimpleStringProperty(prodName); + this.cost = new SimpleDoubleProperty(cost); + } + + //getter and setters + public int getSupId() { + return supId.get(); + } + + public SimpleIntegerProperty supIdProperty() { + return supId; + } + + public void setSupId(int supId) { + this.supId.set(supId); + } + + public int getProdId() { + return prodId.get(); + } + + public SimpleIntegerProperty prodIdProperty() { + return prodId; + } + + public void setProdId(int prodId) { + this.prodId.set(prodId); + } + + public String getSupCompany() { + return supCompany.get(); + } + + public SimpleStringProperty supCompanyProperty() { + return supCompany; + } + + public void setSupCompany(String supCompany) { + this.supCompany.set(supCompany); + } + + public String getProdName() { + return prodName.get(); + } + + public SimpleStringProperty prodNameProperty() { + return prodName; + } + + public void setProdName(String prodName) { + this.prodName.set(prodName); + } + + public double getCost() { + return cost.get(); + } + + public SimpleDoubleProperty costProperty() { + return cost; + } + + public void setCost(double cost) { + this.cost.set(cost); + } +} diff --git a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java index 4dc1587e..8c0021fb 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java @@ -105,7 +105,7 @@ public class ProductController { try{ data = ProductDB.getProductDTO(); } catch (SQLException e) { - System.out.println(e.getMessage()); + System.out.println("Error while fetching table data: " + e.getMessage()); } //put data in the table @@ -114,7 +114,7 @@ public class ProductController { /** * open a new dialog for adding a product - * @param event + * @param event click event for button */ @FXML void btnAddClicked(ActionEvent event) { @@ -211,7 +211,7 @@ public class ProductController { tvProducts.setItems(data); } } catch (Exception e) { - throw new RuntimeException(e); + System.out.println("Error while fetching table data: " + e.getMessage()); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java b/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java index d8a6e90a..56080c6e 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java @@ -1,11 +1,27 @@ 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.ProductDTO; +import org.example.petshopdesktop.DTOs.ProductSupplierDTO; +import org.example.petshopdesktop.controllers.dialogcontrollers.ProductDialogController; +import org.example.petshopdesktop.controllers.dialogcontrollers.ProductSupplierDialogController; +import org.example.petshopdesktop.database.ProductDB; +import org.example.petshopdesktop.database.ProductSupplierDB; +import org.example.petshopdesktop.models.ProductSupplier; + +import java.io.IOException; +import java.sql.SQLException; +import java.sql.SQLIntegrityConstraintViolationException; +import java.util.Optional; public class ProductSupplierController { @@ -19,39 +35,222 @@ public class ProductSupplierController { private Button btnEdit; @FXML - private TableColumn colCost; + private TableColumn colCost; @FXML - private TableColumn colProductId; + private TableColumn colProductId; @FXML - private TableColumn colProductName; + private TableColumn colProductName; @FXML - private TableColumn colSupplierId; + private TableColumn colSupplierId; @FXML - private TableColumn colSupplierName; + private TableColumn colSupplierName; @FXML - private TableView tvProductSuppliers; + private TableView tvProductSuppliers; @FXML private TextField txtSearch; + //data declaration + private ObservableList data = FXCollections.observableArrayList(); + private String mode = null; + + /** + * Set up the table view for table and display it when starting up + */ @FXML - void btnAddClicked(ActionEvent event) { + public 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")); + colSupplierId.setCellValueFactory(new PropertyValueFactory("supId")); + colSupplierName.setCellValueFactory(new PropertyValueFactory("supCompany")); + colCost.setCellValueFactory(new PropertyValueFactory("cost")); + + displayProductSupplier(); + + //EventListener to Enable buttons when a row is selected + tvProductSuppliers.getSelectionModel().selectedItemProperty().addListener( + (observable, oldValue, newValue) -> { + btnEdit.setDisable(false); + btnDelete.setDisable(false); + } + ); + + //EventListener to search when text is changed on searchbar + txtSearch.textProperty().addListener((observable, oldValue, newValue) -> { + displayFilteredProductSupplier(newValue); + }); } + /** + * Display the ProductSupplierDTO to table view + */ + private void displayProductSupplier() { + //Erase old content + data.clear(); + + //get ProductSupplier from database + try{ + data = ProductSupplierDB.getProductSupplierDTO(); + } catch (SQLException e) { + System.out.println("Error while fetching table data: " + e.getMessage()); + } + + //put data in the table + tvProductSuppliers.setItems(data); + } + + /** + * Filter the table given the string from the searchbar + * @param filter word to filter table + */ + private void displayFilteredProductSupplier(String filter){ + data.clear(); + try{ + if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){ + displayProductSupplier(); //If search bar is empty just display everything + } + else{ + //Filter the using the keyword + data = ProductSupplierDB.getFilteredProductSupplierDTO(filter); + tvProductSuppliers.setItems(data); + } + } catch (Exception e) { + System.out.println("Error while fetching table data: " + e.getMessage()); + } + } + + /** + * open a new dialog for adding a productSupplier + * @param event click event for button + */ + @FXML + void btnAddClicked(ActionEvent event) { + mode = "Add"; + openDialog(null,mode); + } + + /** + * Delete a selected productSupplier when delete is clicked + * @param event click event for button + */ @FXML void btnDeleteClicked(ActionEvent event) { + int numRows = 0; + //set selected item + ProductSupplierDTO selectedProductSupplier = tvProductSuppliers.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 product-supplier?"); + Optional result = question.showAndWait(); //show alert and wait for response + + //if confirmed,start deletion + if (result.isPresent() && result.get() == ButtonType.OK) { + int supId = selectedProductSupplier.getSupId(); + int prodId = selectedProductSupplier.getProdId(); + + //try deleting + try{ + numRows = ProductSupplierDB.deleteProductSupplier(supId, prodId); + } + catch (SQLIntegrityConstraintViolationException e){ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText("Delete failed\n" + + "the selected product-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 and reset inputs + displayProductSupplier(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); + } + } } @FXML void btnEditClicked(ActionEvent event) { + //set selected item + ProductSupplierDTO selectedProductSupplier = tvProductSuppliers.getSelectionModel().getSelectedItem(); + if (selectedProductSupplier != null) { + mode = "Edit"; + openDialog(selectedProductSupplier,mode); + } + } + + /** + * Function to open the new Dialog for edit or adding + * depending on the mode given + * @param productSupplier the productSupplier entity for editing, null if adding + * @param mode the mode the dialog should be in + */ + private void openDialog(ProductSupplierDTO productSupplier, String mode){ + //Get new view + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/product-supplier-dialog-view.fxml")); + Scene scene = null; + try{ + scene = new Scene(fxmlLoader.load()); + } catch (IOException e) { + throw new RuntimeException(e); + } + ProductSupplierDialogController dialogController = fxmlLoader.getController(); //controller associated with this view + dialogController.setMode(mode); + if (productSupplier != null) { + dialogController.setSelectedIds(productSupplier.getSupId(), productSupplier.getProdId()); + } + + //Open the dialog depending on the mode + if(mode.equals("Edit")){ + //Make it display suppliers details in dialog + dialogController.displayProductSupplierDetails(productSupplier); + } + Stage dialogStage = new Stage(); + dialogStage.initModality(Modality.APPLICATION_MODAL); //make it modal + if(mode.equals("Add")){ + dialogStage.setTitle("Add Product-Supplier"); + } + else { + dialogStage.setTitle("Edit Product-Supplier"); + } + dialogStage.setScene(scene); + dialogStage.showAndWait(); + + //When dialog closes update table view and disable edit and delete buttons, and reset search bar + displayProductSupplier(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java b/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java index 080cc751..aa909103 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java @@ -99,7 +99,7 @@ public class SupplierController { try{ data = SupplierDB.getSuppliers(); } catch (SQLException e) { - throw new RuntimeException(e); + System.out.println("Error while fetching table data: " + e.getMessage()); } tvSuppliers.setItems(data); @@ -121,7 +121,7 @@ public class SupplierController { tvSuppliers.setItems(data); } } catch (Exception e) { - throw new RuntimeException(e); + System.out.println("Error while fetching table data: " + e.getMessage()); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java index 5cc58d87..3aa29a93 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java @@ -79,6 +79,11 @@ public class ProductDialogController { } + /** + * Validates the inputs, then add or update the database depending + * on the mode + * @param mouseEvent click event for save button + */ private void buttonSaveClicked(MouseEvent mouseEvent) { int numRow = 0; //how many rows affected String errorMsg = ""; //error message for validation @@ -164,7 +169,7 @@ public class ProductDialogController { /** * Display the product data in text fields and combobox - * @param product the supplier entity containing data to display + * @param product the product entity containing data to display */ public void displayProductDetails(ProductDTO product){ if (product!=null){ @@ -176,7 +181,7 @@ public class ProductDialogController { //get the right combobox selection for (Category category : cbProdCategory.getItems()) { if(category.getCategoryId() == product.getCategoryId()){ - cbProdCategory.setValue(category); + cbProdCategory.getSelectionModel().select(category); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java new file mode 100644 index 00000000..909363b2 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java @@ -0,0 +1,245 @@ +package org.example.petshopdesktop.controllers.dialogcontrollers; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.input.MouseEvent; +import javafx.stage.Stage; +import org.example.petshopdesktop.DTOs.ProductSupplierDTO; +import org.example.petshopdesktop.Validator; +import org.example.petshopdesktop.database.ProductDB; +import org.example.petshopdesktop.database.ProductSupplierDB; +import org.example.petshopdesktop.database.SupplierDB; +import org.example.petshopdesktop.models.Product; +import org.example.petshopdesktop.models.ProductSupplier; +import org.example.petshopdesktop.models.Supplier; + +import java.sql.SQLException; +import java.sql.SQLIntegrityConstraintViolationException; + +public class ProductSupplierDialogController { + + @FXML + private Button btnCancel; + + @FXML + private Button btnSave; + + @FXML + private ComboBox cbProduct; + + @FXML + private ComboBox cbSupplier; + + @FXML + private Label lblMode; + + @FXML + private Label lblProductSupplierId; + + @FXML + private TextField txtCost; + + private String mode = null; + private int selectedSupId = -1; + private int selectedProdId = -1; + + /** + * add event listeners to buttons and set up combobox + */ + @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); + } + }); + + //Set up combobox for selecting product and supplier + try{ + ObservableList suppliers = FXCollections.observableArrayList(); //empty list + ObservableList products = FXCollections.observableArrayList(); //empty list + + //get suppliers and products from DB + suppliers = SupplierDB.getSuppliers(); + products = ProductDB.getProducts(); + + //Populate combobox + cbSupplier.setItems(suppliers); + cbProduct.setItems(products); + } + catch(SQLException e){ + throw new RuntimeException(e); + } + + } + + /** + * Validates the inputs, then add or update the database depending + * on the mode + * @param mouseEvent click event for save button + */ + private void buttonSaveClicked(MouseEvent mouseEvent) { + int numRows = 0; + String errorMsg = ""; //error message for validation + + //Check Validation (input required) + errorMsg += Validator.isPresent(txtCost.getText(), "Cost"); + if (cbProduct.getSelectionModel().getSelectedItem() == null) { + errorMsg += "Product is required \n"; + } + if (cbSupplier.getSelectionModel().getSelectedItem() == null) { + errorMsg += "Supplier is required \n"; + } + + //Check validation (length size) + errorMsg += Validator.isLessThanVarChars(txtCost.getText(), "Cost", 12); + + //Check validation (format) + errorMsg += Validator.isNonNegativeDouble(txtCost.getText(), "Cost"); + + if(errorMsg.isEmpty()){ //no validation errors + ProductSupplier productSupplier = collectProductSupplier(); //get productSupplier info + if (mode.equals("Add")) { //add mode + try{ + numRows = ProductSupplierDB.insertProductSupplier(productSupplier); + } + catch(SQLIntegrityConstraintViolationException e){ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText("Add failed \n" + + "the product-supplier link is already in the database"); + alert.showAndWait(); + numRows = -1; //Update numRow so alert only shows once + closeStage(mouseEvent); + } + catch(SQLException e){ + throw new RuntimeException(e); + } + } + else { //edit + try{ + numRows = ProductSupplierDB.updateProductSupplier(selectedSupId, selectedProdId, productSupplier); + } + catch(SQLIntegrityConstraintViolationException e){ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText("Edit failed \n" + + "the product-supplier link is already in the database"); + alert.showAndWait(); + numRows = -1; //Update numRow so alert only shows once + closeStage(mouseEvent); + } + catch(SQLException e){ + throw new RuntimeException(e); + } + } + + //if no rows were affected then there was an error (prompt user of error) + if (numRows == 0){ + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText(mode + " failed"); + alert.showAndWait(); + closeStage(mouseEvent); + } + else if (numRows > 0){ + //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(); + } + } + + /** + * collect the data for new/updated productSupplier + * @return productSupplier entity with data + */ + private ProductSupplier collectProductSupplier() { + ProductSupplier productSupplier = null; + + productSupplier = new ProductSupplier( + cbSupplier.getSelectionModel().getSelectedItem().getSupId(), + cbProduct.getSelectionModel().getSelectedItem().getProdId(), + Double.parseDouble(txtCost.getText()) + ); + + return productSupplier; + } + + /** + * Display the productsupplier data in text fields and combobox + * @param productSupplier + */ + public void displayProductSupplierDetails(ProductSupplierDTO productSupplier){ + if(productSupplier != null){ + txtCost.setText(productSupplier.getCost() + ""); + } + + //Get the right combobox selection (product) + for (Product product : cbProduct.getItems()) { + if(product.getProdId() == productSupplier.getProdId()){ + cbProduct.getSelectionModel().select(product); + } + } + + //Get the right combobox selection (supplier) + for (Supplier supplier : cbSupplier.getItems()) { + if (supplier.getSupId() == productSupplier.getSupId()) { + cbSupplier.getSelectionModel().select(supplier); + } + } + + } + + /** + * 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(); + } + + /** + * Set the mode of the dialog + * @param mode the mode for the dialog + */ + public void setMode(String mode) { + this.mode = mode; + lblMode.setText(mode + " Product"); + lblProductSupplierId.setVisible(false); + } + + /** + * set the current supplier and productId for (needed for update since compound primary key) + * @param supId supplier id + * @param prodId product id + */ + public void setSelectedIds(int supId, int prodId){ + this.selectedSupId = supId; + this.selectedProdId = prodId; + } + +} 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 d901d3d5..34cb91eb 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java @@ -67,6 +67,11 @@ public class SupplierDialogController { }); } + /** + * Validates the inputs, then add or update the database depending + * on the mode + * @param mouseEvent click event for save button + */ private void buttonSaveClicked(MouseEvent mouseEvent) { int numRow = 0; //how many rows affected String errorMsg = ""; //error message for validation diff --git a/src/main/java/org/example/petshopdesktop/database/ProductSupplierDB.java b/src/main/java/org/example/petshopdesktop/database/ProductSupplierDB.java new file mode 100644 index 00000000..cc651bd0 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/database/ProductSupplierDB.java @@ -0,0 +1,197 @@ +package org.example.petshopdesktop.database; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import org.example.petshopdesktop.DTOs.ProductDTO; +import org.example.petshopdesktop.DTOs.ProductSupplierDTO; +import org.example.petshopdesktop.models.Product; +import org.example.petshopdesktop.models.ProductSupplier; + +import java.sql.*; + +public class ProductSupplierDB { + /** + * gets all the productSupplier into an observable list + * @return a list of all the productSupplierDTOs + * @throws SQLException if failed to find productSupplier in the database + */ + public static ObservableList getProductSupplierDTO() throws SQLException{ + //Connect to the database + ObservableList productSuppliers = FXCollections.observableArrayList(); + Connection conn = ConnectionDB.getConnection(); + + //Execute Query + Statement stmt = conn.createStatement(); + String sql = "SELECT ps.supId, ps.prodId, s.supCompany, p.prodName, ps.cost " + + "FROM productsupplier ps " + + "LEFT JOIN product p " + + "ON p.prodId = ps.prodId " + + "LEFT JOIN supplier s " + + "ON s.supId = ps.supId"; + ResultSet rs = stmt.executeQuery(sql); + + //While there is still data add productSupplier to list + while(rs.next()){ + ProductSupplierDTO productSupplier = new ProductSupplierDTO( + rs.getInt(1), + rs.getInt(2), + rs.getString(3), + rs.getString(4), + rs.getDouble(5) + ); + productSuppliers.add(productSupplier); + } + + //close connection and return products + conn.close(); + return productSuppliers; + } + + /** + * Gets a list of ProductSupplierDTOs that is filtered by a given string + * @param filter the word to filter table + * @return ObservableList of ProductSupplierDTOs with the filtered data + * @throws SQLException if getting productSuppliers failed + */ + public static ObservableList getFilteredProductSupplierDTO (String filter) throws SQLException { + //connect to the database + ObservableList productSuppliers = FXCollections.observableArrayList(); + Connection conn = ConnectionDB.getConnection(); + + //Get SQL query for filter word + String sql = + "SELECT ps.supId, ps.prodId, s.supCompany, p.prodName, ps.cost " + + "FROM product p " + + "LEFT JOIN productsupplier ps " + + "ON p.prodId = ps.prodId " + + "LEFT JOIN supplier s " + + "ON s.supId = ps.supId " + + "WHERE " + + "prodName LIKE ? OR " + + "supCompany LIKE ? OR " + + "cost LIKE ?"; + + //add % wildcard so query can use LIKE to filter data + String filteredString = "%" + filter + "%"; + + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setString(1, filteredString); + stmt.setString(2, filteredString); + stmt.setString(3, filteredString); + + //execute query + ResultSet rs = stmt.executeQuery(); + + //While there is still data add productSupplier to the list + while(rs.next()){ + ProductSupplierDTO productSupplier = new ProductSupplierDTO( + rs.getInt(1), + rs.getInt(2), + rs.getString(3), + rs.getString(4), + rs.getDouble(5) + ); + productSuppliers.add(productSupplier); + } + + conn.close(); + return productSuppliers; + } + + /** + * Inserts a new productSupplier to the database + * @param productSupplier productSupplier entity to be inserted + * @return number of rows affected + * @throws SQLException if insert failed + */ + public static int insertProductSupplier(ProductSupplier productSupplier) throws SQLException{ + int numRows = 0; + + Connection conn = ConnectionDB.getConnection(); + String sql = "INSERT INTO productsupplier (prodId, supId, cost) " + + "VALUES (?, ?, ?)"; + + //These are the values from productSupplier to put into query above + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setInt(1, productSupplier.getProdId()); + stmt.setInt(2, productSupplier.getSupId()); + stmt.setDouble(3, productSupplier.getCost()); + + //update number of rows affected, return and close connection + numRows = stmt.executeUpdate(); + conn.close(); + + return numRows; + } + + /** + * Update a productSupplier by deleting old productSupplier and inserting new one + * @param oldProdId old product id (used to change primary compound key) + * @param oldSupId old supplier id (used to change primary compound key) + * @param productSupplier productSupplier entity with new info to update (including new primary compound key) + * @return number of rows affected in database + * @throws SQLException if update failed + */ + public static int updateProductSupplier(int oldSupId, int oldProdId, ProductSupplier productSupplier) throws SQLException{ + int numRows = 0; + Connection conn = ConnectionDB.getConnection(); + + //Make transaction so update can be rolled back if insert failed + conn.setAutoCommit(false); + + try{ + //Delete old data first + String sql = "DELETE FROM productsupplier WHERE supId = ? AND prodId = ?"; + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setInt(1, oldSupId); + stmt.setInt(2, oldProdId); + numRows = stmt.executeUpdate(); + + //Then change the data by inserting a new relation with given keys (only if delete worked) + if(numRows > 0){ + sql = "INSERT INTO productsupplier (prodId, supId, cost) " + + "VALUES (?, ?, ?)"; + stmt = conn.prepareStatement(sql); + stmt.setInt(1, productSupplier.getProdId()); + stmt.setInt(2, productSupplier.getSupId()); + stmt.setDouble(3, productSupplier.getCost()); + numRows = stmt.executeUpdate(); + } + //Commit changes if both delete and insert worked + conn.commit(); + } + catch(SQLException e){ + //Rollback CRUD failed + conn.rollback(); + throw e; + } + finally { + //Set auto commit back to true before closing connection + conn.setAutoCommit(true); + conn.close(); + } + return numRows; + } + + /** + * Delete a productSupplier from the database + * @param prodId id of the product + * @param supId id of the supplier + * @return number of rows affected in the database + * @throws SQLException if delete failed + */ + public static int deleteProductSupplier(int supId, int prodId) throws SQLException{ + int numRows = 0; + Connection conn = ConnectionDB.getConnection(); + + String sql = "DELETE FROM productsupplier WHERE supId = ? AND prodId = ?"; + PreparedStatement stmt = conn.prepareStatement(sql); + stmt.setInt(1, supId); + stmt.setInt(2, prodId); + + numRows = stmt.executeUpdate(); + conn.close(); + + return numRows; + } +} diff --git a/src/main/java/org/example/petshopdesktop/models/Product.java b/src/main/java/org/example/petshopdesktop/models/Product.java index 0738068a..bf0913e5 100644 --- a/src/main/java/org/example/petshopdesktop/models/Product.java +++ b/src/main/java/org/example/petshopdesktop/models/Product.java @@ -83,4 +83,9 @@ public class Product { public void setProdDesc(String prodDesc) { this.prodDesc.set(prodDesc); } + + @Override + public String toString() { + return getProdName(); + } } diff --git a/src/main/java/org/example/petshopdesktop/models/ProductSupplier.java b/src/main/java/org/example/petshopdesktop/models/ProductSupplier.java new file mode 100644 index 00000000..e674974d --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/models/ProductSupplier.java @@ -0,0 +1,54 @@ +package org.example.petshopdesktop.models; + +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleIntegerProperty; + +public class ProductSupplier { + private SimpleIntegerProperty supId; + private SimpleIntegerProperty prodId; + private SimpleDoubleProperty cost; + + //constructor + public ProductSupplier(int supId, int prodId, double cost) { + this.supId = new SimpleIntegerProperty(supId); + this.prodId = new SimpleIntegerProperty(prodId); + this.cost = new SimpleDoubleProperty(cost); + } + + //getter and setters + public int getSupId() { + return supId.get(); + } + + public SimpleIntegerProperty supIdProperty() { + return supId; + } + + public void setSupId(int supId) { + this.supId.set(supId); + } + + public int getProdId() { + return prodId.get(); + } + + public SimpleIntegerProperty prodIdProperty() { + return prodId; + } + + public void setProdId(int prodId) { + this.prodId.set(prodId); + } + + public double getCost() { + return cost.get(); + } + + public SimpleDoubleProperty costProperty() { + return cost; + } + + public void setCost(double cost) { + this.cost.set(cost); + } +} diff --git a/src/main/java/org/example/petshopdesktop/models/Supplier.java b/src/main/java/org/example/petshopdesktop/models/Supplier.java index 36f05094..1120670a 100644 --- a/src/main/java/org/example/petshopdesktop/models/Supplier.java +++ b/src/main/java/org/example/petshopdesktop/models/Supplier.java @@ -106,4 +106,9 @@ public class Supplier { public String getSupFullName() { return getSupContactFirstName() + " " + getSupContactLastName(); } + + @Override + public String toString() { + return getSupCompany(); + } } diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/product-supplier-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/product-supplier-dialog-view.fxml new file mode 100644 index 00000000..0ef57a60 --- /dev/null +++ b/src/main/resources/org/example/petshopdesktop/dialogviews/product-supplier-dialog-view.fxml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +