diff --git a/Petstoredata.sql b/Petstoredata.sql
index 1b968e23..4d50c46a 100644
--- a/Petstoredata.sql
+++ b/Petstoredata.sql
@@ -146,6 +146,14 @@ CREATE TABLE saleItem (
FOREIGN KEY (prodId) REFERENCES product(prodId)
);
+CREATE TABLE purchaseOrder (
+ purchaseOrderId INT AUTO_INCREMENT PRIMARY KEY,
+ supId INT NOT NULL,
+ orderDate DATE NOT NULL,
+ status VARCHAR(50) NOT NULL,
+ FOREIGN KEY (supId) REFERENCES supplier(supId)
+);
+
CREATE TABLE activityLog (
logId INT AUTO_INCREMENT PRIMARY KEY,
employeeId INT NOT NULL,
@@ -281,20 +289,97 @@ VALUES
INSERT INTO sale (saleDate, totalAmount, paymentMethod, employeeId, storeId)
VALUES
-(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);
+-- January Sales
+('2026-01-05 09:15:00', 125.00, 'Card', 1, 1), -- Sale 1: Dog food + treats
+('2026-01-08 11:30:00', 200.00, 'Card', 2, 1), -- Sale 2: Bird cage + fish tank
+('2026-01-12 14:20:00', 60.00, 'Cash', 3, 2), -- Sale 3: Cat toys + hamster wheel
+('2026-01-15 10:45:00', 150.00, 'Debit', 1, 1), -- Sale 4: Dog food (bulk purchase)
+('2026-01-18 16:30:00', 80.00, 'Card', 4, 3), -- Sale 5: Fish tank
+('2026-01-22 13:15:00', 95.00, 'Cash', 2, 2), -- Sale 6: Mixed items
+('2026-01-25 15:40:00', 240.00, 'Card', 5, 4), -- Sale 7: Two bird cages
+('2026-01-28 10:30:00', 80.00, 'Cash', 1, 1), -- Sale 8: Dog food + cat toys
+-- February Sales
+('2026-02-01 09:00:00', 175.00, 'Card', 3, 3), -- Sale 9: Dog food + treats (bulk)
+('2026-02-03 11:20:00', 120.00, 'Card', 2, 1), -- Sale 10: Bird cage
+('2026-02-05 14:50:00', 45.00, 'Cash', 4, 2), -- Sale 11: Hamster wheel + cat toys
+('2026-02-08 16:15:00', 160.00, 'Debit', 1, 1), -- Sale 12: Fish tank + accessories
+('2026-02-10 10:25:00', 100.00, 'Card', 5, 4), -- Sale 13: Dog treats (bulk)
+('2026-02-12 13:45:00', 50.00, 'Cash', 2, 2), -- Sale 14: Dog food
+('2026-02-15 15:30:00', 85.00, 'Card', 3, 3), -- Sale 15: Mixed pet supplies
+('2026-02-18 11:10:00', 200.00, 'Card', 1, 1), -- Sale 16: Bird cage + hamster wheel
+('2026-02-20 14:35:00', 155.00, 'Debit', 4, 3), -- Sale 17: Fish tank + cat toys
+('2026-02-22 16:50:00', 75.00, 'Cash', 2, 1), -- Sale 18: Dog treats + toys
+('2026-02-24 10:15:00', 140.00, 'Card', 5, 4), -- Sale 19: Dog food + treats
+(NOW(), 95.00, 'Card', 1, 1); -- Sale 20: Recent sale (current timestamp)
INSERT INTO saleItem (saleId, prodId, quantity, unitPrice)
VALUES
-(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);
+-- Sale 1 items (Dog food + treats)
+(1, 1, 2, 50.00), -- 2x Premium Dog Food
+(1, 6, 1, 25.00), -- 1x Organic Dog Treats
+-- Sale 2 items (Bird cage + fish tank)
+(2, 3, 1, 120.00), -- 1x Bird Cage Large
+(2, 4, 1, 80.00), -- 1x Fish Tank 20 Gallon
+-- Sale 3 items (Cat toys + hamster wheel)
+(3, 2, 3, 10.00), -- 3x Cat Toy Ball
+(3, 5, 2, 15.00), -- 2x Hamster Wheel
+-- Sale 4 items (Dog food bulk)
+(4, 1, 3, 50.00), -- 3x Premium Dog Food
+-- Sale 5 items (Fish tank)
+(5, 4, 1, 80.00), -- 1x Fish Tank 20 Gallon
+-- Sale 6 items (Mixed)
+(6, 2, 4, 10.00), -- 4x Cat Toy Ball
+(6, 5, 1, 15.00), -- 1x Hamster Wheel
+(6, 6, 1, 25.00), -- 1x Organic Dog Treats
+(6, 1, 1, 50.00), -- 1x Premium Dog Food (partial - discount applied)
+-- Sale 7 items (Two bird cages)
+(7, 3, 2, 120.00), -- 2x Bird Cage Large
+-- Sale 8 items (Dog food + cat toys)
+(8, 1, 1, 50.00), -- 1x Premium Dog Food
+(8, 2, 3, 10.00), -- 3x Cat Toy Ball
+-- Sale 9 items (Dog food + treats bulk)
+(9, 1, 3, 50.00), -- 3x Premium Dog Food
+(9, 6, 1, 25.00), -- 1x Organic Dog Treats
+-- Sale 10 items (Bird cage)
+(10, 3, 1, 120.00), -- 1x Bird Cage Large
+-- Sale 11 items (Hamster wheel + cat toys)
+(11, 5, 1, 15.00), -- 1x Hamster Wheel
+(11, 2, 3, 10.00), -- 3x Cat Toy Ball
+-- Sale 12 items (Fish tank + accessories)
+(12, 4, 2, 80.00), -- 2x Fish Tank 20 Gallon
+-- Sale 13 items (Dog treats bulk)
+(13, 6, 4, 25.00), -- 4x Organic Dog Treats
+-- Sale 14 items (Dog food)
+(14, 1, 1, 50.00), -- 1x Premium Dog Food
+-- Sale 15 items (Mixed supplies)
+(15, 2, 2, 10.00), -- 2x Cat Toy Ball
+(15, 5, 1, 15.00), -- 1x Hamster Wheel
+(15, 6, 2, 25.00), -- 2x Organic Dog Treats
+-- Sale 16 items (Bird cage + hamster wheel)
+(16, 3, 1, 120.00), -- 1x Bird Cage Large
+(16, 4, 1, 80.00), -- 1x Fish Tank 20 Gallon
+-- Sale 17 items (Fish tank + cat toys)
+(17, 4, 1, 80.00), -- 1x Fish Tank 20 Gallon
+(17, 1, 1, 50.00), -- 1x Premium Dog Food
+(17, 6, 1, 25.00), -- 1x Organic Dog Treats
+-- Sale 18 items (Dog treats + toys)
+(18, 6, 2, 25.00), -- 2x Organic Dog Treats
+(18, 2, 2, 10.00), -- 2x Cat Toy Ball
+(18, 5, 1, 15.00), -- 1x Hamster Wheel
+-- Sale 19 items (Dog food + treats)
+(19, 1, 2, 50.00), -- 2x Premium Dog Food
+(19, 6, 2, 25.00), -- 2x Organic Dog Treats (discount applied)
+-- Sale 20 items (Recent sale)
+(20, 2, 5, 10.00), -- 5x Cat Toy Ball
+(20, 5, 3, 15.00); -- 3x Hamster Wheel
+
+INSERT INTO purchaseOrder (supId, orderDate, status)
+VALUES
+(1, '2025-01-15', 'Delivered'),
+(2, '2025-01-20', 'Pending'),
+(3, '2025-02-01', 'Delivered'),
+(4, '2025-02-10', 'In Transit'),
+(1, '2025-02-15', 'Pending');
INSERT INTO activityLog (employeeId, activity)
VALUES
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..b525f4b2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,48 @@
+# Pet Shop Desktop (JavaFX)
+
+Desktop pet shop management app built with JavaFX and MySQL.
+
+Made by **Group 2**, Shiv, Nikitha, Alex, Harkamal.
+
+## Requirements
+
+- IntelliJ IDEA (Community or Ultimate)
+- Java 17+
+- Maven (handled through IntelliJ)
+- Docker and Docker Compose (for the local MySQL container)
+
+## Database setup (IntelliJ)
+
+1. Open the project in IntelliJ.
+2. Open **View → Tool Windows → Services**.
+3. Add a Docker connection if needed, then open the **Docker** section in Services.
+4. Start the Compose stack from `docker-compose.yml` (Compose Up, or Start).
+5. Confirm the `mysql` service is running.
+
+The container uses `mysql:8.4`, creates the `Petstoredb` database, and imports `Petstoredata.sql`.
+
+## App configuration
+
+An example connection file is provided at `connectionpetstore.properties.example`. Copy it to `connectionpetstore.properties` and edit the values to match the local database setup.
+
+## Run the app (IntelliJ, Maven)
+
+1. Open **View → Tool Windows → Maven**.
+2. Click **Reload All Maven Projects** if the dependencies have not loaded yet.
+3. In the Maven tool window, expand **Plugins → javafx**.
+4. Double click **javafx:run**.
+
+Optional, run a clean first:
+- In the Maven tool window, expand **Lifecycle** and run **clean**.
+
+## Default accounts
+
+On first run, the app creates a `users` table (if missing) and seeds two accounts:
+
+- Admin: `admin` / `admin123`
+- Staff: `staff` / `staff123`
+
+## Notes
+
+- `connectionpetstore.properties` is gitignored so credentials are not committed.
+- If the app cannot connect to MySQL, confirm the Compose stack is running and MySQL is available.
diff --git a/pom.xml b/pom.xml
index 6da4edce..3c683c9e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
PetShopDesktop
UTF-8
- 25.0.2
+ 17.0.10
5.12.1
@@ -53,8 +53,7 @@
maven-compiler-plugin
3.13.0
- 23
- 23
+ 17
diff --git a/src/main/java/org/example/petshopdesktop/DTOs/SaleDTO.java b/src/main/java/org/example/petshopdesktop/DTOs/SaleDTO.java
new file mode 100644
index 00000000..a20bf5fd
--- /dev/null
+++ b/src/main/java/org/example/petshopdesktop/DTOs/SaleDTO.java
@@ -0,0 +1,93 @@
+package org.example.petshopdesktop.DTOs;
+
+import javafx.beans.property.*;
+
+public class SaleDTO {
+
+ private IntegerProperty saleId;
+ private StringProperty saleDate;
+ private StringProperty employeeName;
+ private StringProperty productName;
+ private IntegerProperty quantity;
+ private DoubleProperty unitPrice;
+ private DoubleProperty total;
+ private StringProperty paymentMethod;
+
+ public SaleDTO(int saleId, String saleDate, String employeeName, String productName,
+ int quantity, double unitPrice, double total, String paymentMethod) {
+ this.saleId = new SimpleIntegerProperty(saleId);
+ this.saleDate = new SimpleStringProperty(saleDate);
+ this.employeeName = new SimpleStringProperty(employeeName);
+ this.productName = new SimpleStringProperty(productName);
+ this.quantity = new SimpleIntegerProperty(quantity);
+ this.unitPrice = new SimpleDoubleProperty(unitPrice);
+ this.total = new SimpleDoubleProperty(total);
+ this.paymentMethod = new SimpleStringProperty(paymentMethod);
+ }
+
+ // Getters
+ public int getSaleId() {
+ return saleId.get();
+ }
+
+ public String getSaleDate() {
+ return saleDate.get();
+ }
+
+ public String getEmployeeName() {
+ return employeeName.get();
+ }
+
+ public String getProductName() {
+ return productName.get();
+ }
+
+ public int getQuantity() {
+ return quantity.get();
+ }
+
+ public double getUnitPrice() {
+ return unitPrice.get();
+ }
+
+ public double getTotal() {
+ return total.get();
+ }
+
+ public String getPaymentMethod() {
+ return paymentMethod.get();
+ }
+
+ // Properties
+ public IntegerProperty saleIdProperty() {
+ return saleId;
+ }
+
+ public StringProperty saleDateProperty() {
+ return saleDate;
+ }
+
+ public StringProperty employeeNameProperty() {
+ return employeeName;
+ }
+
+ public StringProperty productNameProperty() {
+ return productName;
+ }
+
+ public IntegerProperty quantityProperty() {
+ return quantity;
+ }
+
+ public DoubleProperty unitPriceProperty() {
+ return unitPrice;
+ }
+
+ public DoubleProperty totalProperty() {
+ return total;
+ }
+
+ public StringProperty paymentMethodProperty() {
+ return paymentMethod;
+ }
+}
diff --git a/src/main/java/org/example/petshopdesktop/Launcher.java b/src/main/java/org/example/petshopdesktop/Launcher.java
index 8b91cd9c..70456482 100644
--- a/src/main/java/org/example/petshopdesktop/Launcher.java
+++ b/src/main/java/org/example/petshopdesktop/Launcher.java
@@ -1,5 +1,3 @@
-//Initial commmit
-
package org.example.petshopdesktop;
import javafx.application.Application;
diff --git a/src/main/java/org/example/petshopdesktop/Validator.class b/src/main/java/org/example/petshopdesktop/Validator.class
new file mode 100644
index 00000000..b5653a2d
Binary files /dev/null and b/src/main/java/org/example/petshopdesktop/Validator.class differ
diff --git a/src/main/java/org/example/petshopdesktop/Validator.java b/src/main/java/org/example/petshopdesktop/Validator.java
index 29182e20..9c6f78a6 100644
--- a/src/main/java/org/example/petshopdesktop/Validator.java
+++ b/src/main/java/org/example/petshopdesktop/Validator.java
@@ -3,14 +3,14 @@ package org.example.petshopdesktop;
public class Validator {
/**
- * Checks if string is not empty
+ * Checks if string is not blank
* @param value string to check
* @param name name of the input
- * @return error msg if string is not empty, otherwise empty
+ * @return error msg if string is blank, otherwise empty
*/
public static String isPresent(String value, String name){
- String msg =""; //OK so far
- if(value.isEmpty() || name.isBlank()){
+ String msg = "";
+ if (value == null || value.isBlank()){
msg += name + " is required. \n";
}
return msg;
@@ -23,7 +23,7 @@ public class Validator {
* @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
+ String msg ="";
double result;
try{
result = Double.parseDouble(value);
@@ -40,13 +40,13 @@ public class Validator {
/**
* Checks if the input is a double in 2 different range
* @param value input of string
- * @param name name of inpt
+ * @param name name of input
* @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
+ String msg ="";
double result;
try{
result = Double.parseDouble(value);
@@ -67,7 +67,7 @@ public class Validator {
* @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
+ String msg ="";
int result;
try{
result = Integer.parseInt(value);
@@ -85,6 +85,7 @@ public class Validator {
* check if the string is a given amount of characters or fewer
* @param value input of string
* @param name name of input
+ * @param length max allowed length
* @return error msg if input is more than given characters length
*/
public static String isLessThanVarChars(String value, String name, int length){
@@ -102,8 +103,7 @@ public class Validator {
* @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 msg = "";
String regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
if (!value.matches(regex)){
@@ -119,8 +119,7 @@ public class Validator {
* @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 msg = "";
String regex = "^\\d{3}-\\d{3}-\\d{4}$";
if (!value.matches(regex)){
diff --git a/src/main/java/org/example/petshopdesktop/auth/Role.class b/src/main/java/org/example/petshopdesktop/auth/Role.class
new file mode 100644
index 00000000..b3d3c6cb
Binary files /dev/null and b/src/main/java/org/example/petshopdesktop/auth/Role.class differ
diff --git a/src/main/java/org/example/petshopdesktop/auth/Role.java b/src/main/java/org/example/petshopdesktop/auth/Role.java
index e631ddf7..64f38459 100644
--- a/src/main/java/org/example/petshopdesktop/auth/Role.java
+++ b/src/main/java/org/example/petshopdesktop/auth/Role.java
@@ -1,13 +1,6 @@
package org.example.petshopdesktop.auth;
-/*
-Petshop Desktop
-Purpose: Application role definitions used by session state and role based access control.
-*/
public enum Role {
- // Administrative access, includes system management screens.
ADMIN,
-
- // Staff access, limited to day to day operational screens.
STAFF
}
diff --git a/src/main/java/org/example/petshopdesktop/auth/UserSession.java b/src/main/java/org/example/petshopdesktop/auth/UserSession.java
index 2cc4538a..450fb3ff 100644
--- a/src/main/java/org/example/petshopdesktop/auth/UserSession.java
+++ b/src/main/java/org/example/petshopdesktop/auth/UserSession.java
@@ -1,24 +1,15 @@
package org.example.petshopdesktop.auth;
-/*
-Petshop Desktop
-Purpose: In memory session state for the authenticated user.
-Notes: Session is process local and cleared on logout or application restart.
-*/
public class UserSession {
- // Singleton instance used to share session state across controllers.
private static UserSession instance;
- // Current authenticated username, null when logged out.
private String username;
- // Current authenticated role, null when logged out.
private Role role;
private UserSession() {}
- // Lazily initialised singleton accessor.
public static UserSession getInstance() {
if (instance == null) {
instance = new UserSession();
@@ -26,13 +17,11 @@ public class UserSession {
return instance;
}
- // Stores identity and role for the active session.
public void login(String username, Role role) {
this.username = username;
this.role = role;
}
- // Clears session state and returns the application to an unauthenticated state.
public void logout() {
this.username = null;
this.role = null;
@@ -46,13 +35,10 @@ public class UserSession {
return role;
}
- // Convenience check for administrative privileges.
- // Role.ADMIN.equals(role) remains safe when role is null.
public boolean isAdmin() {
return Role.ADMIN.equals(role);
}
- // Session is considered active only when both username and role are set.
public boolean isLoggedIn() {
return username != null && role != null;
}
diff --git a/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java b/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java
index 6f60eb7d..51aba3f9 100644
--- a/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java
+++ b/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java
@@ -15,6 +15,21 @@ import org.example.petshopdesktop.util.ActivityLogger;
public class MainLayoutController {
+ private static final String NAV_BASE_STYLE = "-fx-background-color: transparent; " +
+ "-fx-text-fill: #cbd5e1; " +
+ "-fx-background-radius: 10; " +
+ "-fx-cursor: hand; " +
+ "-fx-focus-color: transparent; " +
+ "-fx-faint-focus-color: transparent;";
+
+ private static final String NAV_ACTIVE_STYLE = "-fx-background-color: #FF6B6B; " +
+ "-fx-text-fill: white; " +
+ "-fx-background-radius: 10; " +
+ "-fx-cursor: hand; " +
+ "-fx-focus-color: transparent; " +
+ "-fx-faint-focus-color: transparent; " +
+ "-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.22), 10, 0.15, 0, 2);";
+
@FXML
private Button btnAdoptions;
@@ -180,6 +195,7 @@ public class MainLayoutController {
btnSalesHistory.setText(isAdmin ? "Sales History" : "Sales");
+
}
private void loadView(String fxmlFile) {
@@ -205,9 +221,6 @@ public class MainLayoutController {
}
private void updateButtons(Button activeButton) {
- String base = "-fx-background-color: transparent; -fx-text-fill: #D5DDE6; -fx-cursor: hand; -fx-background-radius: 10; -fx-alignment: CENTER_LEFT;";
- String active = "-fx-background-color: #FF6B6B; -fx-text-fill: white; -fx-cursor: hand; -fx-background-radius: 10; -fx-alignment: CENTER_LEFT;";
-
Button[] buttons = {
btnAdoptions,
btnPets,
@@ -224,12 +237,12 @@ public class MainLayoutController {
for (Button button : buttons) {
if (button != null) {
- button.setStyle(base);
+ button.setStyle(NAV_BASE_STYLE);
}
}
if (activeButton != null) {
- activeButton.setStyle(active);
+ activeButton.setStyle(NAV_ACTIVE_STYLE);
}
}
diff --git a/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java b/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java
index 87c087ef..6c436479 100644
--- a/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java
+++ b/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java
@@ -115,10 +115,10 @@ public class AdoptionDB {
Connection conn = ConnectionDB.getConnection();
Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery("SELECT customerId, firstName, lastName FROM customer");
+ ResultSet rs = stmt.executeQuery("SELECT customerId, firstName, lastName, email, phone FROM customer");
while (rs.next()) {
- customers.add(new Customer(rs.getInt(1), rs.getString(2), rs.getString(3)));
+ customers.add(new Customer(rs.getInt(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5)));
}
conn.close();
diff --git a/src/main/java/org/example/petshopdesktop/database/SaleDB.java b/src/main/java/org/example/petshopdesktop/database/SaleDB.java
new file mode 100644
index 00000000..43bc798d
--- /dev/null
+++ b/src/main/java/org/example/petshopdesktop/database/SaleDB.java
@@ -0,0 +1,113 @@
+package org.example.petshopdesktop.database;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import org.example.petshopdesktop.DTOs.SaleDTO;
+
+import java.sql.*;
+
+public class SaleDB {
+
+ /**
+ * Get all sale items with details
+ * @return ObservableList of SaleDTOs
+ * @throws SQLException if database operation fails
+ */
+ public static ObservableList getSales() throws SQLException {
+ ObservableList sales = FXCollections.observableArrayList();
+ Connection conn = ConnectionDB.getConnection();
+
+ String sql = """
+ SELECT
+ s.saleId,
+ DATE_FORMAT(s.saleDate, '%Y-%m-%d %H:%i') as saleDate,
+ CONCAT(e.firstName, ' ', e.lastName) as employeeName,
+ p.prodName,
+ si.quantity,
+ si.unitPrice,
+ (si.quantity * si.unitPrice) as lineTotal,
+ s.paymentMethod
+ FROM sale s
+ JOIN saleItem si ON s.saleId = si.saleId
+ JOIN product p ON si.prodId = p.prodId
+ JOIN employee e ON s.employeeId = e.employeeId
+ ORDER BY s.saleDate DESC, s.saleId, si.saleItemId
+ """;
+
+ Statement stmt = conn.createStatement();
+ ResultSet rs = stmt.executeQuery(sql);
+
+ while (rs.next()) {
+ sales.add(new SaleDTO(
+ rs.getInt("saleId"),
+ rs.getString("saleDate"),
+ rs.getString("employeeName"),
+ rs.getString("prodName"),
+ rs.getInt("quantity"),
+ rs.getDouble("unitPrice"),
+ rs.getDouble("lineTotal"),
+ rs.getString("paymentMethod")
+ ));
+ }
+
+ conn.close();
+ return sales;
+ }
+
+ /**
+ * Get filtered sale items
+ * @param filter search term
+ * @return ObservableList of SaleDTOs matching the filter
+ * @throws SQLException if database operation fails
+ */
+ public static ObservableList getFilteredSales(String filter) throws SQLException {
+ ObservableList sales = FXCollections.observableArrayList();
+ Connection conn = ConnectionDB.getConnection();
+
+ String sql = """
+ SELECT
+ s.saleId,
+ DATE_FORMAT(s.saleDate, '%Y-%m-%d %H:%i') as saleDate,
+ CONCAT(e.firstName, ' ', e.lastName) as employeeName,
+ p.prodName,
+ si.quantity,
+ si.unitPrice,
+ (si.quantity * si.unitPrice) as lineTotal,
+ s.paymentMethod
+ FROM sale s
+ JOIN saleItem si ON s.saleId = si.saleId
+ JOIN product p ON si.prodId = p.prodId
+ JOIN employee e ON s.employeeId = e.employeeId
+ WHERE s.saleId LIKE ?
+ OR p.prodName LIKE ?
+ OR CONCAT(e.firstName, ' ', e.lastName) LIKE ?
+ OR s.paymentMethod LIKE ?
+ ORDER BY s.saleDate DESC, s.saleId, si.saleItemId
+ """;
+
+ PreparedStatement pstmt = conn.prepareStatement(sql);
+ String searchPattern = "%" + filter + "%";
+ pstmt.setString(1, searchPattern);
+ pstmt.setString(2, searchPattern);
+ pstmt.setString(3, searchPattern);
+ pstmt.setString(4, searchPattern);
+
+ ResultSet rs = pstmt.executeQuery();
+
+ while (rs.next()) {
+ sales.add(new SaleDTO(
+ rs.getInt("saleId"),
+ rs.getString("saleDate"),
+ rs.getString("employeeName"),
+ rs.getString("prodName"),
+ rs.getInt("quantity"),
+ rs.getDouble("unitPrice"),
+ rs.getDouble("lineTotal"),
+ rs.getString("paymentMethod")
+ ));
+ }
+
+ conn.close();
+ return sales;
+ }
+}
diff --git a/src/main/java/org/example/petshopdesktop/database/UserDB.java b/src/main/java/org/example/petshopdesktop/database/UserDB.java
index 3b5f78b4..88efe556 100644
--- a/src/main/java/org/example/petshopdesktop/database/UserDB.java
+++ b/src/main/java/org/example/petshopdesktop/database/UserDB.java
@@ -5,10 +5,6 @@ import org.example.petshopdesktop.models.User;
import java.sql.*;
-/*
-Petshop Desktop
-Purpose: User authentication and role lookup against the users table.
-*/
public class UserDB {
/**
@@ -34,8 +30,6 @@ public class UserDB {
int userId = rs.getInt("user_id");
String uname = rs.getString("username");
- // Role values are stored in the database as strings and normalised to match the enum.
- // Table constraints limit role values, Role.valueOf is expected to be safe under normal operation.
Role role = Role.valueOf(rs.getString("role").toUpperCase());
return new User(userId, uname, role);
@@ -59,7 +53,6 @@ public class UserDB {
)
""";
- // Default accounts support initial development and testing, credentials should be rotated or removed for deployment.
String seedAdmin = """
INSERT IGNORE INTO users (username, password_hash, role)
VALUES ('admin', SHA2('admin123', 256), 'ADMIN')
diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/adoption-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/adoption-dialog-view.fxml
index ef02cdf0..c3a14b62 100644
--- a/src/main/resources/org/example/petshopdesktop/dialogviews/adoption-dialog-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/dialogviews/adoption-dialog-view.fxml
@@ -13,7 +13,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/appointment-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/appointment-dialog-view.fxml
index b12bc777..99cf0833 100644
--- a/src/main/resources/org/example/petshopdesktop/dialogviews/appointment-dialog-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/dialogviews/appointment-dialog-view.fxml
@@ -17,7 +17,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/pet-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/pet-dialog-view.fxml
index 0784811b..d4c97ddb 100644
--- a/src/main/resources/org/example/petshopdesktop/dialogviews/pet-dialog-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/dialogviews/pet-dialog-view.fxml
@@ -13,7 +13,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/product-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/product-dialog-view.fxml
index 2972f5ed..2164ec66 100644
--- a/src/main/resources/org/example/petshopdesktop/dialogviews/product-dialog-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/dialogviews/product-dialog-view.fxml
@@ -13,7 +13,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/product-supplier-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/product-supplier-dialog-view.fxml
index 0ef57a60..ec29e4b6 100644
--- a/src/main/resources/org/example/petshopdesktop/dialogviews/product-supplier-dialog-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/dialogviews/product-supplier-dialog-view.fxml
@@ -13,7 +13,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml
index 327ce2d0..6cf098fd 100644
--- a/src/main/resources/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml
@@ -13,7 +13,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml b/src/main/resources/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml
index e26557c8..968d1021 100644
--- a/src/main/resources/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml
@@ -12,7 +12,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/login-view.fxml b/src/main/resources/org/example/petshopdesktop/login-view.fxml
index 65199c95..ad6e0bca 100644
--- a/src/main/resources/org/example/petshopdesktop/login-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/login-view.fxml
@@ -10,7 +10,7 @@
diff --git a/src/main/resources/org/example/petshopdesktop/main-layout-view.fxml b/src/main/resources/org/example/petshopdesktop/main-layout-view.fxml
index a1471b98..fdf5c267 100644
--- a/src/main/resources/org/example/petshopdesktop/main-layout-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/main-layout-view.fxml
@@ -5,131 +5,146 @@
+
-
+
-
+
-
+
-
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/adoption-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/adoption-view.fxml
index c1ec6564..9443ef14 100644
--- a/src/main/resources/org/example/petshopdesktop/modelviews/adoption-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/modelviews/adoption-view.fxml
@@ -11,7 +11,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/appointment-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/appointment-view.fxml
index 4bfd3029..f698c5c1 100644
--- a/src/main/resources/org/example/petshopdesktop/modelviews/appointment-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/modelviews/appointment-view.fxml
@@ -11,7 +11,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/inventory-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/inventory-view.fxml
index dea27d1b..18e9ad5a 100644
--- a/src/main/resources/org/example/petshopdesktop/modelviews/inventory-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/modelviews/inventory-view.fxml
@@ -11,7 +11,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/pet-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/pet-view.fxml
index a9ab6772..43c3c323 100644
--- a/src/main/resources/org/example/petshopdesktop/modelviews/pet-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/modelviews/pet-view.fxml
@@ -11,7 +11,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/product-supplier-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/product-supplier-view.fxml
index 6ef50d13..19817faa 100644
--- a/src/main/resources/org/example/petshopdesktop/modelviews/product-supplier-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/modelviews/product-supplier-view.fxml
@@ -11,7 +11,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/product-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/product-view.fxml
index 2473d057..d9b9a37c 100644
--- a/src/main/resources/org/example/petshopdesktop/modelviews/product-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/modelviews/product-view.fxml
@@ -11,7 +11,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/purchase-order-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/purchase-order-view.fxml
index e4c3a488..74a00e6d 100644
--- a/src/main/resources/org/example/petshopdesktop/modelviews/purchase-order-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/modelviews/purchase-order-view.fxml
@@ -7,7 +7,7 @@
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/purchaseorder-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/purchaseorder-view.fxml
deleted file mode 100644
index fdac860e..00000000
--- a/src/main/resources/org/example/petshopdesktop/modelviews/purchaseorder-view.fxml
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/sale-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/sale-view.fxml
index 4556d5d4..3bcfa9a9 100644
--- a/src/main/resources/org/example/petshopdesktop/modelviews/sale-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/modelviews/sale-view.fxml
@@ -14,7 +14,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/service-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/service-view.fxml
index 2adac139..5353b0e6 100644
--- a/src/main/resources/org/example/petshopdesktop/modelviews/service-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/modelviews/service-view.fxml
@@ -11,7 +11,7 @@
-
+
diff --git a/src/main/resources/org/example/petshopdesktop/modelviews/supplier-view.fxml b/src/main/resources/org/example/petshopdesktop/modelviews/supplier-view.fxml
index 423ae2bf..9c6d75cc 100644
--- a/src/main/resources/org/example/petshopdesktop/modelviews/supplier-view.fxml
+++ b/src/main/resources/org/example/petshopdesktop/modelviews/supplier-view.fxml
@@ -11,7 +11,7 @@
-
+