Added CRUD to productSuppliers

-add CRUD to productSupplier and changed sqlDatabase so cost is in productSuppliers table
This commit is contained in:
Alex
2026-02-04 19:05:41 -07:00
parent 07a6d3bfc6
commit b53dcf10a7
13 changed files with 962 additions and 27 deletions

View File

@@ -85,6 +85,7 @@ CREATE TABLE product (
CREATE TABLE productSupplier ( CREATE TABLE productSupplier (
supId INT NOT NULL, supId INT NOT NULL,
prodId INT NOT NULL, prodId INT NOT NULL,
cost DECIMAL(10, 2) NOT NULL,
PRIMARY KEY (supId, prodId), PRIMARY KEY (supId, prodId),
FOREIGN KEY (supId) REFERENCES supplier(supId), FOREIGN KEY (supId) REFERENCES supplier(supId),
FOREIGN KEY (prodId) REFERENCES product(prodId) FOREIGN KEY (prodId) REFERENCES product(prodId)
@@ -234,16 +235,16 @@ VALUES
('Hamster Wheel', 15.00, 5, 'Exercise wheel for small pets'), ('Hamster Wheel', 15.00, 5, 'Exercise wheel for small pets'),
('Organic Dog Treats', 25.00, 1, 'Natural dog treats'); ('Organic Dog Treats', 25.00, 1, 'Natural dog treats');
INSERT INTO productSupplier (supId, prodId) INSERT INTO productSupplier (supId, prodId, cost)
VALUES VALUES
(1, 1), (1, 1, 35.00),
(1, 2), (1, 2, 6.50),
(2, 2), (2, 2, 7.00),
(3, 3), (3, 3, 90.00),
(3, 4), (3, 4, 60.00),
(4, 5), (4, 5, 10.00),
(5, 6), (5, 6, 18.00),
(1, 6); (1, 6, 17.50);
INSERT INTO inventory (prodId, quantity) INSERT INTO inventory (prodId, quantity)
VALUES VALUES

View File

@@ -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);
}
}

View File

@@ -105,7 +105,7 @@ public class ProductController {
try{ try{
data = ProductDB.getProductDTO(); data = ProductDB.getProductDTO();
} catch (SQLException e) { } catch (SQLException e) {
System.out.println(e.getMessage()); System.out.println("Error while fetching table data: " + e.getMessage());
} }
//put data in the table //put data in the table
@@ -114,7 +114,7 @@ public class ProductController {
/** /**
* open a new dialog for adding a product * open a new dialog for adding a product
* @param event * @param event click event for button
*/ */
@FXML @FXML
void btnAddClicked(ActionEvent event) { void btnAddClicked(ActionEvent event) {
@@ -211,7 +211,7 @@ public class ProductController {
tvProducts.setItems(data); tvProducts.setItems(data);
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); System.out.println("Error while fetching table data: " + e.getMessage());
} }
} }

View File

@@ -1,11 +1,27 @@
package org.example.petshopdesktop.controllers; package org.example.petshopdesktop.controllers;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Button; import javafx.fxml.FXMLLoader;
import javafx.scene.control.TableColumn; import javafx.scene.Scene;
import javafx.scene.control.TableView; import javafx.scene.control.*;
import javafx.scene.control.TextField; 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 { public class ProductSupplierController {
@@ -19,39 +35,222 @@ public class ProductSupplierController {
private Button btnEdit; private Button btnEdit;
@FXML @FXML
private TableColumn<?, ?> colCost; private TableColumn<ProductSupplierDTO, Double> colCost;
@FXML @FXML
private TableColumn<?, ?> colProductId; private TableColumn<ProductSupplierDTO, Integer> colProductId;
@FXML @FXML
private TableColumn<?, ?> colProductName; private TableColumn<ProductSupplierDTO, String> colProductName;
@FXML @FXML
private TableColumn<?, ?> colSupplierId; private TableColumn<ProductSupplierDTO, Integer> colSupplierId;
@FXML @FXML
private TableColumn<?, ?> colSupplierName; private TableColumn<ProductSupplierDTO, String> colSupplierName;
@FXML @FXML
private TableView<?> tvProductSuppliers; private TableView<ProductSupplierDTO> tvProductSuppliers;
@FXML @FXML
private TextField txtSearch; private TextField txtSearch;
//data declaration
private ObservableList<ProductSupplierDTO> data = FXCollections.observableArrayList();
private String mode = null;
/**
* Set up the table view for table and display it when starting up
*/
@FXML @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<ProductSupplierDTO,Integer>("prodId"));
colProductName.setCellValueFactory(new PropertyValueFactory<ProductSupplierDTO,String>("prodName"));
colSupplierId.setCellValueFactory(new PropertyValueFactory<ProductSupplierDTO,Integer>("supId"));
colSupplierName.setCellValueFactory(new PropertyValueFactory<ProductSupplierDTO,String>("supCompany"));
colCost.setCellValueFactory(new PropertyValueFactory<ProductSupplierDTO,Double>("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 @FXML
void btnDeleteClicked(ActionEvent event) { 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<ButtonType> 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 @FXML
void btnEditClicked(ActionEvent event) { 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("");
} }
} }

View File

@@ -99,7 +99,7 @@ public class SupplierController {
try{ try{
data = SupplierDB.getSuppliers(); data = SupplierDB.getSuppliers();
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException(e); System.out.println("Error while fetching table data: " + e.getMessage());
} }
tvSuppliers.setItems(data); tvSuppliers.setItems(data);
@@ -121,7 +121,7 @@ public class SupplierController {
tvSuppliers.setItems(data); tvSuppliers.setItems(data);
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); System.out.println("Error while fetching table data: " + e.getMessage());
} }
} }

View File

@@ -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) { private void buttonSaveClicked(MouseEvent mouseEvent) {
int numRow = 0; //how many rows affected int numRow = 0; //how many rows affected
String errorMsg = ""; //error message for validation String errorMsg = ""; //error message for validation
@@ -164,7 +169,7 @@ public class ProductDialogController {
/** /**
* Display the product data in text fields and combobox * 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){ public void displayProductDetails(ProductDTO product){
if (product!=null){ if (product!=null){
@@ -176,7 +181,7 @@ public class ProductDialogController {
//get the right combobox selection //get the right combobox selection
for (Category category : cbProdCategory.getItems()) { for (Category category : cbProdCategory.getItems()) {
if(category.getCategoryId() == product.getCategoryId()){ if(category.getCategoryId() == product.getCategoryId()){
cbProdCategory.setValue(category); cbProdCategory.getSelectionModel().select(category);
} }
} }

View File

@@ -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<Product> cbProduct;
@FXML
private ComboBox<Supplier> 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<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
buttonSaveClicked(mouseEvent);
}
});
btnCancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
closeStage(mouseEvent);
}
});
//Set up combobox for selecting product and supplier
try{
ObservableList<Supplier> suppliers = FXCollections.observableArrayList(); //empty list
ObservableList<Product> 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;
}
}

View File

@@ -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) { private void buttonSaveClicked(MouseEvent mouseEvent) {
int numRow = 0; //how many rows affected int numRow = 0; //how many rows affected
String errorMsg = ""; //error message for validation String errorMsg = ""; //error message for validation

View File

@@ -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<ProductSupplierDTO> getProductSupplierDTO() throws SQLException{
//Connect to the database
ObservableList<ProductSupplierDTO> 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<ProductSupplierDTO> getFilteredProductSupplierDTO (String filter) throws SQLException {
//connect to the database
ObservableList<ProductSupplierDTO> 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;
}
}

View File

@@ -83,4 +83,9 @@ public class Product {
public void setProdDesc(String prodDesc) { public void setProdDesc(String prodDesc) {
this.prodDesc.set(prodDesc); this.prodDesc.set(prodDesc);
} }
@Override
public String toString() {
return getProdName();
}
} }

View File

@@ -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);
}
}

View File

@@ -106,4 +106,9 @@ public class Supplier {
public String getSupFullName() { public String getSupFullName() {
return getSupContactFirstName() + " " + getSupContactLastName(); return getSupContactFirstName() + " " + getSupContactLastName();
} }
@Override
public String toString() {
return getSupCompany();
}
} }

View File

@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox minHeight="-Infinity" minWidth="-Infinity" prefHeight="523.0" prefWidth="790.0" spacing="20.0" style="-fx-font-size: 14px;" xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.dialogcontrollers.ProductSupplierDialogController">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="79.0" prefWidth="727.0" spacing="20.0" style="-fx-background-color: #2C3E50; -fx-background-radius: 14;">
<children>
<VBox alignment="CENTER_LEFT" prefHeight="93.0" prefWidth="358.0">
<children>
<Label fx:id="lblMode" prefHeight="42.0" prefWidth="351.0" text="Mode Product-Supplier" textFill="WHITE">
<font>
<Font name="Comic Sans MS Bold" size="30.0" />
</font>
</Label>
<Label fx:id="lblProductSupplierId" text="ID: 1" textFill="#ffe66d">
<font>
<Font size="14.0" />
</font>
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</Label>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<HBox.margin>
<Insets />
</HBox.margin>
</VBox>
<Region prefHeight="93.0" prefWidth="98.0" HBox.hgrow="ALWAYS" />
<Button fx:id="btnCancel" layoutX="391.0" layoutY="38.0" mnemonicParsing="false" style="-fx-background-color: #E74c3c; -fx-cursor: hand; -fx-background-radius: 8;" text="Cancel" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding>
</Button>
<Button fx:id="btnSave" layoutX="520.0" layoutY="38.0" mnemonicParsing="false" style="-fx-background-color: #3fe06a; -fx-cursor: hand; -fx-background-radius: 8;" text="Save" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding>
</Button>
</children>
<padding>
<Insets left="15.0" right="15.0" />
</padding>
</HBox>
<VBox prefHeight="370.0" prefWidth="750.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-color: #5580b5; -fx-border-radius: 14;">
<children>
<GridPane hgap="25.0" VBox.vgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0">
<children>
<Label text="Product:" textFill="#2c3e50">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<ComboBox fx:id="cbProduct" prefHeight="29.0" prefWidth="336.0" promptText="Select Category" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10; -fx-background-color: white;">
<padding>
<Insets bottom="3.0" left="10.0" right="10.0" top="3.0" />
</padding>
</ComboBox>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1">
<children>
<Label text="Supplier:" textFill="#2c3e50">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<ComboBox fx:id="cbSupplier" prefHeight="29.0" prefWidth="336.0" promptText="Select Category" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10; -fx-background-color: white;">
<padding>
<Insets bottom="3.0" left="10.0" right="10.0" top="3.0" />
</padding>
</ComboBox>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="1">
<children>
<Label text="Cost" textFill="#2c3e50">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<TextField fx:id="txtCost" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10;">
<padding>
<Insets bottom="7.0" left="10.0" right="10.0" top="7.0" />
</padding>
</TextField>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="2" />
</children>
<VBox.margin>
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" />
</VBox.margin>
</GridPane>
</children>
<padding>
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" />
</padding>
</VBox>
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</VBox>