Remove database package and references

This commit is contained in:
2026-03-07 17:45:12 -07:00
parent a6e424de41
commit b5084c6d2e
17 changed files with 1 additions and 2609 deletions

View File

@@ -1,4 +1 @@
url=jdbc:mysql://127.0.0.1:3306/Petstoredb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
user=petapp
password=petapppass
api.baseUrl=http://localhost:8080
api.baseUrl=http://localhost:8080

View File

@@ -4,18 +4,12 @@ import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.example.petshopdesktop.database.UserDB;
import java.io.IOException;
public class PetShopApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
try {
UserDB.initializeTable();
} catch (Exception e) {
System.err.println("Warning: could not initialize users table: " + e.getMessage());
}
FXMLLoader fxmlLoader = new FXMLLoader(PetShopApplication.class.getResource("login-view.fxml"));
Scene scene = new Scene(fxmlLoader.load());
stage.setTitle("Pet Shop Manager - Login");

View File

@@ -1,166 +0,0 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.models.Adoption;
import org.example.petshopdesktop.models.Customer;
import org.example.petshopdesktop.models.Pet;
import org.example.petshopdesktop.util.ActivityLogger;
import java.sql.*;
public class AdoptionDB {
//Select query
private static final String BASE_SELECT =
"SELECT a.adoptionId, a.petId, a.customerId, " +
"CONCAT(c.firstName, ' ', c.lastName) AS customerName, " +
"a.adoptionDate, p.petPrice AS adoptionFee, a.adoptionStatus " +
"FROM adoption a " +
"JOIN customer c ON a.customerId = c.customerId " +
"JOIN pet p ON a.petId = p.petId";
//Retrieve all adoption records from DB
public static ObservableList<Adoption> getAdoptions() throws SQLException {
ObservableList<Adoption> adoptions = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(BASE_SELECT);
//Map results
while (rs.next()) {
adoptions.add(mapRow(rs));
}
conn.close();
return adoptions;
}
//Returns data depending on search query
public static ObservableList<Adoption> getFilteredAdoptions(String filter) throws SQLException {
ObservableList<Adoption> adoptions = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = BASE_SELECT +
" WHERE a.adoptionId LIKE '%" + filter + "%' OR " +
"a.petId LIKE '%" + filter + "%' OR " +
"CONCAT(c.firstName, ' ', c.lastName) LIKE '%" + filter + "%' OR " +
"a.adoptionDate LIKE '%" + filter + "%' OR " +
"p.petPrice LIKE '%" + filter + "%' OR " +
"a.adoptionStatus LIKE '%" + filter + "%'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
//Map results
while (rs.next()) {
adoptions.add(mapRow(rs));
}
conn.close();
return adoptions;
}
//Add new adoption
public static int insertAdoption(Adoption adoption) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = "INSERT INTO adoption (petId, customerId, adoptionDate, adoptionStatus) VALUES (?, ?, ?, ?)";
PreparedStatement stmt = conn.prepareStatement(sql);
//Put data in Adoption object
stmt.setInt(1, adoption.getPetId());
stmt.setInt(2, adoption.getCustomerId());
stmt.setString(3, adoption.getAdoptionDate());
stmt.setString(4, adoption.getAdoptionStatus());
int numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logInsert("adoption",
"N/A",
String.format("Adoption record added for Pet ID %d, Customer ID %d", adoption.getPetId(), adoption.getCustomerId()));
}
return numRows;
}
//Updating pre-existing adoption
public static int updateAdoption(int adoptionId, Adoption adoption) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = "UPDATE adoption SET petId = ?, customerId = ?, adoptionDate = ?, adoptionStatus = ? WHERE adoptionId = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, adoption.getPetId());
stmt.setInt(2, adoption.getCustomerId());
stmt.setString(3, adoption.getAdoptionDate());
stmt.setString(4, adoption.getAdoptionStatus());
stmt.setInt(5, adoptionId);
int numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logUpdate("adoption",
String.valueOf(adoptionId),
String.format("Adoption ID %d updated", adoptionId));
}
return numRows;
}
//Delete adoption
public static int deleteAdoption(int adoptionId) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = "DELETE FROM adoption WHERE adoptionId = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, adoptionId);
int numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logDelete("adoption",
String.valueOf(adoptionId),
String.format("Adoption ID %d deleted", adoptionId));
}
return numRows;
}
//Grab list of customers from DB for comboboxes
public static ObservableList<Customer> getCustomers() throws SQLException {
ObservableList<Customer> customers = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
Statement stmt = conn.createStatement();
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), rs.getString(4), rs.getString(5)));
}
conn.close();
return customers;
}
//DRY: converts DB data into usable Java object
private static Adoption mapRow(ResultSet rs) throws SQLException {
return new Adoption(
rs.getInt("adoptionId"),
rs.getInt("petId"),
rs.getInt("customerId"),
"",
rs.getString("customerName"),
rs.getString("adoptionDate"),
rs.getDouble("adoptionFee"),
rs.getString("adoptionStatus")
);
}
}

View File

@@ -1,223 +0,0 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.DTOs.AppointmentDTO;
import org.example.petshopdesktop.models.Appointment;
import org.example.petshopdesktop.util.ActivityLogger;
import java.sql.*;
public class AppointmentDB {
// ============================
// GET ALL APPOINTMENTS
// ============================
public static ObservableList<AppointmentDTO> getAppointmentDTOs()
throws SQLException {
ObservableList<AppointmentDTO> list =
FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = """
SELECT a.appointmentId,
c.customerId,
CONCAT(c.firstName,' ',c.lastName) AS customerName,
p.petId,
p.petName,
s.serviceId,
s.serviceName,
a.appointmentDate,
a.appointmentTime,
a.appointmentStatus
FROM appointment a
JOIN customer c ON a.customerId = c.customerId
JOIN appointmentPet ap ON a.appointmentId = ap.appointmentId
JOIN pet p ON ap.petId = p.petId
JOIN service s ON a.serviceId = s.serviceId
""";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
AppointmentDTO dto = new AppointmentDTO(
rs.getInt("appointmentId"),
rs.getInt("customerId"),
rs.getString("customerName"),
rs.getInt("petId"),
rs.getString("petName"),
rs.getInt("serviceId"),
rs.getString("serviceName"),
rs.getString("appointmentDate"),
rs.getString("appointmentTime"),
rs.getString("appointmentStatus")
);
list.add(dto);
}
conn.close();
return list;
}
// ============================
// INSERT APPOINTMENT
// ============================
public static int insertAppointment(Appointment appt)
throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = """
INSERT INTO appointment
(serviceId, customerId, appointmentDate,
appointmentTime, appointmentStatus)
VALUES (?,?,?,?,?)
""";
PreparedStatement ps =
conn.prepareStatement(sql,
Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, appt.getServiceId());
ps.setInt(2, appt.getCustomerId());
ps.setString(3, appt.getAppointmentDate());
ps.setString(4, appt.getAppointmentTime());
ps.setString(5, appt.getAppointmentStatus());
ps.executeUpdate();
ResultSet keys = ps.getGeneratedKeys();
int newId = 0;
if (keys.next()) {
newId = keys.getInt(1);
}
conn.close();
// Log the operation
if (newId > 0) {
ActivityLogger.getInstance().logInsert("appointment",
String.valueOf(newId),
String.format("Appointment created for Customer ID %d, Service ID %d", appt.getCustomerId(), appt.getServiceId()));
}
return newId;
}
//
// LINK PET TO APPOINTMENT
//
public static void insertAppointmentPet(int appointmentId,
int petId)
throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql =
"INSERT INTO appointmentPet (appointmentId, petId) VALUES (?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, appointmentId);
ps.setInt(2, petId);
int numRows = ps.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logInsert("appointmentPet",
String.valueOf(appointmentId),
String.format("Pet ID %d linked to Appointment ID %d", petId, appointmentId));
}
}
//
// UPDATE APPOINTMENT
//
public static int updateAppointment(int id,
Appointment appt,
int petId)
throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql =
"UPDATE appointment SET serviceId=?, customerId=?, " +
"appointmentDate=?, appointmentTime=?, appointmentStatus=? " +
"WHERE appointmentId=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, appt.getServiceId());
ps.setInt(2, appt.getCustomerId());
ps.setString(3, appt.getAppointmentDate());
ps.setString(4, appt.getAppointmentTime());
ps.setString(5, appt.getAppointmentStatus());
ps.setInt(6, id);
ps.executeUpdate();
String sql2 =
"UPDATE appointmentPet SET petId=? WHERE appointmentId=?";
PreparedStatement ps2 = conn.prepareStatement(sql2);
ps2.setInt(1, petId);
ps2.setInt(2, id);
ps2.executeUpdate();
conn.close();
// Log the operation
ActivityLogger.getInstance().logUpdate("appointment",
String.valueOf(id),
String.format("Appointment ID %d updated", id));
return 1;
}
//
// DELETE APPOINTMENT
//
public static int deleteAppointment(int id)
throws SQLException {
Connection conn = ConnectionDB.getConnection();
PreparedStatement ps1 =
conn.prepareStatement(
"DELETE FROM appointmentPet WHERE appointmentId=?"
);
ps1.setInt(1, id);
ps1.executeUpdate();
PreparedStatement ps2 =
conn.prepareStatement(
"DELETE FROM appointment WHERE appointmentId=?"
);
ps2.setInt(1, id);
int rows = ps2.executeUpdate();
conn.close();
// Log the operation
if (rows > 0) {
ActivityLogger.getInstance().logDelete("appointment",
String.valueOf(id),
String.format("Appointment ID %d deleted", id));
}
return rows;
}
}

View File

@@ -1,41 +0,0 @@
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

@@ -1,66 +0,0 @@
package org.example.petshopdesktop.database;
import org.example.petshopdesktop.util.ActivityLogger;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class ConnectionDB {
/**
* Method to try and connect to the database using connectionpetstore.properties.
* @return Connection to the database
*/
public static Connection getConnection(){
String url = "";
String user = "";
String password = "";
Properties prop = new Properties();
Path propsPath;
String explicitPath = System.getenv("PETSTORE_DB_PROPS");
if (explicitPath != null && !explicitPath.isBlank()) {
propsPath = Paths.get(explicitPath);
} else {
Path cwd = Paths.get(System.getProperty("user.dir"), "connectionpetstore.properties");
Path xdg = Paths.get(System.getProperty("user.home"), ".config", "petstore", "connectionpetstore.properties");
Path legacyWindows = Paths.get("./connectionpetstore.properties");
if (Files.exists(cwd)) propsPath = cwd;
else if (Files.exists(xdg)) propsPath = xdg;
else propsPath = legacyWindows;
}
try (FileInputStream fis = new FileInputStream(propsPath.toString())) {
prop.load(fis);
url = prop.getProperty("url");
user = prop.getProperty("user");
password = prop.getProperty("password");
}
catch(IOException e){
ActivityLogger.getInstance().logException(
"ConnectionDB.getConnection",
e,
"Reading connection properties file");
throw new RuntimeException("Problem with reading connection info: "+e.getMessage());
}
try{
return DriverManager.getConnection(url,user,password);
}
catch (SQLException e) {
ActivityLogger.getInstance().logException(
"ConnectionDB.getConnection",
e,
"Establishing database connection");
throw new RuntimeException("Problem with database connection: "+e.getMessage());
}
}
}

View File

@@ -1,43 +0,0 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.models.Customer;
import java.sql.*;
public class CustomerDB {
//
// GET ALL CUSTOMERS
//
public static ObservableList<Customer> getCustomers()
throws SQLException {
ObservableList<Customer> list =
FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = "SELECT * FROM customer";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while(rs.next()) {
Customer c = new Customer(
rs.getInt("customerId"),
rs.getString("firstName"),
rs.getString("lastName"),
rs.getString("email"),
rs.getString("phone")
);
list.add(c);
}
conn.close();
return list;
}
}

View File

@@ -1,132 +0,0 @@
package org.example.petshopdesktop.database;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class EmployeeDB {
public static int ensureDefaultEmployee(String firstName, String lastName, String email, String phone, String role, boolean isActive) throws SQLException {
Integer existingId = findEmployeeIdByEmail(email);
if (existingId != null) {
return existingId;
}
try (Connection conn = ConnectionDB.getConnection()) {
conn.setAutoCommit(false);
try {
int storeId = getDefaultStoreId(conn);
int employeeId = createEmployee(conn, firstName, lastName, email, phone, role, isActive);
assignEmployeeToStore(conn, employeeId, storeId);
conn.commit();
return employeeId;
} catch (SQLException e) {
conn.rollback();
throw e;
} finally {
conn.setAutoCommit(true);
}
}
}
public static Integer findEmployeeIdByEmail(String email) throws SQLException {
String sql = "SELECT employeeId FROM employee WHERE email = ? LIMIT 1";
try (Connection conn = ConnectionDB.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, email);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
return rs.getInt("employeeId");
}
}
}
return null;
}
public static int createEmployee(Connection conn, String firstName, String lastName, String email, String phone, String role, boolean isActive) throws SQLException {
String sql = "INSERT INTO employee (firstName, lastName, email, phone, role, isActive) VALUES (?, ?, ?, ?, ?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
ps.setString(1, firstName);
ps.setString(2, lastName);
ps.setString(3, email);
ps.setString(4, phone);
ps.setString(5, role);
ps.setBoolean(6, isActive);
ps.executeUpdate();
try (ResultSet keys = ps.getGeneratedKeys()) {
if (keys.next()) {
return keys.getInt(1);
}
}
}
throw new SQLException("Could not create employee.");
}
public static void assignEmployeeToStore(Connection conn, int employeeId, int storeId) throws SQLException {
String sql = "INSERT IGNORE INTO employeeStore (employeeId, storeId) VALUES (?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, employeeId);
ps.setInt(2, storeId);
ps.executeUpdate();
}
}
public static int getDefaultStoreId() throws SQLException {
try (Connection conn = ConnectionDB.getConnection()) {
return getDefaultStoreId(conn);
}
}
public static int getDefaultStoreId(Connection conn) throws SQLException {
Integer existing = firstStoreId(conn);
if (existing != null) {
return existing;
}
String insert = "INSERT INTO storeLocation (storeName, address, phone, email) VALUES ('Main Store', 'N/A', '000-000-0000', 'main@petshop.com')";
try (PreparedStatement ps = conn.prepareStatement(insert, Statement.RETURN_GENERATED_KEYS)) {
ps.executeUpdate();
try (ResultSet keys = ps.getGeneratedKeys()) {
if (keys.next()) {
return keys.getInt(1);
}
}
}
Integer after = firstStoreId(conn);
if (after != null) {
return after;
}
return 1;
}
public static Integer getPrimaryStoreId(int employeeId) throws SQLException {
String sql = "SELECT storeId FROM employeeStore WHERE employeeId = ? ORDER BY storeId ASC LIMIT 1";
try (Connection conn = ConnectionDB.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, employeeId);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
return rs.getInt("storeId");
}
}
}
return null;
}
private static Integer firstStoreId(Connection conn) throws SQLException {
String sql = "SELECT storeId FROM storeLocation ORDER BY storeId ASC LIMIT 1";
try (PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
return rs.getInt("storeId");
}
}
return null;
}
}

View File

@@ -1,162 +0,0 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.models.Inventory;
import org.example.petshopdesktop.util.ActivityLogger;
import java.sql.*;
public class InventoryDB {
//Base selection query
//Returns invID, ProdID, Quantity from Inventory table
//Returns ProdName from Product table
private static final String BASE_SELECT =
"SELECT i.inventoryId, i.prodId, p.prodName, i.quantity " +
"FROM inventory i " +
"JOIN product p ON i.prodId = p.prodId";
//Retrieves inventory records from DB
public static ObservableList<Inventory> getInventory() throws SQLException {
ObservableList<Inventory> inventoryList = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(BASE_SELECT);
while (rs.next()) {
inventoryList.add(mapRow(rs));
}
conn.close();
return inventoryList;
}
//Returns records depending on search
public static ObservableList<Inventory> getFilteredInventory(String filter) throws SQLException {
ObservableList<Inventory> inventoryList = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = BASE_SELECT +
" WHERE i.inventoryId LIKE ? OR " +
"i.prodId LIKE ? OR " +
"p.prodName LIKE ? OR " +
"i.quantity LIKE ?";
String filteredString = "%" + filter + "%";
PreparedStatement stmt = conn.prepareStatement(sql);
for (int i = 1; i <= 4; i++) {
stmt.setString(i, filteredString);
}
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
inventoryList.add(mapRow(rs));
}
conn.close();
return inventoryList;
}
//Checks if the product already has an inventory entry
public static boolean productExistsInInventory(int prodId) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = "SELECT COUNT(*) FROM inventory WHERE prodId = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, prodId);
ResultSet rs = stmt.executeQuery();
boolean exists = rs.next() && rs.getInt(1) > 0;
conn.close();
return exists;
}
//Inserting new inventory record
public static int insertInventory(Inventory inventory) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = "INSERT INTO inventory (prodId, quantity) VALUES (?, ?)";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, inventory.getProdId());
stmt.setInt(2, inventory.getQuantity());
int numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logInsert("inventory",
"N/A",
String.format("Inventory added for Product ID %d, Quantity %d", inventory.getProdId(), inventory.getQuantity()));
}
return numRows;
}
//Updating inventory record
public static int updateInventory(int inventoryId, Inventory inventory) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = "UPDATE inventory SET prodId = ?, quantity = ? WHERE inventoryId = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, inventory.getProdId());
stmt.setInt(2, inventory.getQuantity());
stmt.setInt(3, inventoryId);
int numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logUpdate("inventory",
String.valueOf(inventoryId),
String.format("Inventory ID %d updated", inventoryId));
}
return numRows;
}
//Deleting inventory record
public static int deleteInventory(int inventoryId) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = "DELETE FROM inventory WHERE inventoryId = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, inventoryId);
int numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logDelete("inventory",
String.valueOf(inventoryId),
String.format("Inventory ID %d deleted", inventoryId));
}
return numRows;
}
//DRY: converts DB data into usable Java object
private static Inventory mapRow(ResultSet rs) throws SQLException {
return new Inventory(
rs.getInt("inventoryId"),
rs.getInt("prodId"),
rs.getString("prodName"),
"",
0,
"",
rs.getInt("quantity"),
0
);
}
}

View File

@@ -1,167 +0,0 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.models.Pet;
import org.example.petshopdesktop.util.ActivityLogger;
import java.sql.*;
public class PetDB {
public static ObservableList<Pet> getPets() throws SQLException {
//Connect to the database
ObservableList<Pet> pets = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
//Execute Query
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM pet");
//While there is still data add pets to the list
while(rs.next()){
Pet pet = new Pet(
rs.getInt(1),
rs.getString(2),
rs.getString(3),
rs.getString(4),
rs.getInt(5),
rs.getString(6),
rs.getDouble(7)
);
pets.add(pet);
}
//close connection and return pets
conn.close();
return pets;
}
public static ObservableList<Pet> getFilteredPets(String filter) throws SQLException {
//Connect to the database
ObservableList<Pet> pets = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
//Get SQL query for filtered word
String sql = "SELECT * FROM pet " +
" WHERE " +
"petName LIKE ? OR " +
"petSpecies LIKE ? OR " +
"petBreed LIKE ? OR " +
"petAge LIKE ? OR " +
"petStatus LIKE ? OR " +
"petPrice LIKE ?";
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);
stmt.setString(6, filteredString);
ResultSet rs = stmt.executeQuery();
while(rs.next()){
Pet pet = new Pet(
rs.getInt(1),
rs.getString(2),
rs.getString(3),
rs.getString(4),
rs.getInt(5),
rs.getString(6),
rs.getDouble(7)
);
pets.add(pet);
}
conn.close();
return pets;
}
public static int insertPet(Pet pet) throws SQLException {
int numRows = 0;
Connection conn = ConnectionDB.getConnection();
String sql = "INSERT INTO pet (petId, petName, petSpecies, petBreed, petAge, petStatus, petPrice)" +
" VALUES (?, ?, ?, ?, ?, ?, ?)";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, pet.getPetId());
stmt.setString(2, pet.getPetName());
stmt.setString(3, pet.getPetSpecies());
stmt.setString(4, pet.getPetBreed());
stmt.setInt(5, pet.getPetAge());
stmt.setString(6, pet.getPetStatus());
stmt.setDouble(7, pet.getPetPrice());
numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logInsert("pet",
String.valueOf(pet.getPetId()),
String.format("Pet '%s' added", pet.getPetName()));
}
return numRows;
}
public static int updatePet(int petId, Pet pet) throws SQLException {
int numRows = 0;
Connection conn = ConnectionDB.getConnection();
String sql = "UPDATE pet SET " +
" petName = ?, " +
" petSpecies = ?, " +
" petBreed = ?, " +
" petAge = ?, " +
" petStatus = ?, " +
" petPrice = ? " +
" WHERE petId = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, pet.getPetName());
stmt.setString(2, pet.getPetSpecies());
stmt.setString(3, pet.getPetBreed());
stmt.setInt(4, pet.getPetAge());
stmt.setString(5, pet.getPetStatus());
stmt.setDouble(6, pet.getPetPrice());
stmt.setInt(7, petId);
numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logUpdate("pet",
String.valueOf(petId),
String.format("Pet '%s' updated", pet.getPetName()));
}
return numRows;
}
public static int deletePet(int petId) throws SQLException {
int numRows = 0;
Connection conn = ConnectionDB.getConnection();
String sql = "DELETE FROM pet WHERE petId = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, petId);
numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logDelete("pet",
String.valueOf(petId),
String.format("Pet ID %d deleted", petId));
}
return numRows;
}
}

View File

@@ -1,234 +0,0 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.DTOs.ProductDTO;
import org.example.petshopdesktop.models.Product;
import org.example.petshopdesktop.models.Supplier;
import org.example.petshopdesktop.util.ActivityLogger;
import java.sql.*;
/**
* A class containing all the methods relating to CRUD on Products table
*/
public class ProductDB {
/**
* gets all the products into an observable list
* @return a list of all the products
* @throws SQLException if failed to find products in the database
*/
public static ObservableList<Product> getProducts() throws SQLException{
//Connect to the database
ObservableList<Product> products = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
//Execute Query
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM product");
//While there is still data add products to the list
while(rs.next()){
Product product = new Product(
rs.getInt(1),
rs.getString(2),
rs.getDouble(3),
rs.getInt(4),
rs.getString(5));
products.add(product);
}
//close connection and return products
conn.close();
return products;
}
/**
* gets all the ProductDTOs into an observable list for display (displays categoryName instead of categoryId)
* @return the list of all the ProductDTOs
* @throws SQLException if failed to find products in the database
*/
public static ObservableList<ProductDTO> getProductDTO() throws SQLException{
//Connect to the database
ObservableList<ProductDTO> products = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
//Execute Query
Statement stmt = conn.createStatement();
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";
ResultSet rs = stmt.executeQuery(sql);
//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);
}
//close connection and return products
conn.close();
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();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logInsert("product",
String.valueOf(product.getProdId()),
String.format("Product '%s' added", product.getProdName()));
}
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();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logUpdate("product",
String.valueOf(prodId),
String.format("Product '%s' updated", product.getProdName()));
}
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();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logDelete("product",
String.valueOf(prodId),
String.format("Product ID %d deleted", prodId));
}
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

@@ -1,219 +0,0 @@
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 org.example.petshopdesktop.util.ActivityLogger;
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();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logInsert("productSupplier",
String.format("ProdID:%d-SupID:%d", productSupplier.getProdId(), productSupplier.getSupId()),
String.format("Product-Supplier relation added for Product ID %d, Supplier ID %d", productSupplier.getProdId(), productSupplier.getSupId()));
}
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();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logUpdate("productSupplier",
String.format("ProdID:%d-SupID:%d", productSupplier.getProdId(), productSupplier.getSupId()),
String.format("Product-Supplier relation updated from ProdID:%d-SupID:%d to ProdID:%d-SupID:%d", oldProdId, oldSupId, productSupplier.getProdId(), productSupplier.getSupId()));
}
}
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();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logDelete("productSupplier",
String.format("ProdID:%d-SupID:%d", prodId, supId),
String.format("Product-Supplier relation deleted for Product ID %d, Supplier ID %d", prodId, supId));
}
return numRows;
}
}

View File

@@ -1,45 +0,0 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.DTOs.PurchaseOrderDTO;
import java.sql.*;
public class PurchaseOrderDB {
public static ObservableList<PurchaseOrderDTO> getPurchaseOrders()
throws SQLException {
ObservableList<PurchaseOrderDTO> list =
FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = """
SELECT po.purchaseOrderId,
s.supCompany,
po.orderDate,
po.status
FROM purchaseOrder po
JOIN supplier s ON po.supId = s.supId
ORDER BY po.purchaseOrderId
""";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
list.add(new PurchaseOrderDTO(
rs.getInt("purchaseOrderId"),
rs.getString("supCompany"),
rs.getString("orderDate"),
rs.getString("status")
));
}
conn.close();
return list;
}
}

View File

@@ -1,572 +0,0 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.DTOs.SaleDTO;
import org.example.petshopdesktop.models.SaleCartItem;
import org.example.petshopdesktop.models.SaleDetail;
import org.example.petshopdesktop.models.SaleLineItem;
import org.example.petshopdesktop.models.analytics.*;
import org.example.petshopdesktop.util.ActivityLogger;
import java.sql.*;
import java.time.LocalDate;
public class SaleDB {
/**
* Get all sale items with details
* @return ObservableList of SaleDTOs
* @throws SQLException if database operation fails
*/
public static ObservableList<SaleDTO> getSales() throws SQLException {
ObservableList<SaleDTO> 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<SaleDTO> getFilteredSales(String filter) throws SQLException {
ObservableList<SaleDTO> 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;
}
public static ObservableList<SaleLineItem> getSaleLineItems() throws SQLException {
ObservableList<SaleLineItem> saleItems = 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 total,
s.paymentMethod,
s.isRefund
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()) {
saleItems.add(new SaleLineItem(
rs.getInt("saleId"),
rs.getString("saleDate"),
rs.getString("employeeName"),
rs.getString("prodName"),
rs.getInt("quantity"),
rs.getDouble("unitPrice"),
rs.getDouble("total"),
rs.getString("paymentMethod"),
rs.getBoolean("isRefund")
));
}
conn.close();
return saleItems;
}
public static int createSale(int employeeId, String paymentMethod, ObservableList<SaleCartItem> cartItems) throws SQLException {
if (cartItems.isEmpty()) {
throw new SQLException("Cannot create sale with empty cart");
}
Connection conn = ConnectionDB.getConnection();
conn.setAutoCommit(false);
try {
double totalAmount = cartItems.stream().mapToDouble(SaleCartItem::getTotal).sum();
String insertSale = """
INSERT INTO sale (saleDate, totalAmount, paymentMethod, employeeId, storeId)
VALUES (NOW(), ?, ?, ?, 1)
""";
PreparedStatement saleStmt = conn.prepareStatement(insertSale, Statement.RETURN_GENERATED_KEYS);
saleStmt.setDouble(1, totalAmount);
saleStmt.setString(2, paymentMethod);
saleStmt.setInt(3, employeeId);
saleStmt.executeUpdate();
ResultSet rs = saleStmt.getGeneratedKeys();
if (!rs.next()) {
throw new SQLException("Failed to get generated sale ID");
}
int saleId = rs.getInt(1);
String insertItem = """
INSERT INTO saleItem (saleId, prodId, quantity, unitPrice)
VALUES (?, ?, ?, ?)
""";
String updateInventory = """
UPDATE inventory
SET quantity = quantity - ?
WHERE prodId = ?
""";
PreparedStatement itemStmt = conn.prepareStatement(insertItem);
PreparedStatement invStmt = conn.prepareStatement(updateInventory);
for (SaleCartItem item : cartItems) {
itemStmt.setInt(1, saleId);
itemStmt.setInt(2, item.getProdId());
itemStmt.setInt(3, item.getQuantity());
itemStmt.setDouble(4, item.getUnitPrice());
itemStmt.executeUpdate();
invStmt.setInt(1, item.getQuantity());
invStmt.setInt(2, item.getProdId());
int updated = invStmt.executeUpdate();
if (updated == 0) {
throw new SQLException("Failed to update inventory for product ID " + item.getProdId());
}
}
conn.commit();
ActivityLogger.getInstance().logInsert("sale",
String.format("Sale ID: %d", saleId),
String.format("Created sale with %d items, total: $%.2f", cartItems.size(), totalAmount));
return saleId;
} catch (SQLException e) {
conn.rollback();
ActivityLogger.getInstance().logException("SaleDB.createSale", e, "Creating sale");
throw e;
} finally {
conn.setAutoCommit(true);
conn.close();
}
}
public static ObservableList<DailySalesData> getDailySalesRevenue() throws SQLException {
ObservableList<DailySalesData> dailySales = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = """
SELECT DATE(s.saleDate) as saleDate, SUM(s.totalAmount) as revenue
FROM sale s
GROUP BY DATE(s.saleDate)
ORDER BY saleDate ASC
""";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
LocalDate date = rs.getDate("saleDate").toLocalDate();
double revenue = rs.getDouble("revenue");
dailySales.add(new DailySalesData(date, revenue));
}
conn.close();
return dailySales;
}
public static ObservableList<ProductSalesData> getTopProductsByRevenue(int limit) throws SQLException {
ObservableList<ProductSalesData> products = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = """
SELECT p.prodName, SUM(si.quantity * si.unitPrice) as totalRevenue
FROM saleItem si
JOIN product p ON si.prodId = p.prodId
GROUP BY p.prodId, p.prodName
ORDER BY totalRevenue DESC
LIMIT ?
""";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, limit);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String productName = rs.getString("prodName");
double totalRevenue = rs.getDouble("totalRevenue");
products.add(new ProductSalesData(productName, 0, totalRevenue));
}
conn.close();
return products;
}
public static ObservableList<ProductSalesData> getTopProductsByQuantity(int limit) throws SQLException {
ObservableList<ProductSalesData> products = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = """
SELECT p.prodName, SUM(si.quantity) as totalQuantity,
SUM(si.quantity * si.unitPrice) as totalRevenue
FROM saleItem si
JOIN product p ON si.prodId = p.prodId
GROUP BY p.prodId, p.prodName
ORDER BY totalQuantity DESC
LIMIT ?
""";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, limit);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String productName = rs.getString("prodName");
int totalQuantity = rs.getInt("totalQuantity");
double totalRevenue = rs.getDouble("totalRevenue");
products.add(new ProductSalesData(productName, totalQuantity, totalRevenue));
}
conn.close();
return products;
}
public static ObservableList<PaymentMethodData> getPaymentMethodDistribution() throws SQLException {
ObservableList<PaymentMethodData> paymentMethods = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = """
SELECT s.paymentMethod, COUNT(*) as transactionCount,
SUM(s.totalAmount) as totalRevenue
FROM sale s
GROUP BY s.paymentMethod
ORDER BY totalRevenue DESC
""";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
String paymentMethod = rs.getString("paymentMethod");
int transactionCount = rs.getInt("transactionCount");
double totalRevenue = rs.getDouble("totalRevenue");
paymentMethods.add(new PaymentMethodData(paymentMethod, transactionCount, totalRevenue));
}
conn.close();
return paymentMethods;
}
public static ObservableList<EmployeeSalesData> getEmployeeSalesPerformance() throws SQLException {
ObservableList<EmployeeSalesData> employees = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = """
SELECT CONCAT(e.firstName, ' ', e.lastName) as employeeName,
COUNT(DISTINCT s.saleId) as transactionCount,
SUM(s.totalAmount) as totalRevenue,
COALESCE(SUM(si.quantity), 0) as totalItemsSold
FROM sale s
JOIN employee e ON s.employeeId = e.employeeId
LEFT JOIN saleItem si ON s.saleId = si.saleId
GROUP BY e.employeeId, e.firstName, e.lastName
ORDER BY totalRevenue DESC
""";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
String employeeName = rs.getString("employeeName");
int transactionCount = rs.getInt("transactionCount");
double totalRevenue = rs.getDouble("totalRevenue");
int totalItemsSold = rs.getInt("totalItemsSold");
employees.add(new EmployeeSalesData(employeeName, transactionCount, totalRevenue, totalItemsSold));
}
conn.close();
return employees;
}
public static SalesSummary getSalesSummary() throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = """
SELECT COUNT(DISTINCT s.saleId) as totalTransactions,
COALESCE(SUM(s.totalAmount), 0) as totalRevenue,
COALESCE(AVG(s.totalAmount), 0) as avgTransactionValue,
COALESCE(SUM(si.quantity), 0) as totalItemsSold
FROM sale s
LEFT JOIN saleItem si ON s.saleId = si.saleId
""";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
SalesSummary summary = null;
if (rs.next()) {
int totalTransactions = rs.getInt("totalTransactions");
double totalRevenue = rs.getDouble("totalRevenue");
double avgTransactionValue = rs.getDouble("avgTransactionValue");
int totalItemsSold = rs.getInt("totalItemsSold");
summary = new SalesSummary(totalTransactions, totalRevenue, avgTransactionValue, totalItemsSold);
}
conn.close();
return summary;
}
public static SaleDetail getSaleById(int saleId) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String saleSql = """
SELECT s.saleId, s.saleDate, s.totalAmount, s.paymentMethod,
CONCAT(e.firstName, ' ', e.lastName) as employeeName,
s.isRefund
FROM sale s
JOIN employee e ON s.employeeId = e.employeeId
WHERE s.saleId = ?
""";
PreparedStatement saleStmt = conn.prepareStatement(saleSql);
saleStmt.setInt(1, saleId);
ResultSet saleRs = saleStmt.executeQuery();
if (!saleRs.next()) {
conn.close();
throw new SQLException("Sale not found with ID: " + saleId);
}
boolean isRefund = saleRs.getBoolean("isRefund");
if (isRefund) {
conn.close();
throw new SQLException("Cannot refund a refund transaction");
}
SaleDetail detail = new SaleDetail(
saleRs.getInt("saleId"),
saleRs.getTimestamp("saleDate").toLocalDateTime(),
saleRs.getDouble("totalAmount"),
saleRs.getString("paymentMethod"),
saleRs.getString("employeeName"),
FXCollections.observableArrayList()
);
String itemsSql = """
SELECT si.prodId, p.prodName, si.quantity, si.unitPrice,
(si.quantity * si.unitPrice) as total
FROM saleItem si
JOIN product p ON si.prodId = p.prodId
WHERE si.saleId = ?
""";
PreparedStatement itemsStmt = conn.prepareStatement(itemsSql);
itemsStmt.setInt(1, saleId);
ResultSet itemsRs = itemsStmt.executeQuery();
while (itemsRs.next()) {
detail.getItems().add(new SaleDetail.SaleDetailItem(
itemsRs.getInt("prodId"),
itemsRs.getString("prodName"),
itemsRs.getInt("quantity"),
itemsRs.getDouble("unitPrice"),
itemsRs.getDouble("total")
));
}
conn.close();
return detail;
}
public static boolean isRefunded(int saleId) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = """
SELECT COUNT(*) as refundCount
FROM sale
WHERE originalSaleId = ? AND isRefund = TRUE
""";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, saleId);
ResultSet rs = pstmt.executeQuery();
boolean refunded = false;
if (rs.next()) {
refunded = rs.getInt("refundCount") > 0;
}
conn.close();
return refunded;
}
public static int createRefund(int originalSaleId, int employeeId, String paymentMethod, ObservableList<SaleCartItem> refundItems) throws SQLException {
if (refundItems.isEmpty()) {
throw new SQLException("Cannot create refund with empty items");
}
Connection conn = ConnectionDB.getConnection();
SaleDetail originalSale = getSaleById(originalSaleId);
conn = ConnectionDB.getConnection();
if (isRefunded(originalSaleId)) {
throw new SQLException("This sale has already been refunded");
}
conn.setAutoCommit(false);
try {
double totalAmount = -refundItems.stream().mapToDouble(SaleCartItem::getTotal).sum();
String insertSale = """
INSERT INTO sale (saleDate, totalAmount, paymentMethod, employeeId, storeId, isRefund, originalSaleId)
VALUES (NOW(), ?, ?, ?, 1, TRUE, ?)
""";
PreparedStatement saleStmt = conn.prepareStatement(insertSale, Statement.RETURN_GENERATED_KEYS);
saleStmt.setDouble(1, totalAmount);
saleStmt.setString(2, paymentMethod);
saleStmt.setInt(3, employeeId);
saleStmt.setInt(4, originalSaleId);
saleStmt.executeUpdate();
ResultSet rs = saleStmt.getGeneratedKeys();
if (!rs.next()) {
throw new SQLException("Failed to get generated refund ID");
}
int refundId = rs.getInt(1);
String insertItem = """
INSERT INTO saleItem (saleId, prodId, quantity, unitPrice)
VALUES (?, ?, ?, ?)
""";
String updateInventory = """
UPDATE inventory
SET quantity = quantity + ?
WHERE prodId = ?
""";
PreparedStatement itemStmt = conn.prepareStatement(insertItem);
PreparedStatement invStmt = conn.prepareStatement(updateInventory);
for (SaleCartItem item : refundItems) {
itemStmt.setInt(1, refundId);
itemStmt.setInt(2, item.getProdId());
itemStmt.setInt(3, -item.getQuantity());
itemStmt.setDouble(4, item.getUnitPrice());
itemStmt.executeUpdate();
invStmt.setInt(1, item.getQuantity());
invStmt.setInt(2, item.getProdId());
int updated = invStmt.executeUpdate();
if (updated == 0) {
throw new SQLException("Failed to update inventory for product ID " + item.getProdId());
}
}
conn.commit();
ActivityLogger.getInstance().logInsert("sale",
String.format("Refund ID: %d", refundId),
String.format("Created refund for sale ID %d with %d items, total: $%.2f", originalSaleId, refundItems.size(), Math.abs(totalAmount)));
return refundId;
} catch (SQLException e) {
conn.rollback();
ActivityLogger.getInstance().logException("SaleDB.createRefund", e, "Creating refund");
throw e;
} finally {
conn.setAutoCommit(true);
conn.close();
}
}
}

View File

@@ -1,129 +0,0 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.models.Service;
import org.example.petshopdesktop.util.ActivityLogger;
import java.sql.*;
public class ServiceDB {
//
// GET ALL SERVICES
//
public static ObservableList<Service> getServices() throws SQLException {
ObservableList<Service> list = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
String sql = "SELECT * FROM service";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
Service service = new Service(
rs.getInt("serviceId"),
rs.getString("serviceName"),
rs.getString("serviceDesc"),
rs.getInt("serviceDuration"),
rs.getDouble("servicePrice")
);
list.add(service);
}
conn.close();
return list;
}
//
// INSERT SERVICE
//
public static int insertService(Service service) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql =
"INSERT INTO service (serviceName, serviceDesc, serviceDuration, servicePrice) " +
"VALUES (?, ?, ?, ?)";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, service.getServiceName());
stmt.setString(2, service.getServiceDesc());
stmt.setInt(3, service.getServiceDuration());
stmt.setDouble(4, service.getServicePrice());
int rows = stmt.executeUpdate();
conn.close();
// Log the operation
if (rows > 0) {
ActivityLogger.getInstance().logInsert("service",
"N/A",
String.format("Service '%s' added", service.getServiceName()));
}
return rows;
}
//
// UPDATE SERVICE
//
public static int updateService(int id, Service service) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql =
"UPDATE service SET " +
"serviceName=?, serviceDesc=?, serviceDuration=?, servicePrice=? " +
"WHERE serviceId=?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, service.getServiceName());
stmt.setString(2, service.getServiceDesc());
stmt.setInt(3, service.getServiceDuration());
stmt.setDouble(4, service.getServicePrice());
stmt.setInt(5, id);
int rows = stmt.executeUpdate();
conn.close();
// Log the operation
if (rows > 0) {
ActivityLogger.getInstance().logUpdate("service",
String.valueOf(id),
String.format("Service '%s' updated", service.getServiceName()));
}
return rows;
}
//
// DELETE SERVICE
//
public static int deleteService(int id) throws SQLException {
Connection conn = ConnectionDB.getConnection();
String sql = "DELETE FROM service WHERE serviceId=?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, id);
int rows = stmt.executeUpdate();
conn.close();
// Log the operation
if (rows > 0) {
ActivityLogger.getInstance().logDelete("service",
String.valueOf(id),
String.format("Service ID %d deleted", id));
}
return rows;
}
}

View File

@@ -1,202 +0,0 @@
package org.example.petshopdesktop.database;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.example.petshopdesktop.models.Product;
import org.example.petshopdesktop.models.Supplier;
import org.example.petshopdesktop.util.ActivityLogger;
import java.sql.*;
/**
* A class containing all the methods relating to CRUD on Suppliers table
*/
public class SupplierDB {
/**
* gets all the suppliers into an observable list
* @return a list of all the suppliers
* @throws SQLException if failed to find suppliers in the database
*/
public static ObservableList<Supplier> getSuppliers() throws SQLException {
//Connect to the database
ObservableList<Supplier> suppliers = FXCollections.observableArrayList();
Connection conn = ConnectionDB.getConnection();
//Execute Query
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM supplier");
//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;
}
/**
* Inserts a new supplier to the database
* @param supplier supplier entity to be inserted
* @return number of rows affected in the database
* @throws SQLException if insertion failed
*/
public static int insertSupplier(Supplier supplier) throws SQLException {
int numRows = 0;
Connection conn = ConnectionDB.getConnection();
String sql = "INSERT INTO supplier (supId, supCompany, supContactFirstName, supContactLastName, supEmail, supPhone)" +
"VALUES (?, ?, ?, ?, ?, ?)";
//These are the values from supplier to put into the query above
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, supplier.getSupId());
stmt.setString(2, supplier.getSupCompany());
stmt.setString(3, supplier.getSupContactFirstName());
stmt.setString(4, supplier.getSupContactLastName());
stmt.setString(5, supplier.getSupEmail());
stmt.setString(6, supplier.getSupPhone());
//update the number of rows affected, return and close connection
numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logInsert("supplier",
String.valueOf(supplier.getSupId()),
String.format("Supplier '%s' added", supplier.getSupCompany()));
}
return numRows;
}
/**
* Update an existing supplier to the database
* @param supId id of supplier
* @param supplier new supplier data
* @return number of rows affected in the database
* @throws SQLException if update failed
*/
public static int updateSupplier(int supId, Supplier supplier) throws SQLException {
int numRows = 0;
Connection conn = ConnectionDB.getConnection();
String sql = "UPDATE supplier SET " +
" supCompany = ?, " +
" supContactFirstName = ?, " +
" supContactLastName = ?, " +
" supEmail = ?, " +
" supPhone = ? " +
" WHERE supId = ?";
//updated values to update the supplier with the query above
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, supplier.getSupCompany());
stmt.setString(2, supplier.getSupContactFirstName());
stmt.setString(3, supplier.getSupContactLastName());
stmt.setString(4, supplier.getSupEmail());
stmt.setString(5, supplier.getSupPhone());
stmt.setInt(6, supId);
//Update the rows and close connection
numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logUpdate("supplier",
String.valueOf(supId),
String.format("Supplier '%s' updated", supplier.getSupCompany()));
}
return numRows;
}
/**
* Delete a supplier form the database
* @param supId supplier id to be deleted
* @return number of rows affected in the database
* @throws SQLException if delete failed
*/
public static int deleteSupplier(int supId) throws SQLException {
int numRows = 0;
Connection conn = ConnectionDB.getConnection();
String sql = "DELETE FROM supplier WHERE supId = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
//The supplier id to be deleted for the query above
stmt.setInt(1, supId);
//close connection and update rows affected
numRows = stmt.executeUpdate();
conn.close();
// Log the operation
if (numRows > 0) {
ActivityLogger.getInstance().logDelete("supplier",
String.valueOf(supId),
String.format("Supplier ID %d deleted", supId));
}
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

@@ -1,198 +0,0 @@
package org.example.petshopdesktop.database;
import org.example.petshopdesktop.auth.Role;
import org.example.petshopdesktop.models.StaffAccount;
import org.example.petshopdesktop.models.User;
import org.example.petshopdesktop.util.ActivityLogger;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class UserDB {
public static User authenticate(String username, String password) throws SQLException {
String sql = "SELECT u.user_id, u.employee_id, u.username, u.role, e.firstName, e.lastName "
+ "FROM users u "
+ "JOIN employee e ON u.employee_id = e.employeeId "
+ "WHERE u.username = ? AND u.password_hash = SHA2(?, 256) AND e.isActive = TRUE";
try (Connection conn = ConnectionDB.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, username);
ps.setString(2, password);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
int userId = rs.getInt("user_id");
int employeeId = rs.getInt("employee_id");
String uname = rs.getString("username");
Role role = Role.valueOf(rs.getString("role").toUpperCase());
String firstName = rs.getString("firstName");
String lastName = rs.getString("lastName");
return new User(userId, employeeId, uname, firstName, lastName, role);
}
}
}
return null;
}
public static void initializeTable() throws SQLException {
String createTable = """
CREATE TABLE IF NOT EXISTS users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
employee_id INT NOT NULL,
username VARCHAR(100) NOT NULL UNIQUE,
password_hash CHAR(64) NOT NULL,
role ENUM('ADMIN','STAFF') NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
FOREIGN KEY (employee_id) REFERENCES employee(employeeId)
)
""";
try (Connection conn = ConnectionDB.getConnection();
Statement st = conn.createStatement()) {
st.executeUpdate(createTable);
}
ensureCompatibleSchema();
int adminEmployeeId = EmployeeDB.ensureDefaultEmployee("John", "Doe", "john@petshop.com", "111-222-3333", "Manager", true);
int staffEmployeeId = EmployeeDB.ensureDefaultEmployee("Sara", "Smith", "sara@petshop.com", "444-555-6666", "Staff", true);
ensureDefaultUser(adminEmployeeId, "admin", "admin123", Role.ADMIN);
ensureDefaultUser(staffEmployeeId, "staff", "staff123", Role.STAFF);
}
public static int createStaffAccount(String firstName, String lastName, String email, String phone, String username, String password) throws SQLException {
if (username == null || username.isBlank()) {
throw new SQLException("Username is required.");
}
if (password == null || password.isBlank()) {
throw new SQLException("Password is required.");
}
int storeId = EmployeeDB.getDefaultStoreId();
try (Connection conn = ConnectionDB.getConnection()) {
conn.setAutoCommit(false);
try {
int employeeId = EmployeeDB.createEmployee(conn, firstName, lastName, email, phone, "Staff", true);
EmployeeDB.assignEmployeeToStore(conn, employeeId, storeId);
String insertUser = "INSERT INTO users (employee_id, username, password_hash, role) VALUES (?, ?, SHA2(?, 256), 'STAFF')";
try (PreparedStatement ps = conn.prepareStatement(insertUser, Statement.RETURN_GENERATED_KEYS)) {
ps.setInt(1, employeeId);
ps.setString(2, username);
ps.setString(3, password);
ps.executeUpdate();
try (ResultSet keys = ps.getGeneratedKeys()) {
if (keys.next()) {
int userId = keys.getInt(1);
conn.commit();
ActivityLogger.getInstance().logInsert("users", String.valueOf(userId), "Created staff account: " + username);
return userId;
}
}
}
conn.rollback();
throw new SQLException("Could not create staff account.");
} catch (SQLException e) {
conn.rollback();
throw e;
} catch (RuntimeException e) {
conn.rollback();
throw e;
} finally {
conn.setAutoCommit(true);
}
}
}
public static List<StaffAccount> getStaffAccounts() throws SQLException {
String sql = "SELECT u.user_id, u.username, u.created_at, e.employeeId, e.firstName, e.lastName, e.email, e.phone, e.isActive "
+ "FROM users u "
+ "JOIN employee e ON u.employee_id = e.employeeId "
+ "WHERE u.role = 'STAFF' "
+ "ORDER BY u.created_at DESC";
List<StaffAccount> accounts = new ArrayList<>();
try (Connection conn = ConnectionDB.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
accounts.add(new StaffAccount(
rs.getInt("user_id"),
rs.getInt("employeeId"),
rs.getString("username"),
rs.getString("firstName"),
rs.getString("lastName"),
rs.getString("email"),
rs.getString("phone"),
rs.getBoolean("isActive"),
rs.getTimestamp("created_at")
));
}
}
return accounts;
}
private static void ensureCompatibleSchema() throws SQLException {
try (Connection conn = ConnectionDB.getConnection();
Statement st = conn.createStatement()) {
try {
st.executeUpdate("ALTER TABLE users ADD COLUMN employee_id INT NULL");
} catch (SQLException ignored) {
}
try {
st.executeUpdate("ALTER TABLE users ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL");
} catch (SQLException ignored) {
}
try {
st.executeUpdate("ALTER TABLE users ADD CONSTRAINT fk_users_employee FOREIGN KEY (employee_id) REFERENCES employee(employeeId)");
} catch (SQLException ignored) {
}
}
}
private static void ensureDefaultUser(int employeeId, String username, String password, Role role) throws SQLException {
String insert = "INSERT IGNORE INTO users (employee_id, username, password_hash, role) VALUES (?, ?, SHA2(?, 256), ?)";
String updateIfMissingEmployeeId = "UPDATE users SET employee_id = ? WHERE username = ? AND (employee_id IS NULL OR employee_id = 0)";
try (Connection conn = ConnectionDB.getConnection()) {
int rows;
try (PreparedStatement ps = conn.prepareStatement(insert)) {
ps.setInt(1, employeeId);
ps.setString(2, username);
ps.setString(3, password);
ps.setString(4, role.name());
rows = ps.executeUpdate();
}
try (PreparedStatement ps = conn.prepareStatement(updateIfMissingEmployeeId)) {
ps.setInt(1, employeeId);
ps.setString(2, username);
ps.executeUpdate();
}
if (rows > 0) {
ActivityLogger.getInstance().logInsert("users", username, "Default " + role.name().toLowerCase() + " user created");
}
}
}
}