Merge pull request 'Develop' (#1) from develop into main

Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
2026-07-07 19:26:37 +00:00
15 changed files with 694 additions and 155 deletions
+47 -106
View File
@@ -1,141 +1,82 @@
-- Restaurant Database Management System
--
-- Instructions:
-- 1. Create all required tables.
-- 2. Design appropriate PRIMARY KEY and FOREIGN KEY relationships.
-- 3. Add suitable constraints based on the requirements.
-- 4. Insert initial mock data.
-- 5. Insert at least 3 menu items.
-- 6. The script should be executable from start to finish without errors.
-- =======================================================
-- USER TABLE
-- =======================================================
--
-- Represents customers using the system.
--
-- Required information:
-- - Unique identifier
-- - Username
-- - Password
-- - Email (optional)
--
-- Requirements:
-- - Each user must have a unique identifier.
-- - Usernames must be unique.
-- - Username and password are required.
-- - Passwords should not be stored in plain text.
--
-- CREATE TABLE ...
CREATE TABLE users(
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
email VARCHAR(250)
);
-- =======================================================
-- MENU ITEM TABLE
-- =======================================================
--
-- Represents available food and drink items.
--
-- Required information:
-- - Unique identifier
-- - Name
-- - Description (optional)
-- - Price
-- - Category (optional)
--
-- Requirements:
-- - Each menu item must have a unique identifier.
-- - Name is required.
-- - Price must always be positive.
--
-- CREATE TABLE ...
CREATE TABLE menu_items(
id SERIAL PRIMARY KEY,
name VARCHAR(250) NOT NULL,
description TEXT,
price NUMERIC NOT NULL CHECK (price > 0),
category VARCHAR(50)
);
-- =======================================================
-- ORDER TABLE
-- =======================================================
--
-- Represents orders placed by customers.
--
-- Required information:
-- - Unique identifier
-- - Reference to customer
-- - Creation date and time
-- - Total price
--
-- Requirements:
-- - Each order must belong to exactly one user.
-- - A user can have multiple orders.
-- - The relationship between User and Order must be implemented.
--
-- Note:
-- Avoid using reserved SQL keywords as table names.
-- Consider using a name such as "orders" or "customer_orders".
--
-- CREATE TABLE ...
CREATE TABLE user_orders (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
created_at TIMESTAMP NOT NULL,
total_price NUMERIC NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- =======================================================
-- ORDER DETAIL TABLE
-- =======================================================
--
-- Represents items inside an order.
--
-- Required information:
-- - Unique identifier
-- - Reference to an order
-- - Reference to a menu item
-- - Quantity
-- - Item price at purchase time
--
-- Requirements:
-- - Each detail record must belong to one order.
-- - Each detail record must reference one menu item.
-- - Quantity must always be greater than zero.
-- - Store the item's price at the moment of purchase.
--
-- CREATE TABLE ...
CREATE TABLE order_details(
id SERIAL PRIMARY KEY,
order_id INT NOT NULL,
menu_id INT NOT NULL,
quantity NUMERIC NOT NULL CHECK (quantity > 0),
item_price NUMERIC NOT NULL CHECK (item_price > 0),
FOREIGN KEY (order_id) REFERENCES user_orders(id),
FOREIGN KEY (menu_id) REFERENCES menu_items(id)
);
-- =======================================================
-- INITIAL MENU DATA
-- =======================================================
--
-- Insert at least 3 food or drink items.
--
-- Example categories:
-- - Pizza
-- - Burger
-- - Pasta
-- - Drink
--
-- INSERT INTO ...
-- =======================================================
-- OPTIONAL TEST DATA
-- =======================================================
--
-- You may insert sample users and orders for testing.
-- This section is optional.
--
-- INSERT INTO ...
INSERT INTO menu_items (name, description, price, category) VALUES
('Margherita Pizza', 'Classic pizza with tomato sauce, mozzarella, and basil.', 12.99, 'Pizza'),
('Pepperoni Pizza', NULL, 14.49, 'Pizza'),
('Cheeseburger', 'Beef patty with cheddar cheese, lettuce, and tomato.', 10.99, 'Burger'),
('Chicken Burger', NULL, 11.49, 'Burger'),
('Caesar Salad', 'Romaine lettuce, croutons, parmesan, and Caesar dressing.', 8.99, 'Salad'),
('Greek Salad', NULL, 9.49, 'Salad'),
('French Fries', 'Crispy golden potato fries.', 4.99, 'Side'),
('Onion Rings', NULL, 5.49, 'Side'),
('Espresso', NULL, 2.99, 'Drink'),
('Cappuccino', 'Espresso with steamed milk and milk foam.', 4.49, 'Drink');
-- =======================================================
-- VERIFICATION QUERIES
-- =======================================================
--
-- Uncomment these queries to verify your database.
--
-- SELECT * FROM ...;
-- SELECT * FROM ...;
-- SELECT * FROM ...;
-- SELECT * FROM ...;
SELECT * FROM users;
SELECT * FROM menu_items;
SELECT * FROM user_orders;
SELECT * FROM order_details;
+54 -5
View File
@@ -1,24 +1,73 @@
package dev.dao;
import dev.database.DatabaseConnection;
import dev.model.MenuItem;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class MenuItemDao {
public List<MenuItem> findAll() {
// TODO:
// Retrieve all menu items
String sql = "SELECT * FROM menu_items";
List<MenuItem> items = new ArrayList<>();
return null;
try (PreparedStatement ps = DatabaseConnection
.getConnection()
.prepareStatement(sql))
{
ResultSet rs = ps.executeQuery();
while (rs.next())
{
MenuItem menuItem = new MenuItem();
menuItem.setId(rs.getInt("id"));
menuItem.setName(rs.getString("name"));
menuItem.setDescription(rs.getString("description"));
menuItem.setPrice(rs.getDouble("price"));
menuItem.setCategory(rs.getString("category"));
items.add(menuItem);
}
} catch (SQLException e) {
System.out.println(e.getStackTrace());
}
return items;
}
public MenuItem findById(int id) {
// TODO:
// Find menu item by id
String sql = "SELECT * FROM menu_items WHERE id=?";
try(PreparedStatement ps = DatabaseConnection
.getConnection()
.prepareStatement(sql))
{
ps.setInt(1,id);
ResultSet rs = ps.executeQuery();
if(rs.next())
{
MenuItem item = new MenuItem();
item.setId(rs.getInt("id"));
item.setName(rs.getString("name"));
item.setDescription(rs.getString("description"));
item.setPrice(rs.getDouble("price"));
item.setCategory(rs.getString("category"));
return item;
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return null;
}
+55 -5
View File
@@ -1,25 +1,75 @@
package dev.dao;
import dev.database.DatabaseConnection;
import dev.model.Order;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
public class OrderDao {
public int save(Order order) {
// TODO:
// Insert order and return generated id
String sql = "INSERT INTO user_orders(user_id, created_at, total_price) VALUES(?,?,?)";
try (PreparedStatement ps = DatabaseConnection
.getConnection()
.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS))
{
ps.setInt(1, order.getUserId());
ps.setTimestamp(2, Timestamp.valueOf(order.getCreatedAt()));
ps.setDouble(3, order.getTotalPrice());
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if(rs.next()) return rs.getInt(1);
} catch (SQLException e) {
e.printStackTrace();
}
return -1;
}
public List<Order> findByUserId(int userId) {
// TODO:
// Retrieve all orders of a user
List<Order> orders = new ArrayList<>();
String sql = "SELECT * FROM user_orders WHERE user_id=?";
return null;
try(PreparedStatement ps = DatabaseConnection
.getConnection()
.prepareStatement(sql))
{
ps.setInt(1,userId);
ResultSet rs = ps.executeQuery();
while(rs.next())
{
Order order = new Order();
order.setId(rs.getInt("id"));
order.setUserId(rs.getInt("user_id"));
order.setTotalPrice(rs.getDouble("total_price"));
order.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
orders.add(order);
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return orders;
}
}
+51 -5
View File
@@ -1,24 +1,70 @@
package dev.dao;
import dev.database.DatabaseConnection;
import dev.model.OrderDetail;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class OrderDetailDao {
public void save(OrderDetail detail) {
// TODO:
// Insert order detail
String sql = "INSERT INTO order_details (order_id, menu_id, quantity, item_price) VALUES (?,?,?,?)";
try (PreparedStatement ps = DatabaseConnection
.getConnection()
.prepareStatement(sql))
{
ps.setInt(1,detail.getOrderId());
ps.setInt(2,detail.getMenuItemId());
ps.setInt(3,detail.getQuantity());
ps.setDouble(4,detail.getPrice());
ps.executeUpdate();
} catch (SQLException e) {
System.out.println(e.getStackTrace());
}
}
public List<OrderDetail> findByOrderId(int orderId) {
// TODO:
// Retrieve order details
String sql = "SELECT * FROM order_details WHERE order_id=?";
return null;
List<OrderDetail> details = new ArrayList<>();
try (PreparedStatement ps = DatabaseConnection
.getConnection()
.prepareStatement(sql))
{
ps.setInt(1,orderId);
ResultSet rs = ps.executeQuery();
while(rs.next())
{
OrderDetail detail = new OrderDetail();
detail.setOrderId(rs.getInt("order_id"));
detail.setMenuItemId(rs.getInt("menu_id"));
detail.setPrice(rs.getDouble("item_price"));
detail.setQuantity(rs.getInt("quantity"));
details.add(detail);
}
} catch (SQLException e) {
System.out.println(e.getStackTrace());
}
return details;
}
}
+40 -5
View File
@@ -1,23 +1,58 @@
package dev.dao;
import dev.database.DatabaseConnection;
import dev.model.User;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UserDao {
public boolean save(User user) {
// TODO:
// Insert user into database
String sql = "INSERT INTO users (username, password_hash, email) VALUES (?, ?, ?)";
try {
PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement(sql);
ps.setString(1, user.getUsername());
ps.setString(2, user.getPasswordHash());
ps.setString(3, user.getEmail());
ps.executeUpdate();
return true;
} catch (SQLException e) {
System.out.println("fail to save user: " + e.getMessage());
}
return false;
}
public User findByUsername(String username) {
// TODO:
// Find a user by username
String sql = "SELECT * FROM users WHERE username=?";
return null;
User result = null;
try {
PreparedStatement stmt = DatabaseConnection.getConnection().prepareStatement(sql);
stmt.setString(1, username);
ResultSet rs = stmt.executeQuery();
if (rs.next()){
result = new User(
rs.getInt("id"),
rs.getString("username"),
rs.getString("password_hash"),
rs.getString("email")
);
}
} catch (SQLException e) {
System.err.println("Unable to find user: " + e.getMessage());
}
return result;
}
}
@@ -1,6 +1,7 @@
package dev.database;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseConnection {
@@ -9,7 +10,7 @@ public class DatabaseConnection {
private static final String USER = "postgres"; // Your Username
private static final String PASSWORD = "password"; // Your Password
private static final String PASSWORD = "FinalProjectDev"; // Your Password
private DatabaseConnection() {
@@ -17,11 +18,7 @@ public class DatabaseConnection {
public static Connection getConnection()
throws SQLException {
// TODO:
// Return a valid PostgreSQL connection
return null;
return DriverManager.getConnection(URL,USER,PASSWORD);
}
}
+23
View File
@@ -0,0 +1,23 @@
package dev.model;
public class CartItem {
private final MenuItem item;
private final int quantity;
public CartItem(MenuItem item, int quantity) {
this.item = item;
this.quantity = quantity;
}
public MenuItem getItem() {
return item;
}
public int getQuantity() {
return quantity;
}
public double getSubtotal() {
return item.getPrice() * quantity;
}
}
+40
View File
@@ -12,4 +12,44 @@ public class MenuItem {
private String category;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
}
+27
View File
@@ -12,4 +12,31 @@ public class Order {
private double totalPrice;
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public double getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(double totalPrice) {
this.totalPrice = totalPrice;
}
public int getId() { return id; }
public void setId(int id) {
this.id = id;
}
}
+16
View File
@@ -12,4 +12,20 @@ public class OrderDetail {
private double price;
public int getOrderId() { return orderId; }
public void setOrderId( int orderId ) { this.orderId = orderId; }
public int getMenuItemId() { return menuItemId; }
public void setMenuItemId(int menuItemId) { this.menuItemId = menuItemId; }
public int getQuantity() { return quantity; }
public void setQuantity(int quantity) { this.quantity = quantity; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
}
+33
View File
@@ -10,4 +10,37 @@ public class User {
private String email;
public User(int id, String username, String passwordHash, String email) {
this.id = id;
this.username = username;
this.password = passwordHash;
this.email = email;
}
public User(String username, String passwordHash, String email) {
this.username = username;
this.password = passwordHash;
this.email = email;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public String getPasswordHash() {
return password;
}
public String getEmail() {
return email;
}
}
+44 -4
View File
@@ -1,23 +1,63 @@
package dev.service;
import dev.dao.UserDao;
import dev.model.User;
import java.util.Objects;
public class AuthService {
private final UserDao userDao = new UserDao();
public boolean register(String username, String password, String email) {
// TODO:
// Validate and register user
if (!isValidEmail(email)){
System.err.println("Invalid email address.");
return false;
}
User user = new User(
username,
String.valueOf(password.hashCode()),
email
);
if (userDao.save(user)){
System.out.println("Successfully registered user");
return true;
}
return false;
}
public User login(String username, String password) {
// TODO:
// Authenticate user
User dbUser = userDao.findByUsername(username);
if (dbUser == null){
return null;
}
String dbUserPasswordHash = dbUser.getPasswordHash();
if (Objects.equals(dbUserPasswordHash,
String.valueOf(password.hashCode()))){
return dbUser;
}
return null;
}
public boolean isValidEmail(String email) {
if (email == null || email.isBlank()) {
return true;
}
int atIndex = email.indexOf('@');
if (atIndex <= 0) return false;
int dotIndex = email.lastIndexOf('.');
if (dotIndex <= atIndex + 1) return false;
if (dotIndex == email.length() - 1) return false;
return true;
}
}
+68 -2
View File
@@ -1,11 +1,77 @@
package dev.service;
import dev.dao.MenuItemDao;
import dev.model.MenuItem;
import dev.model.User;
import java.util.List;
import java.util.Scanner;
public class MenuService {
public static final MenuItemDao menuItemDao = new MenuItemDao();
public void showMenu() {
// TODO:
// Display menu items
List<MenuItem> items = menuItemDao.findAll();
System.out.println("=======================");
System.out.println("== MENU ==");
System.out.println("=======================");
for (MenuItem item : items) {
System.out.format("[%d] %s - $%.2f\n%s\nCategory: %s\n",
item.getId(),
item.getName(),
item.getPrice(),
item.getDescription(),
item.getCategory()
);
}
}
public void ShowPanel(User user) {
OrderService orderService = new OrderService();
while (true) {
System.out.println("=======================");
System.out.println("== WELCOME ==");
System.out.println("=======================");
System.out.println("""
1.Place order
2.Order history
3.Logout
""");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
switch (choice) {
case 1: {
orderService.placeOrder(user.getId());
break;
}
case 2: {
orderService.showOrderHistory(user.getId());
break;
}
case 3: {
System.out.println("goodbye, " + user.getUsername());
return;
}
default:{
System.out.println("invalid choice.enter a number between [1,3]");
}
}
}
}
+149 -6
View File
@@ -1,26 +1,169 @@
package dev.service;
import dev.dao.OrderDao;
import dev.dao.OrderDetailDao;
import dev.model.CartItem;
import dev.model.MenuItem;
import dev.model.Order;
import dev.model.OrderDetail;
import java.awt.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class OrderService {
private final static OrderDetailDao orderDetailDao = new OrderDetailDao();
private final static OrderDao orderDao = new OrderDao();
private final static MenuService menuService = new MenuService();
private final static Scanner scanner = new Scanner(System.in);
public void placeOrder(int userId) {
// TODO:
// Create order
List<CartItem> cart = buildCart(scanner);
if (cart == null || cart.isEmpty()) {
System.err.println("The cart is empty. Order placement aborted.");
return;
}
double totalPrice = 0;
for (CartItem cartItem: cart) {
totalPrice += cartItem.getSubtotal();
}
Order order = new Order();
order.setUserId(userId);
order.setCreatedAt(LocalDateTime.now());
order.setTotalPrice(totalPrice);
int orderId = orderDao.save(order);
if (orderId == -1) {
System.err.println("Order could not be placed (Database error).");
return;
}
order.setId(orderId);
for (CartItem cartItem : cart){
OrderDetail orderDetail = new OrderDetail();
orderDetail.setOrderId(orderId);
orderDetail.setMenuItemId( cartItem.getItem().getId());
orderDetail.setQuantity(cartItem.getQuantity());
orderDetail.setPrice(cartItem.getItem().getPrice());
orderDetailDao.save(orderDetail);
}
printReceipt(orderId);
System.out.println("Order saved successfully.");
}
public void printReceipt(int orderId) {
// TODO:
// Print order receipt
List<OrderDetail> details = orderDetailDao.findByOrderId(orderId);
System.out.println("\n--- order receipt: " + orderId + " ---");
System.out.printf("%-15s %-5s %-10s%n", "name", "quantity", "totalPrice");
double total = 0;
for (OrderDetail d : details) {
MenuItem item = MenuService.menuItemDao.findById(d.getMenuItemId());
double sub = d.getPrice() * d.getQuantity();
total += sub;
System.out.printf("%-15s %-5d %-10.2f%n", item.getName(), d.getQuantity(), sub);
}
System.out.println("------------------------------");
System.out.printf("totalPrice: %.2f%n", total);
}
public void showOrderHistory(int userId) {
// TODO:
// Display user's order history
List<Order> orders = orderDao.findByUserId(userId);
if (orders.isEmpty())
{
System.out.println("No orders found.");
return;
}
System.out.println("\n===== ORDER HISTORY =====");
for (Order order : orders)
{
System.out.println("Order ID: " + order.getId()
+ " | Total: $" + order.getTotalPrice()
+ " | Date: " + order.getCreatedAt()
);
}
}
public List<CartItem> buildCart(Scanner scanner) {
List<CartItem> cart = new ArrayList<>();
menuService.showMenu();
while(true) {
System.out.println("\n[0] End order");
System.out.println("[-1] Show menu again");
System.out.println("Please select an item number:");
if (!scanner.hasNextInt()) {
System.err.println("Invalid input. Please enter a number.");
scanner.next();
continue;
}
int choice = scanner.nextInt();
if (choice == -1) {
menuService.showMenu();
continue;
}
if (choice == 0) {
if (cart.isEmpty()) {
System.out.println("Your cart is empty. Please select items.");
continue;
}
break;
}
MenuItem item = MenuService.menuItemDao.findById(choice);
if (item == null) {
System.err.println("Invalid item ID, please try again.");
continue;
}
System.out.println("Enter quantity for " + item.getName() + ": ");
if (!scanner.hasNextInt()) {
System.err.println("Invalid quantity input. Please enter a number.");
scanner.next();
continue;
}
int quantity = scanner.nextInt();
if (quantity <= 0){
System.err.println("Invalid quantity. Must be greater than 0.");
continue;
}
cart.add(new CartItem(item, quantity));
System.out.println(quantity + "x " + item.getName() + " added to cart.");
}
return cart;
}
}
+44 -11
View File
@@ -1,5 +1,9 @@
package dev.ui;
import dev.model.User;
import dev.service.AuthService;
import dev.service.MenuService;
import java.util.Scanner;
public class ConsoleMenu {
@@ -7,6 +11,8 @@ public class ConsoleMenu {
private final Scanner scanner =
new Scanner(System.in);
private AuthService authService = new AuthService();
public void start() {
while (true) {
@@ -18,23 +24,50 @@ public class ConsoleMenu {
System.out.println("3. Exit");
int choice = scanner.nextInt();
scanner.nextLine();
switch (choice) {
case 1:
// TODO
break;
case 1: {
System.out.print("Enter your username: ");
String username = scanner.nextLine();
System.out.print("Enter your password: ");
String password = scanner.nextLine();
case 2:
// TODO
break;
User user = authService.login(username, password);
case 3:
if (user == null) {
System.err.println("Unable to login.");
continue;
}
MenuService menuService = new MenuService();
menuService.ShowPanel(user);
break;
}
case 2: {
System.out.print("Enter your username: ");
String username = scanner.nextLine();
System.out.print("Enter your password: ");
String password = scanner.nextLine();
System.out.print("Enter your email (optional): ");
String tmp = scanner.nextLine();
String email = tmp.isEmpty() ? null : tmp;
if (!authService.register(username, password, email)) {
System.err.println("Registration failed.");
continue;
}
System.out.println("Registration successful!");
break;
}
case 3: {
return;
default:
System.out.println("Invalid choice");
}
default: {
System.out.println("Invalid choice enter a number between [1, 3]");
}
}
}