Added CRUD to Products and added Validation to dialog

This commit is contained in:
Alex
2026-02-03 20:02:46 -07:00
parent 310b66329f
commit 07a6d3bfc6
14 changed files with 1147 additions and 145 deletions

View File

@@ -7,24 +7,24 @@ USE Petstoredb;
CREATE TABLE storeLocation ( CREATE TABLE storeLocation (
storeId INT AUTO_INCREMENT PRIMARY KEY, storeId INT AUTO_INCREMENT PRIMARY KEY,
storeName VARCHAR(100) NOT NULL, storeName VARCHAR(100) NOT NULL,
address VARCHAR(255), address VARCHAR(255) NOT NULL,
phone VARCHAR(20), phone VARCHAR(20) NOT NULL,
email VARCHAR(100) email VARCHAR(100) NOT NULL
); );
CREATE TABLE employee ( CREATE TABLE employee (
employeeId INT AUTO_INCREMENT PRIMARY KEY, employeeId INT AUTO_INCREMENT PRIMARY KEY,
firstName VARCHAR(50) NOT NULL, firstName VARCHAR(50) NOT NULL,
lastName VARCHAR(50) NOT NULL, lastName VARCHAR(50) NOT NULL,
email VARCHAR(100), email VARCHAR(100) NOT NULL,
phone VARCHAR(20), phone VARCHAR(20) NOT NULL,
role VARCHAR(50), role VARCHAR(50) NOT NULL,
isActive BOOLEAN DEFAULT TRUE isActive BOOLEAN DEFAULT TRUE NOT NULL
); );
CREATE TABLE employeeStore ( CREATE TABLE employeeStore (
employeeId INT, employeeId INT NOT NULL,
storeId INT, storeId INT NOT NULL,
PRIMARY KEY (employeeId, storeId), PRIMARY KEY (employeeId, storeId),
FOREIGN KEY (employeeId) REFERENCES employee(employeeId), FOREIGN KEY (employeeId) REFERENCES employee(employeeId),
FOREIGN KEY (storeId) REFERENCES storeLocation(storeId) FOREIGN KEY (storeId) REFERENCES storeLocation(storeId)
@@ -34,26 +34,26 @@ CREATE TABLE customer (
customerId INT AUTO_INCREMENT PRIMARY KEY, customerId INT AUTO_INCREMENT PRIMARY KEY,
firstName VARCHAR(50) NOT NULL, firstName VARCHAR(50) NOT NULL,
lastName VARCHAR(50) NOT NULL, lastName VARCHAR(50) NOT NULL,
email VARCHAR(100), email VARCHAR(100) NOT NULL,
phone VARCHAR(20) phone VARCHAR(20) NOT NULL
); );
CREATE TABLE pet ( CREATE TABLE pet (
petId INT AUTO_INCREMENT PRIMARY KEY, petId INT AUTO_INCREMENT PRIMARY KEY,
petName VARCHAR(50), petName VARCHAR(50) NOT NULL,
petSpecies VARCHAR(50), petSpecies VARCHAR(50) NOT NULL,
petBreed VARCHAR(50), petBreed VARCHAR(50) NOT NULL,
petAge INT, petAge INT NOT NULL,
petStatus VARCHAR(20), petStatus VARCHAR(20) NOT NULL,
petPrice DECIMAL(10, 2) petPrice DECIMAL(10, 2) NOT NULL
); );
CREATE TABLE adoption ( CREATE TABLE adoption (
adoptionId INT AUTO_INCREMENT PRIMARY KEY, adoptionId INT AUTO_INCREMENT PRIMARY KEY,
petId INT, petId INT NOT NULL,
customerId INT, customerId INT NOT NULL,
adoptionDate DATE, adoptionDate DATE NOT NULL,
adoptionStatus VARCHAR(20), adoptionStatus VARCHAR(20) NOT NULL,
FOREIGN KEY (petId) REFERENCES pet(petId), FOREIGN KEY (petId) REFERENCES pet(petId),
FOREIGN KEY (customerId) REFERENCES customer(customerId) FOREIGN KEY (customerId) REFERENCES customer(customerId)
); );
@@ -61,31 +61,30 @@ CREATE TABLE adoption (
CREATE TABLE supplier ( CREATE TABLE supplier (
supId INT AUTO_INCREMENT PRIMARY KEY, supId INT AUTO_INCREMENT PRIMARY KEY,
supCompany VARCHAR(100) NOT NULL, supCompany VARCHAR(100) NOT NULL,
supContactFirstName VARCHAR(50), supContactFirstName VARCHAR(50) NOT NULL,
supContactLastName VARCHAR(50), supContactLastName VARCHAR(50) NOT NULL,
supEmail VARCHAR(100), supEmail VARCHAR(100) NOT NULL,
supPhone VARCHAR(20) supPhone VARCHAR(20) NOT NULL
); );
CREATE TABLE category ( CREATE TABLE category (
categoryId INT AUTO_INCREMENT PRIMARY KEY, categoryId INT AUTO_INCREMENT PRIMARY KEY,
categoryName VARCHAR(100) NOT NULL, categoryName VARCHAR(100) NOT NULL,
categoryType VARCHAR(50) categoryType VARCHAR(50) NOT NULL
); );
CREATE TABLE product ( CREATE TABLE product (
prodId INT AUTO_INCREMENT PRIMARY KEY, prodId INT AUTO_INCREMENT PRIMARY KEY,
prodName VARCHAR(100) NOT NULL, prodName VARCHAR(100) NOT NULL,
prodSku VARCHAR(50) UNIQUE, prodPrice DECIMAL(10, 2) NOT NULL,
prodPrice DECIMAL(10, 2), categoryId INT NOT NULL,
categoryId INT,
prodDesc TEXT, prodDesc TEXT,
FOREIGN KEY (categoryId) REFERENCES category(categoryId) FOREIGN KEY (categoryId) REFERENCES category(categoryId)
); );
CREATE TABLE productSupplier ( CREATE TABLE productSupplier (
supId INT, supId INT NOT NULL,
prodId INT, prodId INT 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)
@@ -93,8 +92,8 @@ CREATE TABLE productSupplier (
CREATE TABLE inventory ( CREATE TABLE inventory (
inventoryId INT AUTO_INCREMENT PRIMARY KEY, inventoryId INT AUTO_INCREMENT PRIMARY KEY,
prodId INT, prodId INT NOT NULL,
quantity INT DEFAULT 0, quantity INT DEFAULT 0 NOT NULL,
FOREIGN KEY (prodId) REFERENCES product(prodId) FOREIGN KEY (prodId) REFERENCES product(prodId)
); );
@@ -102,24 +101,24 @@ CREATE TABLE service (
serviceId INT AUTO_INCREMENT PRIMARY KEY, serviceId INT AUTO_INCREMENT PRIMARY KEY,
serviceName VARCHAR(100) NOT NULL, serviceName VARCHAR(100) NOT NULL,
serviceDesc TEXT, serviceDesc TEXT,
serviceDuration INT, serviceDuration INT NOT NULL,
servicePrice DECIMAL(10, 2) servicePrice DECIMAL(10, 2) NOT NULL
); );
CREATE TABLE appointment ( CREATE TABLE appointment (
appointmentId INT AUTO_INCREMENT PRIMARY KEY, appointmentId INT AUTO_INCREMENT PRIMARY KEY,
serviceId INT, serviceId INT NOT NULL,
customerId INT, customerId INT NOT NULL,
appointmentDate DATE, appointmentDate DATE NOT NULL,
appointmentTime TIME, appointmentTime TIME NOT NULL,
appointmentStatus VARCHAR(20), appointmentStatus VARCHAR(20) NOT NULL,
FOREIGN KEY (serviceId) REFERENCES service(serviceId), FOREIGN KEY (serviceId) REFERENCES service(serviceId),
FOREIGN KEY (customerId) REFERENCES customer(customerId) FOREIGN KEY (customerId) REFERENCES customer(customerId)
); );
CREATE TABLE appointmentPet ( CREATE TABLE appointmentPet (
appointmentId INT, appointmentId INT NOT NULL,
petId INT, petId INT NOT NULL,
PRIMARY KEY (appointmentId, petId), PRIMARY KEY (appointmentId, petId),
FOREIGN KEY (appointmentId) REFERENCES appointment(appointmentId), FOREIGN KEY (appointmentId) REFERENCES appointment(appointmentId),
FOREIGN KEY (petId) REFERENCES pet(petId) FOREIGN KEY (petId) REFERENCES pet(petId)
@@ -127,30 +126,30 @@ CREATE TABLE appointmentPet (
CREATE TABLE sale ( CREATE TABLE sale (
saleId INT AUTO_INCREMENT PRIMARY KEY, saleId INT AUTO_INCREMENT PRIMARY KEY,
saleDate DATETIME, saleDate DATETIME NOT NULL,
totalAmount DECIMAL(10, 2), totalAmount DECIMAL(10, 2) NOT NULL,
paymentMethod VARCHAR(50), paymentMethod VARCHAR(50) NOT NULL,
employeeId INT, employeeId INT NOT NULL,
storeId INT, storeId INT NOT NULL,
FOREIGN KEY (employeeId) REFERENCES employee(employeeId), FOREIGN KEY (employeeId) REFERENCES employee(employeeId),
FOREIGN KEY (storeId) REFERENCES storeLocation(storeId) FOREIGN KEY (storeId) REFERENCES storeLocation(storeId)
); );
CREATE TABLE saleItem ( CREATE TABLE saleItem (
saleItemId INT AUTO_INCREMENT PRIMARY KEY, saleItemId INT AUTO_INCREMENT PRIMARY KEY,
saleId INT, saleId INT NOT NULL,
prodId INT, prodId INT NOT NULL,
quantity INT, quantity INT NOT NULL,
unitPrice DECIMAL(10, 2), unitPrice DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (saleId) REFERENCES sale(saleId), FOREIGN KEY (saleId) REFERENCES sale(saleId),
FOREIGN KEY (prodId) REFERENCES product(prodId) FOREIGN KEY (prodId) REFERENCES product(prodId)
); );
CREATE TABLE activityLog ( CREATE TABLE activityLog (
logId INT AUTO_INCREMENT PRIMARY KEY, logId INT AUTO_INCREMENT PRIMARY KEY,
employeeId INT, employeeId INT NOT NULL,
activity TEXT, activity TEXT NOT NULL,
logTimestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, logTimestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (employeeId) REFERENCES employee(employeeId) FOREIGN KEY (employeeId) REFERENCES employee(employeeId)
); );
@@ -159,78 +158,148 @@ CREATE TABLE activityLog (
INSERT INTO storeLocation (storeName, address, phone, email) INSERT INTO storeLocation (storeName, address, phone, email)
VALUES VALUES
('Downtown Branch', '123 Main St', '123-456-7890', 'downtown@petshop.com'), ('Downtown Branch', '123 Main St', '123-456-7890', 'downtown@petshop.com'),
('North Branch', '456 North Ave', '987-654-3210', 'north@petshop.com'); ('North Branch', '456 North Ave', '987-654-3210', 'north@petshop.com'),
('West Side Store', '789 West Blvd', '555-123-4567', 'westside@petshop.com'),
('East End Shop', '321 East Road', '555-987-6543', 'eastend@petshop.com'),
('South Mall Location', '654 South Plaza', '555-246-8135', 'southmall@petshop.com');
INSERT INTO employee (firstName, lastName, email, phone, role, isActive) INSERT INTO employee (firstName, lastName, email, phone, role, isActive)
VALUES VALUES
('John', 'Doe', 'john@petshop.com', '111-222-3333', 'Manager', TRUE), ('John', 'Doe', 'john@petshop.com', '111-222-3333', 'Manager', TRUE),
('Sara', 'Smith', 'sara@petshop.com', '444-555-6666', 'Staff', TRUE); ('Sara', 'Smith', 'sara@petshop.com', '444-555-6666', 'Staff', TRUE),
('Michael', 'Johnson', 'michael@petshop.com', '222-333-4444', 'Groomer', TRUE),
('Lisa', 'Williams', 'lisa@petshop.com', '333-444-5555', 'Staff', TRUE),
('David', 'Brown', 'david@petshop.com', '555-666-7777', 'Veterinarian', TRUE),
('Emma', 'Davis', 'emma@petshop.com', '666-777-8888', 'Manager', FALSE);
INSERT INTO employeeStore (employeeId, storeId) INSERT INTO employeeStore (employeeId, storeId)
VALUES VALUES
(1, 1), (1, 1),
(2, 1), (2, 1),
(2, 2); (2, 2),
(3, 2),
(4, 3),
(5, 1),
(5, 4),
(6, 5);
INSERT INTO customer (firstName, lastName, email, phone) INSERT INTO customer (firstName, lastName, email, phone)
VALUES VALUES
('Alex', 'Brown', 'alex@gmail.com', '777-888-9999'), ('Alex', 'Brown', 'alex@gmail.com', '777-888-9999'),
('Emily', 'Clark', 'emily@gmail.com', '666-555-4444'); ('Emily', 'Clark', 'emily@gmail.com', '666-555-4444'),
('James', 'Wilson', 'james@gmail.com', '888-999-0000'),
('Olivia', 'Martinez', 'olivia@gmail.com', '999-000-1111'),
('William', 'Anderson', 'william@gmail.com', '000-111-2222'),
('Sophia', 'Taylor', 'sophia@gmail.com', '111-222-3333');
INSERT INTO pet (petName, petSpecies, petBreed, petAge, petStatus, petPrice) INSERT INTO pet (petName, petSpecies, petBreed, petAge, petStatus, petPrice)
VALUES VALUES
('Buddy', 'Dog', 'Labrador', 2, 'Available', 500.00), ('Buddy', 'Dog', 'Labrador', 2, 'Available', 500.00),
('Milo', 'Cat', 'Persian', 1, 'Available', 300.00); ('Milo', 'Cat', 'Persian', 1, 'Available', 300.00),
('Charlie', 'Dog', 'Golden Retriever', 3, 'Available', 550.00),
('Luna', 'Cat', 'Siamese', 2, 'Adopted', 350.00),
('Max', 'Dog', 'Beagle', 1, 'Available', 450.00),
('Bella', 'Cat', 'Maine Coon', 4, 'Available', 400.00);
INSERT INTO adoption (petId, customerId, adoptionDate, adoptionStatus) INSERT INTO adoption (petId, customerId, adoptionDate, adoptionStatus)
VALUES VALUES
(1, 1, '2026-01-15', 'Completed'); (1, 1, '2026-01-15', 'Completed'),
(4, 3, '2026-01-20', 'Completed'),
(2, 2, '2026-01-25', 'Pending'),
(5, 4, '2026-02-01', 'Completed'),
(6, 5, '2026-02-02', 'Pending');
INSERT INTO supplier (supCompany, supContactFirstName, supContactLastName, supEmail, supPhone) INSERT INTO supplier (supCompany, supContactFirstName, supContactLastName, supEmail, supPhone)
VALUES VALUES
('PetFood Inc', 'Robert', 'King', 'contact@petfood.com', '888-111-2222'); ('PetFood Inc', 'Robert', 'King', 'contact@petfood.com', '888-111-2222'),
('Toy World', 'Jennifer', 'Lee', 'sales@toyworld.com', '888-222-3333'),
('Pet Supplies Co', 'Kevin', 'White', 'info@petsupplies.com', '888-333-4444'),
('Animal Care Products', 'Nancy', 'Green', 'orders@animalcare.com', '888-444-5555'),
('Premium Pet Goods', 'Tom', 'Black', 'support@premiumpet.com', '888-555-6666');
INSERT INTO category (categoryName, categoryType) INSERT INTO category (categoryName, categoryType)
VALUES VALUES
('Dog Food', 'Product'), ('Dog Food', 'Product'),
('Cat Toys', 'Product'); ('Cat Toys', 'Product'),
('Bird Supplies', 'Product'),
('Aquarium', 'Product'),
('Small Animals', 'Product');
INSERT INTO product (prodName, prodSku, prodPrice, categoryId, prodDesc) INSERT INTO product (prodName, prodPrice, categoryId, prodDesc)
VALUES VALUES
('Premium Dog Food', 'DF001', 50.00, 1, 'High quality dog food'), ('Premium Dog Food', 50.00, 1, 'High quality dog food'),
('Cat Toy Ball', 'CT001', 10.00, 2, 'Colorful toy for cats'); ('Cat Toy Ball', 10.00, 2, 'Colorful toy for cats'),
('Bird Cage Large', 120.00, 3, 'Spacious bird cage'),
('Fish Tank 20 Gallon', 80.00, 4, 'Complete aquarium kit'),
('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)
VALUES VALUES
(1, 1), (1, 1),
(1, 2); (1, 2),
(2, 2),
(3, 3),
(3, 4),
(4, 5),
(5, 6),
(1, 6);
INSERT INTO inventory (prodId, quantity) INSERT INTO inventory (prodId, quantity)
VALUES VALUES
(1, 100), (1, 100),
(2, 200); (2, 200),
(3, 50),
(4, 30),
(5, 150),
(6, 75);
INSERT INTO service (serviceName, serviceDesc, serviceDuration, servicePrice) INSERT INTO service (serviceName, serviceDesc, serviceDuration, servicePrice)
VALUES VALUES
('Pet Grooming', 'Full grooming service', 60, 40.00); ('Pet Grooming', 'Full grooming service', 60, 40.00),
('Nail Trimming', 'Quick nail trim', 15, 10.00),
('Bath and Brush', 'Bathing and brushing service', 45, 30.00),
('Veterinary Checkup', 'Complete health examination', 30, 75.00),
('Teeth Cleaning', 'Professional dental cleaning', 90, 100.00);
INSERT INTO appointment (serviceId, customerId, appointmentDate, appointmentTime, appointmentStatus) INSERT INTO appointment (serviceId, customerId, appointmentDate, appointmentTime, appointmentStatus)
VALUES VALUES
(1, 2, '2026-02-01', '10:30:00', 'Booked'); (1, 2, '2026-02-01', '10:30:00', 'Booked'),
(2, 1, '2026-02-03', '14:00:00', 'Booked'),
(3, 3, '2026-02-05', '09:00:00', 'Completed'),
(4, 4, '2026-02-07', '11:30:00', 'Booked'),
(5, 5, '2026-02-10', '15:00:00', 'Cancelled');
INSERT INTO appointmentPet (appointmentId, petId) INSERT INTO appointmentPet (appointmentId, petId)
VALUES VALUES
(1, 2); (1, 2),
(2, 1),
(3, 3),
(4, 5),
(5, 6);
INSERT INTO sale (saleDate, totalAmount, paymentMethod, employeeId, storeId) INSERT INTO sale (saleDate, totalAmount, paymentMethod, employeeId, storeId)
VALUES VALUES
(NOW(), 60.00, 'Card', 2, 1); (NOW(), 60.00, 'Card', 2, 1),
('2026-01-28 10:30:00', 50.00, 'Cash', 1, 1),
('2026-01-29 14:15:00', 120.00, 'Card', 4, 3),
('2026-01-30 16:45:00', 80.00, 'Card', 2, 2),
('2026-02-01 11:20:00', 150.00, 'Cash', 5, 4);
INSERT INTO saleItem (saleId, prodId, quantity, unitPrice) INSERT INTO saleItem (saleId, prodId, quantity, unitPrice)
VALUES VALUES
(1, 2, 2, 10.00); (1, 2, 2, 10.00),
(2, 1, 1, 50.00),
(3, 3, 1, 120.00),
(4, 4, 1, 80.00),
(5, 6, 6, 25.00),
(2, 2, 3, 10.00);
INSERT INTO activityLog (employeeId, activity) INSERT INTO activityLog (employeeId, activity)
VALUES VALUES
(1, 'Created new sale'), (1, 'Created new sale'),
(2, 'Booked appointment'); (2, 'Booked appointment'),
(3, 'Completed grooming service'),
(4, 'Processed inventory order'),
(5, 'Conducted health checkup'),
(1, 'Updated customer information');

View File

@@ -11,17 +11,15 @@ import org.example.petshopdesktop.models.Product;
public class ProductDTO { public class ProductDTO {
private SimpleIntegerProperty prodId; private SimpleIntegerProperty prodId;
private SimpleStringProperty prodName; private SimpleStringProperty prodName;
private SimpleStringProperty prodSku;
private SimpleDoubleProperty prodPrice; private SimpleDoubleProperty prodPrice;
private SimpleIntegerProperty categoryId; //used for edit and delete private SimpleIntegerProperty categoryId; //used for edit and delete
private SimpleStringProperty categoryName; private SimpleStringProperty categoryName;
private SimpleStringProperty prodDesc; private SimpleStringProperty prodDesc;
//constructor //constructor
public ProductDTO(int prodId, String prodName, String prodSku, double prodPrice, int categoryId, String categoryName, String prodDesc) { public ProductDTO(int prodId, String prodName, double prodPrice, int categoryId, String categoryName, String prodDesc) {
this.prodId = new SimpleIntegerProperty(prodId); this.prodId = new SimpleIntegerProperty(prodId);
this.prodName = new SimpleStringProperty(prodName); this.prodName = new SimpleStringProperty(prodName);
this.prodSku = new SimpleStringProperty(prodSku);
this.prodPrice = new SimpleDoubleProperty(prodPrice); this.prodPrice = new SimpleDoubleProperty(prodPrice);
this.categoryId = new SimpleIntegerProperty(categoryId); this.categoryId = new SimpleIntegerProperty(categoryId);
this.categoryName = new SimpleStringProperty(categoryName); this.categoryName = new SimpleStringProperty(categoryName);
@@ -53,18 +51,6 @@ public class ProductDTO {
this.prodName.set(prodName); this.prodName.set(prodName);
} }
public String getProdSku() {
return prodSku.get();
}
public SimpleStringProperty prodSkuProperty() {
return prodSku;
}
public void setProdSku(String prodSku) {
this.prodSku.set(prodSku);
}
public double getProdPrice() { public double getProdPrice() {
return prodPrice.get(); return prodPrice.get();
} }
@@ -121,7 +107,6 @@ public class ProductDTO {
Product product = new Product( Product product = new Product(
getProdId(), getProdId(),
getProdName(), getProdName(),
getProdSku(),
getProdPrice(), getProdPrice(),
getCategoryId(), getCategoryId(),
getProdDesc() getProdDesc()

View File

@@ -0,0 +1,131 @@
package org.example.petshopdesktop;
public class Validator {
/**
* Checks if string is not empty
* @param value string to check
* @param name name of the input
* @return error msg if string is not empty, otherwise empty
*/
public static String isPresent(String value, String name){
String msg =""; //OK so far
if(value.isEmpty() || name.isBlank()){
msg += name + " is required. \n";
}
return msg;
}
/**
* Checks if the input is a non-negative double
* @param value input of string
* @param name name of input
* @return error msg if input is not a number or negative, otherwise empty
*/
public static String isNonNegativeDouble(String value, String name){
String msg =""; //OK so far
double result;
try{
result = Double.parseDouble(value);
if (result < 0){
msg += name + " must be greater than or equal 0. \n";
}
}
catch (NumberFormatException e){
msg += name + " must be a number.\n";
}
return msg;
}
/**
* Checks if the input is a double in 2 different range
* @param value input of string
* @param name name of inpt
* @param minValue min value of range
* @param maxValue max value of range
* @return error msg if input is out of range, otherwise empty
*/
public static String isDoubleInRange(String value, String name, double minValue, double maxValue){
String msg =""; //OK so far
double result;
try{
result = Double.parseDouble(value);
if (result < minValue || result > maxValue){
msg += name + " must be between " + minValue + " and " + maxValue + "\n";
}
}
catch (NumberFormatException e){
msg += name + " must be a number.\n";
}
return msg;
}
/**
* Checks if the input is a non-negative integer
* @param value input of string
* @param name name of input
* @return error msg if input is not a number or negative, otherwise empty
*/
public static String isNonNegativeInteger(String value, String name){
String msg =""; //OK so far
int result;
try{
result = Integer.parseInt(value);
if (result < 0){
msg += name + " must be greater than or equal 0. \n";
}
}
catch (NumberFormatException e){
msg += name + " must be a whole number.\n";
}
return msg;
}
/**
* check if the string is a given amount of characters or fewer
* @param value input of string
* @param name name of input
* @return error msg if input is more than given characters length
*/
public static String isLessThanVarChars(String value, String name, int length){
String msg ="";
if (value.length() > length){
msg += name + " must be less than " + length + " characters. \n";
}
return msg;
}
/**
* Checks if the input is a valid email format
* @param value input of string
* @param name name of input
* @return error msg if input is not a valid email format, otherwise empty
*/
public static String isValidEmail(String value, String name){
String msg = ""; //OK so far
// Email regex
String regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
if (!value.matches(regex)){
msg += name + " is not in a valid format. \n";
}
return msg;
}
/**
* Checks if the input is a valid phone number in format XXX-XXX-XXXX
* @param value input of string
* @param name name of input
* @return error msg if input is not in valid phone format, otherwise empty
*/
public static String isValidPhoneNumber(String value, String name){
String msg = ""; //OK so far
// Phone regex
String regex = "^\\d{3}-\\d{3}-\\d{4}$";
if (!value.matches(regex)){
msg += name + " must be in format XXX-XXX-XXXX. \n";
}
return msg;
}
}

View File

@@ -4,16 +4,24 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList; 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.scene.control.cell.PropertyValueFactory;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.example.petshopdesktop.DTOs.ProductDTO; import org.example.petshopdesktop.DTOs.ProductDTO;
import org.example.petshopdesktop.controllers.dialogcontrollers.ProductDialogController;
import org.example.petshopdesktop.controllers.dialogcontrollers.SupplierDialogController;
import org.example.petshopdesktop.database.ProductDB; import org.example.petshopdesktop.database.ProductDB;
import org.example.petshopdesktop.database.SupplierDB;
import org.example.petshopdesktop.models.Product; import org.example.petshopdesktop.models.Product;
import org.example.petshopdesktop.models.Supplier;
import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.Optional;
/** /**
* The controller for any operations in the products view * The controller for any operations in the products view
@@ -44,9 +52,6 @@ public class ProductController {
@FXML @FXML
private TableColumn<ProductDTO, Double> colProductPrice; private TableColumn<ProductDTO, Double> colProductPrice;
@FXML
private TableColumn<ProductDTO, String> colProductSKU;
@FXML @FXML
private TableView<ProductDTO> tvProducts; private TableView<ProductDTO> tvProducts;
@@ -68,19 +73,31 @@ public class ProductController {
//set up table columns //set up table columns
colProductId.setCellValueFactory(new PropertyValueFactory<ProductDTO,Integer>("prodId")); colProductId.setCellValueFactory(new PropertyValueFactory<ProductDTO,Integer>("prodId"));
colProductName.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("prodName")); colProductName.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("prodName"));
colProductSKU.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("prodSku"));
colProductPrice.setCellValueFactory(new PropertyValueFactory<ProductDTO,Double>("prodPrice")); colProductPrice.setCellValueFactory(new PropertyValueFactory<ProductDTO,Double>("prodPrice"));
colProductCategory.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("categoryName")); colProductCategory.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("categoryName"));
colProductDesc.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("prodDesc")); colProductDesc.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("prodDesc"));
displayProducts(); displayProduct();
//EventListener to Enable buttons when a row is selected
tvProducts.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) -> {
displayFilteredProduct(newValue);
});
} }
/** /**
* Display the productDTO to table view * Display the productDTO to table view
*/ */
private void displayProducts(){ private void displayProduct(){
//Erase old content //Erase old content
data.clear(); data.clear();
@@ -95,20 +112,148 @@ public class ProductController {
tvProducts.setItems(data); tvProducts.setItems(data);
} }
/**
* open a new dialog for adding a product
* @param event
*/
@FXML @FXML
void btnAddClicked(ActionEvent event) { void btnAddClicked(ActionEvent event) {
mode = "Add";
openDialog(null,mode);
} }
/**
* Delete a selected product 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 product
ProductDTO selectedProduct = tvProducts.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?");
Optional<ButtonType> result = question.showAndWait(); //show alert and wait for response
//if confirmed,start deletion
if (result.isPresent() && result.get() == ButtonType.OK) {
int prodId = selectedProduct.getProdId();
//try deleting
try{
numRows = ProductDB.deleteProduct(prodId);
}
catch (SQLIntegrityConstraintViolationException e){
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setHeaderText("Database Operation Error");
alert.setContentText("Delete failed\n" +
"the selected product 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
displayProduct();
btnDelete.setDisable(true);
btnEdit.setDisable(true);
txtSearch.setText("");
}
}
} }
/**
* Open a new dialog for editing a product
* @param event click event for button
*/
@FXML @FXML
void btnEditClicked(ActionEvent event) { void btnEditClicked(ActionEvent event) {
//set selected product
ProductDTO selectedProduct = tvProducts.getSelectionModel().getSelectedItem();
if (selectedProduct != null) {
mode = "Edit";
openDialog(selectedProduct, mode);
}
}
/**
* Filter the table given the string from the searchbar
* @param filter word to filter table
*/
private void displayFilteredProduct(String filter){
data.clear();
try{
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
displayProduct(); //If search bar is empty just display everything
}
else{
//Filter the using the keyword
data = ProductDB.getFilteredProductDTOs(filter);
tvProducts.setItems(data);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Function to open the new Dialog for edit or adding
* depending on the mode given
* @param product the product entity for editing, null if adding
* @param mode the mode the dialog should be in
*/
private void openDialog(ProductDTO product, String mode){
//Get new view
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/product-dialog-view.fxml"));
Scene scene = null;
try{
scene = new Scene(fxmlLoader.load());
} catch (IOException e) {
throw new RuntimeException(e);
}
ProductDialogController 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.displayProductDetails(product);
}
Stage dialogStage = new Stage();
dialogStage.initModality(Modality.APPLICATION_MODAL); //make it modal
if(mode.equals("Add")){
dialogStage.setTitle("Add Product");
}
else {
dialogStage.setTitle("Edit Product");
}
dialogStage.setScene(scene);
dialogStage.showAndWait();
//When dialog closes update table view and disable edit and delete buttons, and reset search bar
displayProduct();
btnDelete.setDisable(true);
btnEdit.setDisable(true);
txtSearch.setText("");
} }
} }

View File

@@ -74,7 +74,7 @@ public class SupplierController {
displaySupplier(); displaySupplier();
// Enable buttons when a row is selected //EventListener to Enable buttons when a row is selected
tvSuppliers.getSelectionModel().selectedItemProperty().addListener( tvSuppliers.getSelectionModel().selectedItemProperty().addListener(
(observable, oldValue, newValue) -> { (observable, oldValue, newValue) -> {
btnEdit.setDisable(false); btnEdit.setDisable(false);
@@ -82,6 +82,11 @@ public class SupplierController {
} }
); );
//EventListener to search when text is changed on searchbar
txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
displayFilteredSupplier(newValue);
});
} }
@@ -100,10 +105,30 @@ public class SupplierController {
tvSuppliers.setItems(data); tvSuppliers.setItems(data);
} }
/**
* Filter the table given the string from the searchbar
* @param filter word to filter table
*/
private void displayFilteredSupplier(String filter){
data.clear();
try{
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
displaySupplier(); //If search bar is empty just display everything
}
else{
//Filter the using the keyword
data = SupplierDB.getFilteredSuppliers(filter);
tvSuppliers.setItems(data);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/** /**
* open a new dialog for adding a supplier * open a new dialog for adding a supplier
* @param event * @param event click event for button
*/ */
@FXML @FXML
void btnAddClicked(ActionEvent event) { void btnAddClicked(ActionEvent event) {
@@ -112,8 +137,8 @@ public class SupplierController {
} }
/** /**
* * Delete a selected supplier when delete is clicked
* @param event * @param event click event for button
*/ */
@FXML @FXML
void btnDeleteClicked(ActionEvent event) { void btnDeleteClicked(ActionEvent event) {
@@ -162,13 +187,16 @@ public class SupplierController {
alert.showAndWait(); alert.showAndWait();
//refresh display //refresh display
displaySupplier(); displaySupplier();
btnDelete.setDisable(true);
btnEdit.setDisable(true);
txtSearch.setText("");
} }
} }
} }
/** /**
* Open a new dialog for editing a supplier * Open a new dialog for editing a supplier
* @param event click event * @param event click event for button
*/ */
@FXML @FXML
void btnEditClicked(ActionEvent event) { void btnEditClicked(ActionEvent event) {
@@ -184,12 +212,12 @@ public class SupplierController {
/** /**
* Function to open the new Dialog for edit or adding * Function to open the new Dialog for edit or adding
* depending on the mode given * depending on the mode given
* @param supplier the supplier entity fo editing, null if adding * @param supplier the supplier entity for editing, null if adding
* @param mode the mode the dialog should be in * @param mode the mode the dialog should be in
*/ */
private void openDialog(Supplier supplier, String mode){ private void openDialog(Supplier supplier, String mode){
//Get new view //Get new view
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml")); //CHECK FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml"));
Scene scene = null; Scene scene = null;
try{ try{
scene = new Scene(fxmlLoader.load()); scene = new Scene(fxmlLoader.load());
@@ -215,10 +243,11 @@ public class SupplierController {
dialogStage.setScene(scene); dialogStage.setScene(scene);
dialogStage.showAndWait(); dialogStage.showAndWait();
//When dialog closes update table view and disable edit and delete buttons //When dialog closes update table view and disable edit and delete buttons, and reset search bar
displaySupplier(); displaySupplier();
btnDelete.setDisable(true); btnDelete.setDisable(true);
btnEdit.setDisable(true); btnEdit.setDisable(true);
txtSearch.setText("");
} }
} }

View File

@@ -0,0 +1,211 @@
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.ProductDTO;
import org.example.petshopdesktop.Validator;
import org.example.petshopdesktop.database.CategoryDB;
import org.example.petshopdesktop.database.ProductDB;
import org.example.petshopdesktop.models.Category;
import org.example.petshopdesktop.models.Product;
import org.example.petshopdesktop.models.Supplier;
import java.sql.SQLException;
import java.util.ArrayList;
public class ProductDialogController {
@FXML
private Button btnCancel;
@FXML
private Button btnSave;
@FXML
private ComboBox<Category> cbProdCategory;
@FXML
private Label lblMode;
@FXML
private Label lblProdId;
@FXML
private TextField txtProdDesc;
@FXML
private TextField txtProdName;
@FXML
private TextField txtProdPrice;
private String mode = null;
/**
* Add event listeners to buttons when dialog loads
*/
@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 category
try {
//set up combobox
ObservableList<Category> categories = FXCollections.observableArrayList(); //empty list
categories = CategoryDB.getCategories();
cbProdCategory.setItems(categories);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
private void buttonSaveClicked(MouseEvent mouseEvent) {
int numRow = 0; //how many rows affected
String errorMsg = ""; //error message for validation
//Check Validation (input required)
errorMsg += Validator.isPresent(txtProdName.getText(), "Product Name");
errorMsg += Validator.isPresent(txtProdPrice.getText(), "Product Price");
if (cbProdCategory.getSelectionModel().getSelectedItem() == null) {
errorMsg += "Category is required \n";
}
//Check validation (length size)
errorMsg += Validator.isLessThanVarChars(txtProdName.getText(), "Product Name", 100);
errorMsg += Validator.isLessThanVarChars(txtProdDesc.getText(), "Description", 100);
errorMsg += Validator.isLessThanVarChars(txtProdPrice.getText(), "Product Price", 12);
//Check Validation (format)
errorMsg += Validator.isNonNegativeDouble(txtProdPrice.getText(), "Product Price");
if (errorMsg.isEmpty()) { //no validation errors detected
Product product = collectProduct(); //get product info
if (mode.equals("Add")){ //add mode
try{
numRow = ProductDB.insertProduct(product);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
else { //edit
try{
numRow = ProductDB.updateProduct(product.getProdId(),product);
} 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();
}
}
/**
* Collect the product info
* @return product info with the id or the new product
*/
private Product collectProduct(){
int prodId = 0;
Product product = null;
if(lblProdId.isVisible()){ //Edit mode
//get product id from lblId (split the string so we only get the int)
prodId = Integer.parseInt(lblProdId.getText().split(": ")[1]);
}
product = new Product(
prodId,
txtProdName.getText(),
Double.parseDouble(txtProdPrice.getText()),
cbProdCategory.getSelectionModel().getSelectedItem().getCategoryId(),
txtProdDesc.getText()
);
return product;
}
/**
* Display the product data in text fields and combobox
* @param product the supplier entity containing data to display
*/
public void displayProductDetails(ProductDTO product){
if (product!=null){
lblProdId.setText("ID: " + product.getProdId());
txtProdName.setText(product.getProdName());
txtProdDesc.setText(product.getProdDesc());
txtProdPrice.setText(product.getProdPrice() + "");
//get the right combobox selection
for (Category category : cbProdCategory.getItems()) {
if(category.getCategoryId() == product.getCategoryId()){
cbProdCategory.setValue(category);
}
}
}
}
/**
* 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 to for the dialog
*/
public void setMode(String mode) {
this.mode = mode;
lblMode.setText(mode + " Product");
if(mode.equals("Add")) {
lblProdId.setVisible(false);
}
else if(mode.equals("Edit")) {
lblProdId.setVisible(true);
}
}
}

View File

@@ -9,6 +9,7 @@ import javafx.scene.control.Label;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent; import javafx.scene.input.MouseEvent;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.example.petshopdesktop.Validator;
import org.example.petshopdesktop.database.SupplierDB; import org.example.petshopdesktop.database.SupplierDB;
import org.example.petshopdesktop.models.Supplier; import org.example.petshopdesktop.models.Supplier;
@@ -45,6 +46,9 @@ public class SupplierDialogController {
private String mode = null; private String mode = null;
/**
* Add event listeners to buttons when dialog loads
*/
@FXML @FXML
void initialize() { void initialize() {
//Set up mouse handlers for buttons //Set up mouse handlers for buttons
@@ -67,7 +71,22 @@ public class SupplierDialogController {
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
//TODO: Import validation class and validate text fields here //Check validation (input required)
errorMsg += Validator.isPresent(txtCompanyName.getText(), "Company Name");
errorMsg += Validator.isPresent(txtContactFirstName.getText(), "Contact First Name");
errorMsg += Validator.isPresent(txtContactLastName.getText(), "Contact Last Name");
errorMsg += Validator.isPresent(txtEmail.getText(), "Email Address");
errorMsg += Validator.isPresent(txtPhone.getText(), "Phone Number");
//Check validation (Length size)
errorMsg += Validator.isLessThanVarChars(txtCompanyName.getText(),"Company Name", 100);
errorMsg += Validator.isLessThanVarChars(txtContactFirstName.getText(), "Contact First Name", 50);
errorMsg += Validator.isLessThanVarChars(txtContactLastName.getText(), "Contact Last Name", 50);
errorMsg += Validator.isLessThanVarChars(txtEmail.getText(), "Email Address", 100);
//Check validation (format)
errorMsg += Validator.isValidEmail(txtEmail.getText(), "Email Address");
errorMsg += Validator.isValidPhoneNumber(txtPhone.getText(), "Phone Number");
if(errorMsg.isEmpty()){ //no validation errors detected if(errorMsg.isEmpty()){ //no validation errors detected
Supplier supplier = collectSupplier(); //get supplier info Supplier supplier = collectSupplier(); //get supplier info

View File

@@ -0,0 +1,41 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.models.Category;
import org.example.petshopdesktop.models.Product;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class CategoryDB {
/**
* gets all the category into an observable list
* @return a list of all the category
* @throws SQLException if failed to find categories in the database
*/
public static ObservableList<Category> getCategories() throws SQLException{
//Connect to the database
ObservableList<Category> categories = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
//Execute Query
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM category");
//While there is still data add categories to the list
while(rs.next()){
Category category = new Category(
rs.getInt(1),
rs.getString(2),
rs.getString(3));
categories.add(category);
}
//close connection and return categories
conn.close();
return categories;
}
}

View File

@@ -4,11 +4,9 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import org.example.petshopdesktop.DTOs.ProductDTO; import org.example.petshopdesktop.DTOs.ProductDTO;
import org.example.petshopdesktop.models.Product; import org.example.petshopdesktop.models.Product;
import org.example.petshopdesktop.models.Supplier;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*; import java.sql.*;
import java.util.Properties;
/** /**
* A class containing all the methods relating to CRUD on Products table * A class containing all the methods relating to CRUD on Products table
@@ -34,10 +32,9 @@ public class ProductDB {
Product product = new Product( Product product = new Product(
rs.getInt(1), rs.getInt(1),
rs.getString(2), rs.getString(2),
rs.getString(3), rs.getDouble(3),
rs.getDouble(4), rs.getInt(4),
rs.getInt(5), rs.getString(5));
rs.getString(6));
products.add(product); products.add(product);
} }
@@ -58,7 +55,7 @@ public class ProductDB {
//Execute Query //Execute Query
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
String sql = "SELECT p.prodId, p.prodName, p.prodSku, p.prodPrice, p.categoryId, c.categoryName, p.prodDesc " + String sql = "SELECT p.prodId, p.prodName, p.prodPrice, p.categoryId, c.categoryName, p.prodDesc " +
"FROM product p " + "FROM product p " +
"LEFT JOIN category c ON p.categoryId = c.categoryId"; "LEFT JOIN category c ON p.categoryId = c.categoryId";
ResultSet rs = stmt.executeQuery(sql); ResultSet rs = stmt.executeQuery(sql);
@@ -68,11 +65,10 @@ public class ProductDB {
ProductDTO product = new ProductDTO( ProductDTO product = new ProductDTO(
rs.getInt(1), rs.getInt(1),
rs.getString(2), rs.getString(2),
rs.getString(3), rs.getDouble(3),
rs.getDouble(4), rs.getInt(4),
rs.getInt(5), rs.getString(5),
rs.getString(6), rs.getString(6));
rs.getString(7));
products.add(product); products.add(product);
} }
@@ -80,4 +76,137 @@ public class ProductDB {
conn.close(); conn.close();
return products; return products;
} }
/**
* Inserts a new product to the database
* @param product product entity to be inserted
* @return number of rows affected in the database
* @throws SQLException if insertion failed
*/
public static int insertProduct(Product product) throws SQLException {
int numRows = 0;
Connection conn = ConnectionDB.getConnection();
String sql = "INSERT INTO product (prodId, prodName, prodPrice, categoryId, prodDesc)" +
"VALUES (?, ?, ?, ?, ?)";
//These are the values from product to put into the query above
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, product.getProdId());
stmt.setString(2, product.getProdName());
stmt.setDouble(3, product.getProdPrice());
stmt.setInt(4, product.getCategoryId());
stmt.setString(5, product.getProdDesc());
//update the number of rows affected, return and close connection
numRows = stmt.executeUpdate();
conn.close();
return numRows;
}
/**
* Update an existing product to the database
* @param prodId id of product
* @param product new product data
* @return number of rows affected in the database
* @throws SQLException if update failed
*/
public static int updateProduct(int prodId, Product product) throws SQLException {
int numRows = 0;
Connection conn = ConnectionDB.getConnection();
String sql = "UPDATE product SET " +
" prodName = ?, " +
" prodPrice = ?, " +
" categoryId = ?, " +
" prodDesc = ? " +
" WHERE prodId = ?";
//update values to query
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, product.getProdName());
stmt.setDouble(2, product.getProdPrice());
stmt.setInt(3, product.getCategoryId());
stmt.setString(4, product.getProdDesc());
stmt.setInt(5, prodId);
//Update rows and close connection
numRows = stmt.executeUpdate();
conn.close();
return numRows;
}
/**
* Delete a product from the database
* @param prodId product id to be deleted
* @return number of rows affected in the database
* @throws SQLException if delete failed
*/
public static int deleteProduct(int prodId) throws SQLException {
int numRows = 0;
Connection conn = ConnectionDB.getConnection();
String sql = "DELETE FROM product WHERE prodId = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, prodId);
//close connection and update rows affected
numRows = stmt.executeUpdate();
conn.close();
return numRows;
}
/**
* Gets a list of productDTOs that is filtered by a given string
* @param filter the word to filter table
* @return ObservableList of ProductDTOs with the filtered data
* @throws SQLException if getting products failed
*/
public static ObservableList<ProductDTO> getFilteredProductDTOs(String filter) throws SQLException {
//Connect to the database
ObservableList<ProductDTO> products = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
//Get SQL query for filtered word
String sql =
"SELECT p.prodId, p.prodName, p.prodPrice, p.categoryId, c.categoryName, p.prodDesc" +
" FROM product p" +
" LEFT JOIN category c ON p.categoryId = c.categoryId" +
" WHERE " +
"prodName LIKE ? OR " +
"prodPrice LIKE ? OR " +
"categoryName LIKE ? OR " +
"prodDesc LIKE ?";
//add % wildcard so the 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);
stmt.setString(4, filteredString);
//execute query
ResultSet rs = stmt.executeQuery();
//While there is still data add products to the list
while(rs.next()){
ProductDTO product = new ProductDTO(
rs.getInt(1),
rs.getString(2),
rs.getDouble(3),
rs.getInt(4),
rs.getString(5),
rs.getString(6));
products.add(product);
}
conn.close();
return products;
}
} }

View File

@@ -26,7 +26,7 @@ public class SupplierDB {
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM supplier"); ResultSet rs = stmt.executeQuery("SELECT * FROM supplier");
//While there is still data add products to the list //While there is still data add suppliers to the list
while(rs.next()){ while(rs.next()){
Supplier supplier = new Supplier( Supplier supplier = new Supplier(
rs.getInt(1), rs.getInt(1),
@@ -127,4 +127,54 @@ public class SupplierDB {
return numRows; return numRows;
} }
/**
* Gets a list of Suppliers that is filtered by a given string
* @param filter the word to filter table
* @return ObservableList of suppliers with the filtered data
* @throws SQLException if getting suppliers failed
*/
public static ObservableList<Supplier> getFilteredSuppliers(String filter) throws SQLException {
//Connect to the database
ObservableList<Supplier> suppliers = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
//Get SQL query for filtered word
String sql =
"SELECT * FROM supplier" +
" WHERE " +
"supCompany LIKE ? OR " +
"supContactFirstName LIKE ? OR " +
"supContactLastName LIKE ? OR " +
"supEmail LIKE ? OR " +
"supPhone LIKE ?";
//add % wildcard so the 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);
stmt.setString(4, filteredString);
stmt.setString(5, filteredString);
//execute query
ResultSet rs = stmt.executeQuery();
//While there is still data add suppliers to the list
while(rs.next()){
Supplier supplier = new Supplier(
rs.getInt(1),
rs.getString(2),
rs.getString(3),
rs.getString(4),
rs.getString(5),
rs.getString(6));
suppliers.add(supplier);
}
conn.close();
return suppliers;
}
} }

View File

@@ -0,0 +1,59 @@
package org.example.petshopdesktop.models;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
public class Category {
private SimpleIntegerProperty categoryId;
private SimpleStringProperty categoryName;
private SimpleStringProperty categoryType;
//Constrctor
public Category(int categoryId, String categoryName, String categoryType) {
this.categoryId = new SimpleIntegerProperty(categoryId);
this.categoryName = new SimpleStringProperty(categoryName);
this.categoryType = new SimpleStringProperty(categoryType);
}
//getters and setters
public int getCategoryId() {
return categoryId.get();
}
public SimpleIntegerProperty categoryIdProperty() {
return categoryId;
}
public void setCategoryId(int categoryId) {
this.categoryId.set(categoryId);
}
public String getCategoryName() {
return categoryName.get();
}
public SimpleStringProperty categoryNameProperty() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName.set(categoryName);
}
public String getCategoryType() {
return categoryType.get();
}
public SimpleStringProperty categoryTypeProperty() {
return categoryType;
}
public void setCategoryType(String categoryType) {
this.categoryType.set(categoryType);
}
@Override
public String toString() {
return getCategoryName();
}
}

View File

@@ -10,16 +10,14 @@ import javafx.beans.property.SimpleStringProperty;
public class Product { public class Product {
private SimpleIntegerProperty prodId; private SimpleIntegerProperty prodId;
private SimpleStringProperty prodName; private SimpleStringProperty prodName;
private SimpleStringProperty prodSku;
private SimpleDoubleProperty prodPrice; private SimpleDoubleProperty prodPrice;
private SimpleIntegerProperty categoryId; private SimpleIntegerProperty categoryId;
private SimpleStringProperty prodDesc; private SimpleStringProperty prodDesc;
//constructor //constructor
public Product(int prodId, String prodName, String prodSku, double prodPrice, int categoryId, String prodDesc) { public Product(int prodId, String prodName, double prodPrice, int categoryId, String prodDesc) {
this.prodId = new SimpleIntegerProperty(prodId); this.prodId = new SimpleIntegerProperty(prodId);
this.prodName = new SimpleStringProperty(prodName); this.prodName = new SimpleStringProperty(prodName);
this.prodSku = new SimpleStringProperty(prodSku);
this.prodPrice = new SimpleDoubleProperty(prodPrice); this.prodPrice = new SimpleDoubleProperty(prodPrice);
this.categoryId = new SimpleIntegerProperty(categoryId); this.categoryId = new SimpleIntegerProperty(categoryId);
this.prodDesc = new SimpleStringProperty(prodDesc); this.prodDesc = new SimpleStringProperty(prodDesc);
@@ -50,18 +48,6 @@ public class Product {
this.prodName.set(prodName); this.prodName.set(prodName);
} }
public String getProdSku() {
return prodSku.get();
}
public SimpleStringProperty prodSkuProperty() {
return prodSku;
}
public void setProdSku(String prodSku) {
this.prodSku.set(prodSku);
}
public double getProdPrice() { public double getProdPrice() {
return prodPrice.get(); return prodPrice.get();
} }

View File

@@ -0,0 +1,149 @@
<?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.ProductDialogController">
<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="79.0" prefWidth="246.0">
<children>
<Label fx:id="lblMode" prefHeight="54.0" prefWidth="246.0" text="Mode Product" textFill="WHITE">
<font>
<Font name="Comic Sans MS Bold" size="30.0" />
</font>
</Label>
<Label fx:id="lblProdId" 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="79.0" prefWidth="243.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 Name:" textFill="#2c3e50">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<TextField fx:id="txtProdName" 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">
<children>
<Label text="Product Price:" textFill="#2c3e50">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<TextField fx:id="txtProdPrice" 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.rowIndex="1">
<children>
<Label text="Category:" textFill="#2c3e50">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<ComboBox fx:id="cbProdCategory" 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" GridPane.rowIndex="1">
<children>
<Label text="Description:" textFill="#2c3e50">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<TextField fx:id="txtProdDesc" 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.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>

View File

@@ -68,11 +68,10 @@
<TableView fx:id="tvProducts" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS"> <TableView fx:id="tvProducts" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
<columns> <columns>
<TableColumn fx:id="colProductId" prefWidth="60.0" text="ID" /> <TableColumn fx:id="colProductId" prefWidth="60.0" text="ID" />
<TableColumn fx:id="colProductName" prefWidth="150.0" text="Name" /> <TableColumn fx:id="colProductName" prefWidth="170.85714721679688" text="Name" />
<TableColumn fx:id="colProductCategory" prefWidth="150.0" text="Category" /> <TableColumn fx:id="colProductCategory" prefWidth="195.4285888671875" text="Category" />
<TableColumn fx:id="colProductDesc" prefWidth="220.0" text="Description" /> <TableColumn fx:id="colProductDesc" prefWidth="210.28570556640625" text="Description" />
<TableColumn fx:id="colProductPrice" prefWidth="100.0" text="Price" /> <TableColumn fx:id="colProductPrice" prefWidth="115.4285888671875" text="Price" />
<TableColumn fx:id="colProductSKU" prefWidth="70.2857666015625" text="SKU" />
</columns> </columns>
</TableView> </TableView>
</children> </children>