Restaurant Database Management System #1

Open
faraz_ardeh wants to merge 1 commits from develop into main
20 changed files with 896 additions and 159 deletions
+10
View File
@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="WS-10-Database" />
</profile>
</annotationProcessing>
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="25" project-jdk-type="JavaSDK" />
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+59 -104
View File
@@ -1,141 +1,96 @@
-- 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.
-- This script creates the whole schema from scratch and inserts some
-- initial data. It can be run from start to finish without errors.
--
-- Run with: psql -U postgres -d restaurant_db -f database.sql
-- Drop old tables first so the script is re-runnable.
-- Order matters because of the foreign keys (drop children before parents).
DROP TABLE IF EXISTS order_details CASCADE;
DROP TABLE IF EXISTS orders CASCADE;
DROP TABLE IF EXISTS menu_items CASCADE;
DROP TABLE IF EXISTS users CASCADE;
-- =======================================================
-- 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 ...
-- Passwords are stored as a hash (never plain text) by the Java app.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL, -- SHA-256 hex hash
email VARCHAR(255) -- optional
);
-- =======================================================
-- 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(100) NOT NULL,
description TEXT, -- optional
price NUMERIC(10, 2) NOT NULL CHECK (price > 0),
category VARCHAR(50) -- optional
);
-- =======================================================
-- ORDER TABLE
-- ORDER TABLE ("order" is a reserved word, so we use "orders")
-- =======================================================
--
-- 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 ...
-- Each order belongs to exactly one user (One-to-Many: user -> orders).
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL REFERENCES users(id),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
total_price NUMERIC(10, 2) NOT NULL DEFAULT 0 CHECK (total_price >= 0)
);
-- =======================================================
-- 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 ...
-- One line inside an order (One-to-Many: order -> order_details).
-- "price" is the item price at the moment of purchase, so history stays
-- correct even if the menu price changes later.
CREATE TABLE order_details (
id SERIAL PRIMARY KEY,
order_id INT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
menu_item_id INT NOT NULL REFERENCES menu_items(id),
quantity INT NOT NULL CHECK (quantity > 0),
price NUMERIC(10, 2) NOT NULL CHECK (price > 0)
);
-- =======================================================
-- INITIAL MENU DATA
-- INITIAL MENU DATA (at least 3 items)
-- =======================================================
--
-- Insert at least 3 food or drink items.
--
-- Example categories:
-- - Pizza
-- - Burger
-- - Pasta
-- - Drink
--
-- INSERT INTO ...
INSERT INTO menu_items (name, description, price, category) VALUES
('Margherita Pizza', 'Classic pizza with tomato, mozzarella and basil', 10.00, 'Pizza'),
('Cheeseburger', 'Beef patty with cheddar, lettuce and tomato', 8.00, 'Burger'),
('Pasta Bolognese', 'Spaghetti with rich beef and tomato sauce', 12.00, 'Pasta'),
('Caesar Salad', 'Romaine, croutons, parmesan and Caesar dressing', 6.50, 'Salad'),
('Coca-Cola', 'Chilled 330ml can', 2.50, 'Drink');
-- =======================================================
-- OPTIONAL TEST DATA
-- =======================================================
--
-- You may insert sample users and orders for testing.
-- This section is optional.
--
-- INSERT INTO ...
-- Sample user. The password below is the SHA-256 hash of the text "1234"
-- so you can log in with username "admin" / password "1234" for testing.
INSERT INTO users (username, password, email) VALUES
('admin', '03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4', 'admin@pizzeria.com');
-- =======================================================
-- VERIFICATION QUERIES
-- VERIFICATION QUERIES (optional, uncomment to check)
-- =======================================================
--
-- Uncomment these queries to verify your database.
--
-- SELECT * FROM ...;
-- SELECT * FROM ...;
-- SELECT * FROM ...;
-- SELECT * FROM ...;
-- SELECT * FROM users;
-- SELECT * FROM menu_items;
-- SELECT * FROM orders;
-- SELECT * FROM order_details;
+50 -6
View File
@@ -1,25 +1,69 @@
package dev.dao;
import dev.database.DatabaseConnection;
import dev.model.MenuItem;
import java.sql.Connection;
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
List<MenuItem> items = new ArrayList<>();
return null;
String sql = "SELECT id, name, description, price, category FROM menu_items ORDER BY id";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
items.add(mapRow(rs));
}
} catch (SQLException e) {
System.out.println("Error while loading menu: " + e.getMessage());
}
return items;
}
public MenuItem findById(int id) {
// TODO:
// Find menu item by id
String sql = "SELECT id, name, description, price, category FROM menu_items WHERE id = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, id);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return mapRow(rs);
}
}
} catch (SQLException e) {
System.out.println("Error while finding menu item: " + e.getMessage());
}
return null;
}
}
/** Turns the current row of a ResultSet into a MenuItem object. */
private MenuItem mapRow(ResultSet rs) throws SQLException {
return new MenuItem(
rs.getInt("id"),
rs.getString("name"),
rs.getString("description"),
rs.getDouble("price"),
rs.getString("category")
);
}
}
+61 -6
View File
@@ -1,25 +1,80 @@
package dev.dao;
import dev.database.DatabaseConnection;
import dev.model.Order;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
public class OrderDao {
/**
* Inserts an order and returns the id the database generated for it.
* Returns -1 if something went wrong. We let the DB fill in created_at
* with its DEFAULT, and only send user_id and total_price.
*/
public int save(Order order) {
// TODO:
// Insert order and return generated id
String sql = "INSERT INTO orders (user_id, total_price) VALUES (?, ?)";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement stmt =
conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
stmt.setInt(1, order.getUserId());
stmt.setDouble(2, order.getTotalPrice());
stmt.executeUpdate();
// Read back the auto-generated id (SERIAL primary key).
try (ResultSet keys = stmt.getGeneratedKeys()) {
if (keys.next()) {
return keys.getInt(1);
}
}
} catch (SQLException e) {
System.out.println("Error while saving order: " + e.getMessage());
}
return -1;
}
public List<Order> findByUserId(int userId) {
// TODO:
// Retrieve all orders of a user
List<Order> orders = new ArrayList<>();
return null;
String sql = "SELECT id, user_id, created_at, total_price " +
"FROM orders WHERE user_id = ? ORDER BY created_at DESC";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, userId);
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
Timestamp ts = rs.getTimestamp("created_at");
orders.add(new Order(
rs.getInt("id"),
rs.getInt("user_id"),
ts.toLocalDateTime(),
rs.getDouble("total_price")
));
}
}
} catch (SQLException e) {
System.out.println("Error while loading orders: " + e.getMessage());
}
return orders;
}
}
}
+48 -6
View File
@@ -1,24 +1,66 @@
package dev.dao;
import dev.database.DatabaseConnection;
import dev.model.OrderDetail;
import java.sql.Connection;
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_item_id, quantity, price) " +
"VALUES (?, ?, ?, ?)";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, detail.getOrderId());
stmt.setInt(2, detail.getMenuItemId());
stmt.setInt(3, detail.getQuantity());
stmt.setDouble(4, detail.getPrice());
stmt.executeUpdate();
} catch (SQLException e) {
System.out.println("Error while saving order detail: " + e.getMessage());
}
}
public List<OrderDetail> findByOrderId(int orderId) {
// TODO:
// Retrieve order details
List<OrderDetail> details = new ArrayList<>();
return null;
String sql = "SELECT id, order_id, menu_item_id, quantity, price " +
"FROM order_details WHERE order_id = ? ORDER BY id";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, orderId);
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
details.add(new OrderDetail(
rs.getInt("id"),
rs.getInt("order_id"),
rs.getInt("menu_item_id"),
rs.getInt("quantity"),
rs.getDouble("price")
));
}
}
} catch (SQLException e) {
System.out.println("Error while loading order details: " + e.getMessage());
}
return details;
}
}
}
+51 -6
View File
@@ -1,23 +1,68 @@
package dev.dao;
import dev.database.DatabaseConnection;
import dev.model.User;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UserDao {
/**
* Inserts a new user. The password passed in here is expected to already
* be hashed by the service layer. Returns true if the insert worked.
*/
public boolean save(User user) {
// TODO:
// Insert user into database
String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
return false;
// try-with-resources closes the connection and statement automatically.
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, user.getUsername());
stmt.setString(2, user.getPassword());
stmt.setString(3, user.getEmail());
int rows = stmt.executeUpdate();
return rows > 0;
} catch (SQLException e) {
System.out.println("Error while saving user: " + e.getMessage());
return false;
}
}
/**
* Looks up a user by username. Returns null if nobody matches.
*/
public User findByUsername(String username) {
// TODO:
// Find a user by username
String sql = "SELECT id, username, password, email FROM users WHERE username = ?";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, username);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return new User(
rs.getInt("id"),
rs.getString("username"),
rs.getString("password"),
rs.getString("email")
);
}
}
} catch (SQLException e) {
System.out.println("Error while finding user: " + e.getMessage());
}
return null;
}
}
}
@@ -1,8 +1,13 @@
package dev.database;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* Small helper that hands out PostgreSQL connections.
* Every DAO calls getConnection() when it needs to talk to the database.
*/
public class DatabaseConnection {
private static final String URL = "jdbc:postgresql://localhost:5432/restaurant_db"; // DB Server
@@ -18,10 +23,10 @@ public class DatabaseConnection {
public static Connection getConnection()
throws SQLException {
// TODO:
// Return a valid PostgreSQL connection
return null;
// DriverManager opens a fresh TCP connection to PostgreSQL using the
// JDBC URL and credentials above. The postgresql driver on the
// classpath registers itself automatically, so no Class.forName needed.
return DriverManager.getConnection(URL, USER, PASSWORD);
}
}
}
+52 -1
View File
@@ -12,4 +12,55 @@ public class MenuItem {
private String category;
}
public MenuItem() {
}
public MenuItem(int id, String name, String description, double price, String category) {
this.id = id;
this.name = name;
this.description = description;
this.price = price;
this.category = 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;
}
}
+43 -1
View File
@@ -12,4 +12,46 @@ public class Order {
private double totalPrice;
}
public Order() {
}
public Order(int id, int userId, LocalDateTime createdAt, double totalPrice) {
this.id = id;
this.userId = userId;
this.createdAt = createdAt;
this.totalPrice = totalPrice;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public double getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(double totalPrice) {
this.totalPrice = totalPrice;
}
}
+57 -1
View File
@@ -12,4 +12,60 @@ public class OrderDetail {
private double price;
}
public OrderDetail() {
}
public OrderDetail(int id, int orderId, int menuItemId, int quantity, double price) {
this.id = id;
this.orderId = orderId;
this.menuItemId = menuItemId;
this.quantity = quantity;
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
/** Convenience: price for this line = unit price * quantity. */
public double getSubtotal() {
return price * quantity;
}
}
+42
View File
@@ -10,4 +10,46 @@ public class User {
private String email;
public User() {
}
public User(int id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
+63 -7
View File
@@ -1,23 +1,79 @@
package dev.service;
import dev.dao.UserDao;
import dev.model.User;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class AuthService {
private final UserDao userDao = new UserDao();
/**
* Registers a new user. Checks the username is free and that the fields
* are not empty, then stores the password as a SHA-256 hash.
* Returns true only if the account was actually created.
*/
public boolean register(String username, String password, String email) {
// TODO:
// Validate and register user
if (username == null || username.isBlank()
|| password == null || password.isBlank()) {
System.out.println("Username and password are required.");
return false;
}
return false;
// Username must be unique.
if (userDao.findByUsername(username) != null) {
System.out.println("That username is already taken.");
return false;
}
User user = new User();
user.setUsername(username);
user.setPassword(hash(password)); // never store plain text
user.setEmail(email == null || email.isBlank() ? null : email);
return userDao.save(user);
}
/**
* Checks the given credentials against the database.
* Returns the User on success, or null if the username does not exist
* or the password is wrong.
*/
public User login(String username, String password) {
// TODO:
// Authenticate user
User user = userDao.findByUsername(username);
if (user == null) {
return null; // no such username
}
return null;
// Hash the entered password and compare with the stored hash.
if (user.getPassword().equals(hash(password))) {
return user;
}
return null; // wrong password
}
}
/** Hashes text with SHA-256 and returns it as a lowercase hex string. */
private String hash(String text) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] bytes = digest.digest(text.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
// SHA-256 is always available, so this should never happen.
throw new RuntimeException("SHA-256 not available", e);
}
}
}
+33 -5
View File
@@ -1,12 +1,40 @@
package dev.service;
import dev.dao.MenuItemDao;
import dev.model.MenuItem;
import java.util.List;
public class MenuService {
public void showMenu() {
// TODO:
// Display menu items
private final MenuItemDao menuItemDao = new MenuItemDao();
/** Loads every menu item so other parts of the app can use them. */
public List<MenuItem> getMenu() {
return menuItemDao.findAll();
}
}
/** Prints the whole menu to the console in a simple table. */
public void showMenu() {
List<MenuItem> items = menuItemDao.findAll();
if (items.isEmpty()) {
System.out.println("The menu is empty.");
return;
}
System.out.println("---------------------------------------------");
System.out.printf("%-4s %-20s %-10s %-10s%n", "ID", "Name", "Price", "Category");
System.out.println("---------------------------------------------");
for (MenuItem item : items) {
String category = item.getCategory() == null ? "-" : item.getCategory();
System.out.printf("%-4d %-20s $%-9.2f %-10s%n",
item.getId(), item.getName(), item.getPrice(), category);
}
System.out.println("---------------------------------------------");
}
}
+149 -7
View File
@@ -1,26 +1,168 @@
package dev.service;
import dev.dao.MenuItemDao;
import dev.dao.OrderDao;
import dev.dao.OrderDetailDao;
import dev.model.MenuItem;
import dev.model.Order;
import dev.model.OrderDetail;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class OrderService {
private final MenuItemDao menuItemDao = new MenuItemDao();
private final OrderDao orderDao = new OrderDao();
private final OrderDetailDao orderDetailDao = new OrderDetailDao();
private final Scanner scanner;
/** The Scanner is shared with the console UI so input stays consistent. */
public OrderService(Scanner scanner) {
this.scanner = scanner;
}
/**
* Lets the logged-in user build an order item by item, then stores the
* Order and its OrderDetail rows in the database and prints a receipt.
*/
public void placeOrder(int userId) {
// TODO:
// Create order
List<MenuItem> menu = menuItemDao.findAll();
if (menu.isEmpty()) {
System.out.println("Sorry, there is nothing on the menu right now.");
return;
}
System.out.println("\nAvailable Items:");
for (MenuItem item : menu) {
System.out.printf("%d. %s - $%.2f%n", item.getId(), item.getName(), item.getPrice());
}
// The "cart": order lines the user has chosen so far.
List<OrderDetail> cart = new ArrayList<>();
while (true) {
System.out.print("\nEnter the ID of the item to add (or 0 to finish): ");
int itemId = readInt();
if (itemId == 0) {
break;
}
MenuItem item = menuItemDao.findById(itemId);
if (item == null) {
System.out.println("No item with that ID. Try again.");
continue;
}
System.out.print("Enter quantity: ");
int quantity = readInt();
if (quantity <= 0) {
System.out.println("Quantity must be at least 1.");
continue;
}
// Store the current price so the receipt stays correct later.
OrderDetail line = new OrderDetail();
line.setMenuItemId(item.getId());
line.setQuantity(quantity);
line.setPrice(item.getPrice());
cart.add(line);
System.out.printf("Added %dx %s to your cart.%n", quantity, item.getName());
}
if (cart.isEmpty()) {
System.out.println("Your cart is empty, order cancelled.");
return;
}
// Work out the grand total.
double total = 0;
for (OrderDetail line : cart) {
total += line.getSubtotal();
}
// Save the order first so we get its generated id.
Order order = new Order();
order.setUserId(userId);
order.setTotalPrice(total);
int orderId = orderDao.save(order);
if (orderId == -1) {
System.out.println("Could not save the order. Please try again.");
return;
}
// Now save each line with the order id we just got back.
for (OrderDetail line : cart) {
line.setOrderId(orderId);
orderDetailDao.save(line);
}
printReceipt(orderId);
System.out.println("Order saved successfully!");
}
/**
* Reads an order back from the database and prints a detailed receipt:
* item names, quantities, unit prices, subtotals and the grand total.
*/
public void printReceipt(int orderId) {
// TODO:
// Print order receipt
List<OrderDetail> details = orderDetailDao.findByOrderId(orderId);
if (details.isEmpty()) {
System.out.println("No details found for order #" + orderId);
return;
}
System.out.println("\n[Order Summary / Receipt]");
System.out.println("---------------------------------------------");
System.out.printf("%-18s %-6s %-9s %-9s%n", "Item", "Qty", "Unit", "Total");
System.out.println("---------------------------------------------");
double grandTotal = 0;
for (OrderDetail line : details) {
MenuItem item = menuItemDao.findById(line.getMenuItemId());
String name = (item == null) ? "(removed item)" : item.getName();
System.out.printf("%-18s %-6d $%-8.2f $%-8.2f%n",
name, line.getQuantity(), line.getPrice(), line.getSubtotal());
grandTotal += line.getSubtotal();
}
System.out.println("---------------------------------------------");
System.out.printf("Final Total: $%.2f%n", grandTotal);
}
/** Shows every past order of a user together with what each one cost. */
public void showOrderHistory(int userId) {
// TODO:
// Display user's order history
List<Order> orders = orderDao.findByUserId(userId);
if (orders.isEmpty()) {
System.out.println("You have not placed any orders yet.");
return;
}
System.out.println("\n===== ORDER HISTORY =====");
for (Order order : orders) {
System.out.printf("Order #%d | %s | Total: $%.2f%n",
order.getId(), order.getCreatedAt(), order.getTotalPrice());
}
}
}
/** Reads an int safely so bad input does not crash the program. */
private int readInt() {
while (!scanner.hasNextInt()) {
System.out.print("Please enter a number: ");
scanner.next(); // throw away the bad token
}
return scanner.nextInt();
}
}
+110 -4
View File
@@ -1,5 +1,10 @@
package dev.ui;
import dev.model.User;
import dev.service.AuthService;
import dev.service.MenuService;
import dev.service.OrderService;
import java.util.Scanner;
public class ConsoleMenu {
@@ -7,8 +12,16 @@ public class ConsoleMenu {
private final Scanner scanner =
new Scanner(System.in);
private final AuthService authService = new AuthService();
private final MenuService menuService = new MenuService();
private final OrderService orderService = new OrderService(scanner);
public void start() {
System.out.println("=======================================");
System.out.println(" 🍕 WELCOME TO JAVA PIZZERIA 🍕");
System.out.println("=======================================");
while (true) {
System.out.println();
@@ -16,20 +29,22 @@ public class ConsoleMenu {
System.out.println("1. Login");
System.out.println("2. Register");
System.out.println("3. Exit");
System.out.print("Choose an option: ");
int choice = scanner.nextInt();
int choice = readInt();
switch (choice) {
case 1:
// TODO
handleLogin();
break;
case 2:
// TODO
handleRegister();
break;
case 3:
System.out.println("Goodbye!");
return;
default:
@@ -41,4 +56,95 @@ public class ConsoleMenu {
}
}
private void handleLogin() {
System.out.print("Enter username: ");
String username = scanner.next();
System.out.print("Enter password: ");
String password = scanner.next();
User user = authService.login(username, password);
if (user == null) {
System.out.println("Login failed: wrong username or password.");
return;
}
System.out.println("Welcome back, " + user.getUsername() + "!");
showMainMenu(user);
}
private void handleRegister() {
System.out.print("Choose a username: ");
String username = scanner.next();
System.out.print("Choose a password: ");
String password = scanner.next();
System.out.print("Email (optional, or '-' to skip): ");
String email = scanner.next();
if (email.equals("-")) {
email = null;
}
boolean ok = authService.register(username, password, email);
if (ok) {
System.out.println("Account created! You can log in now.");
} else {
System.out.println("Registration failed. Please try again.");
}
}
/** The menu shown after a successful login. */
private void showMainMenu(User user) {
while (true) {
System.out.println();
System.out.println("=======================================");
System.out.println(" 🍽️ MAIN MENU 🍽️");
System.out.println("=======================================");
System.out.println("1. View Menu");
System.out.println("2. Place a New Order");
System.out.println("3. View Order History");
System.out.println("4. Logout");
System.out.print("Choose an option: ");
int choice = readInt();
switch (choice) {
case 1:
menuService.showMenu();
break;
case 2:
orderService.placeOrder(user.getId());
break;
case 3:
orderService.showOrderHistory(user.getId());
break;
case 4:
System.out.println("Logged out.");
return;
default:
System.out.println("Invalid choice");
}
}
}
/** Reads an int without crashing on bad input. */
private int readInt() {
while (!scanner.hasNextInt()) {
System.out.print("Please enter a number: ");
scanner.next();
}
return scanner.nextInt();
}
}