From cc82879fcc7b9b2f92c89760f5079d8cac52ee16 Mon Sep 17 00:00:00 2001 From: ava Date: Mon, 22 Jun 2026 23:19:56 +0330 Subject: [PATCH] adding codes --- .idea/.gitignore | 10 + .idea/compiler.xml | 13 + .idea/encodings.xml | 7 + .idea/inspectionProfiles/Project_Default.xml | 6 + .idea/jarRepositories.xml | 20 ++ .idea/misc.xml | 12 + .idea/vcs.xml | 6 + database.sql | 249 +++++++++--------- pom.xml | 7 +- src/main/java/dev/dao/MenuItemDao.java | 52 +++- src/main/java/dev/dao/OrderDao.java | 52 +++- src/main/java/dev/dao/OrderDetailDao.java | 46 +++- src/main/java/dev/dao/UserDao.java | 42 ++- .../java/dev/database/DatabaseConnection.java | 11 +- src/main/java/dev/model/MenuItem.java | 40 ++- src/main/java/dev/model/Order.java | 31 ++- src/main/java/dev/model/OrderDetail.java | 37 ++- src/main/java/dev/model/User.java | 31 ++- src/main/java/dev/service/AuthService.java | 25 +- src/main/java/dev/service/MenuService.java | 20 +- src/main/java/dev/service/OrderService.java | 86 +++++- src/main/java/dev/ui/ConsoleMenu.java | 148 ++++++++++- 22 files changed, 796 insertions(+), 155 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..bf2c501 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..5cb71ef --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..4158879 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f24c79d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/database.sql b/database.sql index 2169346..652f8c4 100644 --- a/database.sql +++ b/database.sql @@ -1,141 +1,142 @@ --- 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. +-- ========================================================= +-- WS 10 - Restaurant Database Management System +-- database.sql +-- ========================================================= +-- Drop tables if they already exist (useful when re-running the script) +DROP TABLE IF EXISTS order_details; +DROP TABLE IF EXISTS orders; +DROP TABLE IF EXISTS menu_items; +DROP TABLE IF EXISTS users; --- ======================================================= --- 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 ... +-- ========================================================= +-- 1. USERS (Customer) +-- ========================================================= +CREATE TABLE users ( + id BIGSERIAL NOT NULL PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + password_hash VARCHAR(255) NOT NULL, + email VARCHAR(100) +); +-- ========================================================= +-- 2. MENU_ITEMS +-- ========================================================= +CREATE TABLE menu_items ( + id BIGSERIAL NOT NULL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + description VARCHAR(255), + price NUMERIC(10, 2) NOT NULL CHECK (price > 0), + category VARCHAR(50) +); +-- ========================================================= +-- 3. ORDERS +-- ========================================================= +CREATE TABLE orders ( + id BIGSERIAL NOT NULL PRIMARY KEY, + user_id BIGINT NOT NULL REFERENCES users (id), + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + total_price NUMERIC(10, 2) NOT NULL CHECK (total_price >= 0) +); --- ======================================================= --- 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 ... +-- ========================================================= +-- 4. ORDER_DETAILS (items inside an order) +-- ========================================================= +CREATE TABLE order_details ( + id BIGSERIAL NOT NULL PRIMARY KEY, + order_id BIGINT NOT NULL REFERENCES orders (id), + menu_item_id BIGINT NOT NULL REFERENCES menu_items (id), + quantity INT NOT NULL CHECK (quantity > 0), + unit_price NUMERIC(10, 2) NOT NULL CHECK (unit_price > 0) +); +-- ========================================================= +-- Initial mock data +-- ========================================================= +-- Sample users +-- NOTE: these password_hash values are just placeholders. +-- Your Java app must hash real passwords before inserting (e.g. with BCrypt). +INSERT INTO users (username, password_hash, email) VALUES + ('john_doe', '$2a$10$placeholderHashValue1234567890', 'john@example.com'), + ('jane_smith', '$2a$10$placeholderHashValue1234567891', 'jane@example.com'); --- ======================================================= --- 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 ... +-- Sample menu items (at least 3 required) +INSERT INTO menu_items (name, description, price, category) VALUES + ('Pizza Margherita', 'Classic pizza with tomato, mozzarella and basil', 10.00, 'Main'), + ('Cheeseburger', 'Beef patty with cheddar cheese and house sauce', 8.00, 'Main'), + ('Pasta Carbonara', 'Pasta with egg, pancetta and parmesan', 12.00, 'Main'), + ('Tiramisu', 'Traditional Italian coffee-flavored dessert', 6.50, 'Dessert'), + ('Cola', 'Soft drink, 330ml can', 2.50, 'Drink');-- ========================================================= +-- WS 10 - Restaurant Database Management System +-- database.sql +-- ========================================================= +-- Drop tables if they already exist (useful when re-running the script) +DROP TABLE IF EXISTS order_details; +DROP TABLE IF EXISTS orders; +DROP TABLE IF EXISTS menu_items; +DROP TABLE IF EXISTS users; +-- ========================================================= +-- 1. USERS (Customer) +-- ========================================================= +CREATE TABLE users ( + id BIGSERIAL NOT NULL PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + password_hash VARCHAR(255) NOT NULL, + email VARCHAR(100) +); --- ======================================================= --- 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 ... +-- ========================================================= +-- 2. MENU_ITEMS +-- ========================================================= +CREATE TABLE menu_items ( + id BIGSERIAL NOT NULL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + description VARCHAR(255), + price NUMERIC(10, 2) NOT NULL CHECK (price > 0), + category VARCHAR(50) +); +-- ========================================================= +-- 3. ORDERS +-- ========================================================= +CREATE TABLE orders ( + id BIGSERIAL NOT NULL PRIMARY KEY, + user_id BIGINT NOT NULL REFERENCES users (id), + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + total_price NUMERIC(10, 2) NOT NULL CHECK (total_price >= 0) +); +-- ========================================================= +-- 4. ORDER_DETAILS (items inside an order) +-- ========================================================= +CREATE TABLE order_details ( + id BIGSERIAL NOT NULL PRIMARY KEY, + order_id BIGINT NOT NULL REFERENCES orders (id), + menu_item_id BIGINT NOT NULL REFERENCES menu_items (id), + quantity INT NOT NULL CHECK (quantity > 0), + unit_price NUMERIC(10, 2) NOT NULL CHECK (unit_price > 0) +); --- ======================================================= --- INITIAL MENU DATA --- ======================================================= --- --- Insert at least 3 food or drink items. --- --- Example categories: --- - Pizza --- - Burger --- - Pasta --- - Drink --- --- INSERT INTO ... +-- ========================================================= +-- Initial mock data +-- ========================================================= +-- Sample users +-- NOTE: these password_hash values are just placeholders. +-- Your Java app must hash real passwords before inserting (e.g. with BCrypt). +INSERT INTO users (username, password_hash, email) VALUES + ('john_doe', '$2a$10$placeholderHashValue1234567890', 'john@example.com'), + ('jane_smith', '$2a$10$placeholderHashValue1234567891', 'jane@example.com'); - --- ======================================================= --- OPTIONAL TEST DATA --- ======================================================= --- --- You may insert sample users and orders for testing. --- This section is optional. --- --- INSERT INTO ... - - - --- ======================================================= --- VERIFICATION QUERIES --- ======================================================= --- --- Uncomment these queries to verify your database. --- --- SELECT * FROM ...; --- SELECT * FROM ...; --- SELECT * FROM ...; --- SELECT * FROM ...; \ No newline at end of file +-- Sample menu items (at least 3 required) +INSERT INTO menu_items (name, description, price, category) VALUES + ('Pizza Margherita', 'Classic pizza with tomato, mozzarella and basil', 10.00, 'Main'), + ('Cheeseburger', 'Beef patty with cheddar cheese and house sauce', 8.00, 'Main'), + ('Pasta Carbonara', 'Pasta with egg, pancetta and parmesan', 12.00, 'Main'), + ('Tiramisu', 'Traditional Italian coffee-flavored dessert', 6.50, 'Dessert'), + ('Cola', 'Soft drink, 330ml can', 2.50, 'Drink'); \ No newline at end of file diff --git a/pom.xml b/pom.xml index 028ca50..fd48e96 100644 --- a/pom.xml +++ b/pom.xml @@ -27,6 +27,11 @@ ${postgresql.version} - + + org.mindrot + jbcrypt + 0.4 + + \ No newline at end of file diff --git a/src/main/java/dev/dao/MenuItemDao.java b/src/main/java/dev/dao/MenuItemDao.java index 3bbebe9..f7fa9a2 100644 --- a/src/main/java/dev/dao/MenuItemDao.java +++ b/src/main/java/dev/dao/MenuItemDao.java @@ -1,7 +1,14 @@ package dev.dao; import dev.model.MenuItem; +import dev.database.DatabaseConnection; +import java.math.BigDecimal; +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 { @@ -11,7 +18,23 @@ public class MenuItemDao { // TODO: // Retrieve all menu items - return null; + // return null; + List menuItems = new ArrayList<>(); + String sql = "SELECT id, name, description, price, category FROM menu_items"; + + try (Connection conn = DatabaseConnection.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql); + ResultSet rs = stmt.executeQuery()) { + + while (rs.next()) { + menuItems.add(mapRowToMenuItem(rs)); + } + + } catch (SQLException e) { + e.printStackTrace(); + } + + return menuItems; } public MenuItem findById(int id) { @@ -19,7 +42,32 @@ public class MenuItemDao { // 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 mapRowToMenuItem(rs); + } + } + + } catch (SQLException e) { + e.printStackTrace(); + } + return null; } + private MenuItem mapRowToMenuItem(ResultSet rs) throws SQLException { + int id = rs.getInt("id"); + String name = rs.getString("name"); + String description = rs.getString("description"); + BigDecimal price = rs.getBigDecimal("price"); + String category = rs.getString("category"); -} \ No newline at end of file + return new MenuItem(id, name, description, price, category); + } +} diff --git a/src/main/java/dev/dao/OrderDao.java b/src/main/java/dev/dao/OrderDao.java index 00999a2..8d13f00 100644 --- a/src/main/java/dev/dao/OrderDao.java +++ b/src/main/java/dev/dao/OrderDao.java @@ -1,7 +1,16 @@ package dev.dao; import dev.model.Order; +import dev.database.DatabaseConnection; +import java.math.BigDecimal; +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 { @@ -10,6 +19,25 @@ public class OrderDao { // 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.setBigDecimal(2, order.getTotalPrice()); + + stmt.executeUpdate(); + + try (ResultSet rs = stmt.getGeneratedKeys()) { + if (rs.next()) { + return rs.getInt(1); + } + } + + } catch (SQLException e) { + e.printStackTrace(); + } return -1; } @@ -18,8 +46,30 @@ public class OrderDao { // TODO: // Retrieve all orders of a user + List orders = new ArrayList<>(); + String sql = "SELECT id, user_id, created_at, total_price FROM orders WHERE user_id = ?"; - return null; + try (Connection conn = DatabaseConnection.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setInt(1, userId); + + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + int id = rs.getInt("id"); + int uId = rs.getInt("user_id"); + Timestamp createdAt = rs.getTimestamp("created_at"); + BigDecimal totalPrice = rs.getBigDecimal("total_price"); + + orders.add(new Order(id, uId, createdAt.toLocalDateTime(), totalPrice)); + } + } + + } catch (SQLException e) { + e.printStackTrace(); + } + + return orders; } } \ No newline at end of file diff --git a/src/main/java/dev/dao/OrderDetailDao.java b/src/main/java/dev/dao/OrderDetailDao.java index ed42f56..39d5646 100644 --- a/src/main/java/dev/dao/OrderDetailDao.java +++ b/src/main/java/dev/dao/OrderDetailDao.java @@ -1,7 +1,14 @@ package dev.dao; import dev.model.OrderDetail; +import dev.database.DatabaseConnection; +import java.math.BigDecimal; +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 { @@ -10,15 +17,52 @@ public class OrderDetailDao { // TODO: // Insert order detail + String sql = "INSERT INTO order_details (order_id, menu_item_id, quantity, unit_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.setBigDecimal(4, detail.getPrice()); + + stmt.executeUpdate(); + + } catch (SQLException e) { + e.printStackTrace(); + } } public List findByOrderId(int orderId) { // TODO: // Retrieve order details + List details = new ArrayList<>(); + String sql = "SELECT id, order_id, menu_item_id, quantity, unit_price FROM order_details WHERE order_id = ?"; - return null; + try (Connection conn = DatabaseConnection.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setInt(1, orderId); + + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + int id = rs.getInt("id"); + int oId = rs.getInt("order_id"); + int menuItemId = rs.getInt("menu_item_id"); + int quantity = rs.getInt("quantity"); + BigDecimal price = rs.getBigDecimal("unit_price"); + + details.add(new OrderDetail(id, oId, menuItemId, quantity, price)); + } + } + + } catch (SQLException e) { + e.printStackTrace(); + } + + return details; } } \ No newline at end of file diff --git a/src/main/java/dev/dao/UserDao.java b/src/main/java/dev/dao/UserDao.java index af08106..0fba7e4 100644 --- a/src/main/java/dev/dao/UserDao.java +++ b/src/main/java/dev/dao/UserDao.java @@ -1,21 +1,61 @@ package dev.dao; import dev.model.User; +import dev.database.DatabaseConnection; +import java.sql.Connection; +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 (?, ?, ?)"; - return false; + 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()); + + stmt.executeUpdate(); + return true; + + } catch (SQLException e) { + e.printStackTrace(); + return false; + } } public User findByUsername(String username) { // TODO: // Find a user by username + String sql = "SELECT id, username, password_hash, 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()) { + int id = rs.getInt("id"); + String uname = rs.getString("username"); + String passwordHash = rs.getString("password_hash"); + String email = rs.getString("email"); + + return new User(id, uname, passwordHash, email); + } + } + + } catch (SQLException e) { + e.printStackTrace(); + } return null; } diff --git a/src/main/java/dev/database/DatabaseConnection.java b/src/main/java/dev/database/DatabaseConnection.java index da45535..b24ea61 100644 --- a/src/main/java/dev/database/DatabaseConnection.java +++ b/src/main/java/dev/database/DatabaseConnection.java @@ -1,15 +1,16 @@ package dev.database; import java.sql.Connection; +import java.sql.DriverManager; import java.sql.SQLException; public class DatabaseConnection { + private static final String URL = "jdbc:postgresql://localhost:5432/restaurant_db"; - private static final String URL = "jdbc:postgresql://localhost:5432/restaurant_db"; // DB Server + private static final String USER = "avasanatkar"; - private static final String USER = "postgres"; // Your Username + private static final String PASSWORD = ""; - private static final String PASSWORD = "password"; // Your Password private DatabaseConnection() { @@ -21,7 +22,9 @@ public class DatabaseConnection { // TODO: // Return a valid PostgreSQL connection - return null; + // return null; + return DriverManager.getConnection(URL, USER, PASSWORD); + } } \ No newline at end of file diff --git a/src/main/java/dev/model/MenuItem.java b/src/main/java/dev/model/MenuItem.java index 265ecc1..a3d414a 100644 --- a/src/main/java/dev/model/MenuItem.java +++ b/src/main/java/dev/model/MenuItem.java @@ -1,15 +1,45 @@ package dev.model; +import java.math.BigDecimal; + public class MenuItem { private int id; - private String name; - private String description; - - private double price; - + private BigDecimal price; private String category; + public MenuItem() {} + + public MenuItem(int id, String name, String description, BigDecimal price, String category) { + this.id = id; + this.name = name; + this.description = description; + this.price = price; + this.category = category; + } + + public MenuItem(String name, String description, BigDecimal price, String category) { + 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 BigDecimal getPrice() { return price; } + public void setPrice(BigDecimal price) { this.price = price; } + public String getCategory() { return category; } + public void setCategory(String category) { this.category = category; } + + @Override + public String toString() { + return id + ". " + name + " - $" + price + (category != null ? " (" + category + ")" : ""); + } } \ No newline at end of file diff --git a/src/main/java/dev/model/Order.java b/src/main/java/dev/model/Order.java index 32049cb..eee82e8 100644 --- a/src/main/java/dev/model/Order.java +++ b/src/main/java/dev/model/Order.java @@ -1,15 +1,40 @@ package dev.model; +import java.math.BigDecimal; import java.time.LocalDateTime; public class Order { private int id; - private int userId; - private LocalDateTime createdAt; + private BigDecimal totalPrice; - private double totalPrice; + public Order() {} + public Order(int id, int userId, LocalDateTime createdAt, BigDecimal totalPrice) { + this.id = id; + this.userId = userId; + this.createdAt = createdAt; + this.totalPrice = totalPrice; + } + + public Order(int userId, BigDecimal totalPrice) { + this.userId = userId; + 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 BigDecimal getTotalPrice() { return totalPrice; } + public void setTotalPrice(BigDecimal totalPrice) { this.totalPrice = totalPrice; } + + @Override + public String toString() { + return "Order #" + id + " - " + createdAt + " - Total: $" + totalPrice; + } } \ No newline at end of file diff --git a/src/main/java/dev/model/OrderDetail.java b/src/main/java/dev/model/OrderDetail.java index b5b8bbe..af1c4a7 100644 --- a/src/main/java/dev/model/OrderDetail.java +++ b/src/main/java/dev/model/OrderDetail.java @@ -1,15 +1,44 @@ package dev.model; +import java.math.BigDecimal; + public class OrderDetail { private int id; - private int orderId; - private int menuItemId; - private int quantity; + private BigDecimal price; - private double price; + public OrderDetail() {} + public OrderDetail(int id, int orderId, int menuItemId, int quantity, BigDecimal price) { + this.id = id; + this.orderId = orderId; + this.menuItemId = menuItemId; + this.quantity = quantity; + this.price = price; + } + + public OrderDetail(int orderId, int menuItemId, int quantity, BigDecimal price) { + 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 BigDecimal getPrice() { return price; } + public void setPrice(BigDecimal price) { this.price = price; } + + public BigDecimal getSubtotal() { + return price.multiply(BigDecimal.valueOf(quantity)); + } } \ No newline at end of file diff --git a/src/main/java/dev/model/User.java b/src/main/java/dev/model/User.java index 0ab60c6..8377c37 100644 --- a/src/main/java/dev/model/User.java +++ b/src/main/java/dev/model/User.java @@ -3,11 +3,36 @@ package dev.model; public class User { private int id; - private String username; - private String password; - 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 User(String username, String password, String email) { + 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; } + + @Override + public String toString() { + return "User{id=" + id + ", username='" + username + "', email='" + email + "'}"; + } } \ No newline at end of file diff --git a/src/main/java/dev/service/AuthService.java b/src/main/java/dev/service/AuthService.java index bee866a..f78aebe 100644 --- a/src/main/java/dev/service/AuthService.java +++ b/src/main/java/dev/service/AuthService.java @@ -1,21 +1,42 @@ package dev.service; import dev.model.User; +import dev.dao.UserDao; +import org.mindrot.jbcrypt.BCrypt; public class AuthService { - + private final UserDao userDao = new UserDao(); public boolean register(String username, String password, String email) { // TODO: // Validate and register user + if (username == null || username.isBlank() || password == null || password.isBlank()) { + return false; + } - return false; + if (userDao.findByUsername(username) != null) { + return false; + } + + String hashedPassword = BCrypt.hashpw(password, BCrypt.gensalt()); + User newUser = new User(username, hashedPassword, email); + + return userDao.save(newUser); } public User login(String username, String password) { // TODO: // Authenticate user + User user = userDao.findByUsername(username); + + if (user == null) { + return null; + } + + if (BCrypt.checkpw(password, user.getPassword())) { + return user; + } return null; } diff --git a/src/main/java/dev/service/MenuService.java b/src/main/java/dev/service/MenuService.java index 6dbf4da..dd90381 100644 --- a/src/main/java/dev/service/MenuService.java +++ b/src/main/java/dev/service/MenuService.java @@ -1,12 +1,30 @@ package dev.service; +import dev.dao.MenuItemDao; +import dev.model.MenuItem; +import java.util.List; public class MenuService { - + private final MenuItemDao menuItemDao = new MenuItemDao(); public void showMenu() { // TODO: // Display menu items + List items = menuItemDao.findAll(); + if (items.isEmpty()) { + System.out.println("No menu items available."); + return; + } + + System.out.println("======================================="); + System.out.println(" MENU"); + System.out.println("======================================="); + + for (MenuItem item : items) { + System.out.println(item); + } + + System.out.println("======================================="); } } \ No newline at end of file diff --git a/src/main/java/dev/service/OrderService.java b/src/main/java/dev/service/OrderService.java index 14708f8..4037008 100644 --- a/src/main/java/dev/service/OrderService.java +++ b/src/main/java/dev/service/OrderService.java @@ -1,26 +1,108 @@ 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.math.BigDecimal; +import java.util.List; +import java.util.Map; public class OrderService { + private final OrderDao orderDao = new OrderDao(); + private final OrderDetailDao orderDetailDao = new OrderDetailDao(); + private final MenuItemDao menuItemDao = new MenuItemDao(); - public void placeOrder(int userId) { + public int placeOrder(int userId, Map itemQuantities) { // TODO: // Create order + if (itemQuantities == null || itemQuantities.isEmpty()) { + return -1; + } + + BigDecimal total = BigDecimal.ZERO; + + for (Map.Entry entry : itemQuantities.entrySet()) { + MenuItem item = menuItemDao.findById(entry.getKey()); + if (item == null) { + continue; + } + int quantity = entry.getValue(); + total = total.add(item.getPrice().multiply(BigDecimal.valueOf(quantity))); + } + + Order order = new Order(userId, total); + int orderId = orderDao.save(order); + + if (orderId == -1) { + return -1; + } + + for (Map.Entry entry : itemQuantities.entrySet()) { + MenuItem item = menuItemDao.findById(entry.getKey()); + if (item == null) { + continue; + } + int quantity = entry.getValue(); + + OrderDetail detail = new OrderDetail(orderId, item.getId(), quantity, item.getPrice()); + orderDetailDao.save(detail); + } + + return orderId; } public void printReceipt(int orderId) { // TODO: // Print order receipt + List details = orderDetailDao.findByOrderId(orderId); + if (details.isEmpty()) { + System.out.println("No details found for order #" + orderId); + return; + } + + System.out.println("---------------------------------------"); + System.out.printf("%-12s %-6s %-10s %-10s%n", "Item", "Qty", "Unit", "Total"); + System.out.println("---------------------------------------"); + + BigDecimal grandTotal = BigDecimal.ZERO; + + for (OrderDetail detail : details) { + MenuItem item = menuItemDao.findById(detail.getMenuItemId()); + String name = (item != null) ? item.getName() : "Unknown item"; + BigDecimal subtotal = detail.getSubtotal(); + grandTotal = grandTotal.add(subtotal); + + System.out.printf("%-12s %-6d $%-9.2f $%-9.2f%n", + name, detail.getQuantity(), detail.getPrice(), subtotal); + } + + System.out.println("---------------------------------------"); + System.out.println("Final Total: $" + grandTotal); } public void showOrderHistory(int userId) { // TODO: // Display user's order history + List orders = orderDao.findByUserId(userId); + if (orders.isEmpty()) { + System.out.println("No past orders found."); + return; + } + + System.out.println("======================================="); + System.out.println(" ORDER HISTORY"); + System.out.println("======================================="); + + for (Order order : orders) { + System.out.println(order); + } } - } \ No newline at end of file diff --git a/src/main/java/dev/ui/ConsoleMenu.java b/src/main/java/dev/ui/ConsoleMenu.java index 663dc0c..ea3da5a 100644 --- a/src/main/java/dev/ui/ConsoleMenu.java +++ b/src/main/java/dev/ui/ConsoleMenu.java @@ -1,12 +1,23 @@ package dev.ui; import java.util.Scanner; +import dev.model.MenuItem; +import dev.model.User; +import dev.service.AuthService; +import dev.service.MenuService; +import dev.service.OrderService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; 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(); public void start() { while (true) { @@ -23,10 +34,12 @@ public class ConsoleMenu { case 1: // TODO + handleLogin(); break; case 2: // TODO + handleRegister(); break; case 3: @@ -40,5 +53,138 @@ public class ConsoleMenu { } } + private void handleRegister() { + + System.out.println(); + System.out.println("[Register New Account]"); + System.out.print("Choose a username: "); + String username = scanner.next(); + System.out.print("Choose a password: "); + String password = scanner.next(); + scanner.nextLine(); + System.out.print("Email (optional, press enter to skip): "); + String email = scanner.nextLine(); + + if (email.isBlank()) { + email = null; + } + + boolean success = authService.register(username, password, email); + + if (success) { + System.out.println("Registration successful! You can now login."); + } else { + System.out.println("Registration failed. Username may already be taken."); + } + } + + private void handleLogin() { + + System.out.println(); + System.out.println("[Login]"); + 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("Invalid username or password."); + return; + } + + System.out.println("Welcome, " + user.getUsername() + "!"); + showMainMenu(user); + } + + private void showMainMenu(User user) { + + boolean loggedIn = true; + + while (loggedIn) { + + 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"); + + int choice = scanner.nextInt(); + + switch (choice) { + + case 1: + menuService.showMenu(); + break; + + case 2: + handlePlaceOrder(user); + break; + + case 3: + orderService.showOrderHistory(user.getId()); + break; + + case 4: + loggedIn = false; + System.out.println("Logged out."); + break; + + default: + System.out.println("Invalid choice"); + } + } + } + + private void handlePlaceOrder(User user) { + + menuService.showMenu(); + + Map itemQuantities = new HashMap<>(); + + System.out.println(); + System.out.println("[Placing Order]"); + + while (true) { + System.out.print("Enter the ID of the item to add (or 0 to finish): "); + int itemId = scanner.nextInt(); + + if (itemId == 0) { + break; + } + + System.out.print("Enter quantity: "); + int quantity = scanner.nextInt(); + + if (quantity <= 0) { + System.out.println("Quantity must be greater than zero."); + continue; + } + + itemQuantities.merge(itemId, quantity, Integer::sum); + System.out.println("Added " + quantity + "x item #" + itemId + " to your cart."); + } + + if (itemQuantities.isEmpty()) { + System.out.println("No items added. Order cancelled."); + return; + } + + int orderId = orderService.placeOrder(user.getId(), itemQuantities); + + if (orderId == -1) { + System.out.println("Failed to place order."); + return; + } + + System.out.println(); + System.out.println("[Order Summary / Receipt]"); + orderService.printReceipt(orderId); + System.out.println("Order saved successfully!"); + } } \ No newline at end of file