Skip to content
Albert edited this page Sep 27, 2024 · 35 revisions

Welcome to the restaurant wiki!

Summary: Restaurant Management System

This Java application is a simple restaurant management system. Here's a breakdown of its main components and functionality:

Main Application (App.java)

The main class initializes the application by:

  • Creating a RestaurantDB object
  • Using utility methods to set up fake data
  • Testing the system

RestaurantDB (RestaurantDB.java)

This class serves as the central data repository for the restaurant:

  • Contains HashMaps to store menus, orders, and tables
  • Uses Lombok annotations (@Data, @AllArgsConstructor, @NoArgsConstructor) for automatic getter, setter, and constructor generation

Utilities (Utilities.java)

This class contains static methods for setting up test data and demonstrating system functionality:

  • createFakeTables(): Creates 5 sample tables and adds them to the RestaurantDB
  • createFakeMenus(): Creates 3 sample menus (Night, Vegan, Kids) and adds them to the RestaurantDB
  • testOrder(): Demonstrates creating an order, calculating the total payment, and updating table status
  • printStatusTable(): Prints a list of available (not busy) tables

Order (Order.java)

Represents a customer order, including:

  • Date
  • Waiter
  • Number of people
  • Total payment
  • Payment status
  • Associated table
  • List of menus ordered

It includes methods to calculate the total payment with VAT (IVA in Spanish).

Table and Menu

These classes are used throughout the application to represent restaurant tables and menu items.

Application Flow

  1. Initializes the RestaurantDB
  2. Creates fake menus and tables
  3. Runs a test order:
    • Creates an order with 4 menus
    • Calculates and displays the total payment
    • Marks the order as paid and the table as not busy
  4. Prints the status of available tables

This app demonstrates basic object-oriented programming concepts, data management using HashMaps, and simple restaurant operations like order creation and payment calculation. It serves as a good starting point for a more comprehensive restaurant management system.

Stack

  • IntelJIdea Community
  • JDK 21 Corretto

image

image

Project structure

Reference lab

image

image

image

image

image

POM

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>RestaurantJava</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>RestaurantJava</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.34</version>

    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Core UML

classDiagram
    class Menu {
        -String name
        -Double price
        -String content
        -boolean active
        -boolean water
    }

    class Order {
        -Date date
        -String waiter
        -int peopleQty
        -double totalPayment
        -boolean paid
        -Table table
        -ArrayList<Menu> menus
        +calculateTotalPayment() double
        -calculateIVA(double number) double
    }

    class Table {
        -String name
        -String description
        -int qty
        -boolean busy
    }

    class RestaurantDB {
        -String name
        -int size
        -HashMap<String, Menu> menus
        -HashMap<String, Order> orders
        -HashMap<String, Table> tables
    }

    Order "1" --> "1" Table : has
    Order "1" --> "0..*" Menu : contains
    RestaurantDB "1" --> "0..*" Menu : stores
    RestaurantDB "1" --> "0..*" Order : stores
    RestaurantDB "1" --> "0..*" Table : stores
Loading

Domains

Name Description Why Class/Commit
Controller Controls the flow of the application, handling user input and invoking appropriate manager methods. Separates user interaction from business logic, promoting modularity and easier maintenance. 7d2a30b
Manager Contains the business logic of the application, coordinating operations between different components and enforcing rules. Centralizes and encapsulates business rules, ensuring consistency and facilitating testing. 4bf6ce5
Model Represents domain entities and data structures used within the application, encapsulating their state and behavior. Provides a clear representation of the application's domain, promoting understanding and reuse. 4e19008
Repository Manages the persistence of domain objects, abstracting data storage and retrieval details, providing a clean data access layer. Separates data access concerns from business logic, enabling flexibility and testability. e8abea1
Utils Contains utility classes and methods providing common functionalities required across the application. Encourages code reuse, reduces redundancy, and enhances maintainability. 4b43597
View Represents the user interface components of the application, presenting data to the user and capturing user interactions. Separates presentation logic from other components, improving maintainability and flexibility.

Data and Operations Flux

image

image

Classes

Order

Commit 9364ecd

package org.example.model;

import java.util.ArrayList;
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {

    private Date date;
    private String waiter;
    private int peopleQty;
    private double totalPayment;
    private boolean paid;
    private Table table;
    private ArrayList<Menu> menus;

    // Calculate the amount to pay with IVA
    public double calculateTotalPayment (){

        double totalPyment = 0.0;
        for (Menu m : this.getMenus()) {
            totalPyment = totalPyment + m.getPrice();
        }

        double totalPymentIVA =  calculateIVA(totalPyment);
        this.setTotalPayment(totalPymentIVA);

        System.out.println(this);

        return totalPymentIVA;
    }

    public double calculateIVA(double number){
        number = number * 1.21;
        return number;
    }

}

Utilities

Commit 4b43597

package org.example.utils;

import org.example.model.Menu;
import org.example.model.Order;
import org.example.model.Table;
import org.example.repository.RestaurantDB;

import java.util.ArrayList;
import java.util.Date;

public class Utilities {

    public static void createFakeTables(RestaurantDB r1){
        // create 5 tables
        Table t1 = new Table("Table 01", "Table type Modern", 4, false);
        Table t2 = new Table("Table 02", "Table type Modern", 2, false);
        Table t3 = new Table("Table 03", "Table type Modern", 2, false);
        Table t4 = new Table("Table 04", "Table type Modern", 4, false);
        Table t5 = new Table("Table 05", "Table type Modern", 4, false);
        
        //save tables to r1.tables HashMap tables
        r1.getTables().put("TABLE-01", t1);
        r1.getTables().put("TABLE-02", t2);
        r1.getTables().put("TABLE-03", t3);
        r1.getTables().put("TABLE-04", t4);
        r1.getTables().put("TABLE-05", t5);

    }

    public static void createFakeMenus(RestaurantDB r1){
        Menu m1 = new Menu("Menu Night", 8.5, "", true, true);
        Menu m2 = new Menu("Menu Vegan", 10.5, "", true, true);
        Menu m3 = new Menu("Menu Kids", 12.5, "", true, true);

        r1.getMenus().put("MENU-NIG", m1);
        r1.getMenus().put("MENU-VEG", m2);
        r1.getMenus().put("MENU-KID", m3);

    }

    public static void testOrder(RestaurantDB r1){

        ArrayList<Menu> m = new ArrayList<>();
        m.add(r1.getMenus().get("MENU-NIG"));
        m.add(r1.getMenus().get("MENU-NIG"));
        m.add(r1.getMenus().get("MENU-VEG"));
        m.add(r1.getMenus().get("MENU-KID"));

        Order o1 = new Order(new Date(), "Jazz", 4,
                0.0, false, r1.getTables().get("TABLE-01"), null);
        o1.setMenus(m);

        r1.getTables().get("TABLE-01").setBusy(true);

        System.out.println("Total to pay:"+ o1.calculateTotalPayment());
        System.out.println(o1);

        o1.setPaid(true);

        System.out.println(o1);
        r1.getTables().get("TABLE-01").setBusy(false);

        System.out.println("Table status (" +
                r1.getTables().get("TABLE-01").getName() +
                "):" + r1.getTables().get("TABLE-01").isBusy());

    }

    public static void printStatusTable(RestaurantDB r1) {

        System.out.println("\n\nAvailable tables:\n");
        r1.getTables().get("TABLE-01").setBusy(true);
        for ( Table t : r1.getTables().values() ){

            if(!t.isBusy()) {
                System.out.println(t.getName());
            }
        }
    }

}

Commits

Commits master

Version Date Commit Message Author Commit Link
v0.4 Sep 19, 2024 managers domain created and testOrder() to manager AlbertProfe 4bf6ce5
v0.3 Sep 19, 2024 controller domain implemented with testOrder() and printStatusTable() AlbertProfe 7d2a30b
v0.2 Sep 18, 2024 starting with DDD: utils, model, repo (HashMap, restaurantDB) AlbertProfe e50a5a
v0.1.1 Sep 17, 2024 calculateTotalPayment() implemented AlbertProfe 9364ecd
v0.1 Sep 16, 2024 calculateTotalPayment() methods, static and scope and hash AlbertProfe 4f36b6b
v0.0.1 Sep 13, 2024 classes AlbertProfe 4e19008
v0.0 Sep 13, 2024 create project AlbertProfe e8abea1

Test: JUnit and Mockito

Dependencies JUnit and Mockito

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>RestaurantJava</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>RestaurantJava</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.34</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter -->
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-junit-jupiter</artifactId>
      <version>5.13.0</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>


    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>RELEASE</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Test: CreateOrderTest.java

package org.example;

import org.example.manager.OrderManager;
import org.example.model.Table;
import org.example.model.Menu;
import org.example.repository.RestaurantDB;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.*;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class CreateOrderTest {

    @Mock
    private Scanner scanner;

    private RestaurantDB restaurantDB;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
        restaurantDB = new RestaurantDB();
        restaurantDB.setName("Plaça Catalunya Restaurant");
        restaurantDB.setSize(10);
        createFakeMenus(restaurantDB);
        createFakeTables(restaurantDB);
    }

    private void createFakeTables(RestaurantDB r1) {
        Table t1 = new Table("Table 01", "Table type Modern", 4, false);
        Table t2 = new Table("Table 02", "Table type Modern", 2, false);
        Table t3 = new Table("Table 03", "Table type Modern", 2, false);
        Table t4 = new Table("Table 04", "Table type Modern", 4, false);
        Table t5 = new Table("Table 05", "Table type Modern", 4, false);

        r1.getTables().put("TABLE-01", t1);
        r1.getTables().put("TABLE-02", t2);
        r1.getTables().put("TABLE-03", t3);
        r1.getTables().put("TABLE-04", t4);
        r1.getTables().put("TABLE-05", t5);
    }

    private void createFakeMenus(RestaurantDB r1) {
        Menu m1 = new Menu("Menu Night", 8.5, "", true, true);
        Menu m2 = new Menu("Menu Vegan", 10.5, "", true, true);
        Menu m3 = new Menu("Menu Kids", 12.5, "", true, true);

        r1.getMenus().put("MENU-NIG", m1);
        r1.getMenus().put("MENU-VEG", m2);
        r1.getMenus().put("MENU-KID", m3);
    }

    @Test
    void testCreateOrderSuccessful() {
        // Arrange
        when(scanner.nextLine()).thenReturn( "Joan", "2", "TABLE-01", "MENU-NIG", "MENU-NIG", "MENU-NIG", "0");

        // Act
        boolean result = OrderManager.createOrder(scanner, restaurantDB);

        // Assert
        assertTrue(result);
        assertEquals(1, restaurantDB.getOrders().size());
        assertTrue(restaurantDB.getTables().get("TABLE-01").isBusy());
    }

    @Test
    void testCreateOrderFilled() {
        // Arrange
        when(scanner.nextLine()).thenReturn("Joan", "2", "TABLE-01", "MENU-NIG", "MENU-NIG", "MENU-NIG", "0");

        // Act
        boolean result = OrderManager.createOrder(scanner, restaurantDB);

        // Assert
        assertTrue(result);
        //assertEquals(2, restaurantDB.getOrders().size());
        assertNotEquals(2, restaurantDB.getOrders().size());
        assertTrue(restaurantDB.getTables().get("TABLE-01").isBusy());
    }

    @Test
    void testCreateOrderInvalidPeopleQuantity() {
        // Arrange
        when(scanner.nextLine()).thenReturn("Joan", "-1", "2", "TABLE-02", "MENU-VEG", "0");

        // Act
        boolean result = OrderManager.createOrder(scanner, restaurantDB);

        // Assert
        assertTrue(result);
        assertEquals(1, restaurantDB.getOrders().size());
        assertTrue(restaurantDB.getTables().get("TABLE-02").isBusy());
    }

    // be careful with this test there is a infinite loop
    @Test
    void testCreateOrderNoTableAvailableloop() {
        // Arrange
        when(scanner.nextLine()).thenReturn("Joan", "2");
        // Set all tables as busy
        for (Table table : restaurantDB.getTables().values()) {
            table.setBusy(true);
        }

        // Act
        boolean result = OrderManager.createOrder(scanner, restaurantDB);

        // Assert
        assertFalse(result);
        assertTrue(restaurantDB.getOrders().isEmpty());
    }



}

20 Most Relevant JUnit Assert Methods

  1. assertEquals

    • Checks if two values are equal
    • Example: assertEquals(expected, actual)
  2. assertNotEquals

    • Checks if two values are not equal
    • Example: assertNotEquals(unexpected, actual)
  3. assertTrue

    • Checks if a condition is true
    • Example: assertTrue(someBoolean)
  4. assertFalse

    • Checks if a condition is false
    • Example: assertFalse(someBoolean)
  5. assertNull

    • Checks if an object is null
    • Example: assertNull(someObject)
  6. assertNotNull

    • Checks if an object is not null
    • Example: assertNotNull(someObject)
  7. assertSame

    • Checks if two objects refer to the same object
    • Example: assertSame(expected, actual)
  8. assertNotSame

    • Checks if two objects do not refer to the same object
    • Example: assertNotSame(unexpected, actual)
  9. assertArrayEquals

    • Checks if two arrays are equal
    • Example: assertArrayEquals(expectedArray, actualArray)
  10. assertThrows

    • Checks if a certain exception is thrown
    • Example: assertThrows(ExpectedException.class, () -> { someMethod(); })
  11. assertDoesNotThrow

    • Checks that no exception is thrown
    • Example: assertDoesNotThrow(() -> { someMethod(); })
  12. assertAll

    • Groups multiple assertions
    • Example: assertAll("heading", () -> assertEquals(1, 1), () -> assertTrue(true))
  13. assertIterableEquals

    • Checks if two iterables are deeply equal
    • Example: assertIterableEquals(expectedIterable, actualIterable)
  14. assertLinesMatch

    • Checks if two lists of strings match
    • Example: assertLinesMatch(expectedLines, actualLines)
  15. assertTimeout

    • Checks if execution completes before timeout
    • Example: assertTimeout(Duration.ofMillis(100), () -> { someMethod(); })
  16. assertTimeoutPreemptively

    • Similar to assertTimeout, but interrupts execution if timeout is exceeded
    • Example: assertTimeoutPreemptively(Duration.ofMillis(100), () -> { someMethod(); })
  17. fail

    • Fails a test with the given message
    • Example: fail("This test should have failed")
  18. assertInstanceOf

    • Checks if an object is an instance of a specific class
    • Example: assertInstanceOf(ExpectedClass.class, actualObject)
  19. assertDoesNotThrow

    • Asserts that execution of the supplied executable does not throw any kind of exception
    • Example: assertDoesNotThrow(() -> someMethodThatShouldNotThrow())
  20. assertThrowsExactly

    • Asserts that execution of the supplied executable throws an exception of the expectedType and returns it
    • Example: assertThrowsExactly(NumberFormatException.class, () -> Integer.parseInt("One"))

Output Console

Commit 4e19008

/home/albert/.jdks/corretto-21.0.4/bin/java -javaagent:/app/IDEA-C/lib/idea_rt.jar=43929:/app/IDEA-C/bin -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath /home/albert/MyProjects/Sandbox/RestaurantJava/target/classes:/home/albert/.m2/repository/org/projectlombok/lombok/1.18.34/lombok-1.18.34.jar org.example.App
table from o2: Table(name=Table 01, description=Table type Modern, qty=4, busy=false)
Hello world!

Process finished with exit code 0

Commit 9364ecd

/home/albert/.jdks/corretto-21.0.4/bin/java -javaagent:/app/IDEA-C/lib/idea_rt.jar=38051:/app/IDEA-C/bin -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath /home/albert/MyProjects/Sandbox/RestaurantJava/target/classes:/home/albert/.m2/repository/org/projectlombok/lombok/1.18.34/lombok-1.18.34.jar org.example.App

Init
Order(date=Tue Sep 17 10:58:00 CEST 2024, waiter=Jazz, peopleQty=20, totalPayment=48.4, paid=false, table=Table(name=Table 01, description=Table type Modern, qty=4, busy=false), menus=[Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Vegan, price=10.5, content=, active=true, water=true), Menu(name=Menu Kids, price=12.5, content=, active=true, water=true)])
Total to pay:48.4
Order(date=Tue Sep 17 10:58:00 CEST 2024, waiter=Jazz, peopleQty=20, totalPayment=48.4, paid=false, table=Table(name=Table 01, description=Table type Modern, qty=4, busy=false), menus=[Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Vegan, price=10.5, content=, active=true, water=true), Menu(name=Menu Kids, price=12.5, content=, active=true, water=true)])


Finish

Process finished with exit code 0

commit 4b43597

/home/albert/.jdks/corretto-21.0.4/bin/java -javaagent:/app/IDEA-C/lib/idea_rt.jar=45809:/app/IDEA-C/bin -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath /home/albert/MyProjects/Sandbox/RestaurantJava/target/classes:/home/albert/.m2/repository/org/projectlombok/lombok/1.18.34/lombok-1.18.34.jar org.example.App

Init

Total to pay:48.4
Order(date=Wed Sep 18 12:30:03 CEST 2024, waiter=Jazz, peopleQty=4, totalPayment=48.4, paid=false, table=Table(name=Table 01, description=Table type Modern, qty=4, busy=true), menus=[Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Vegan, price=10.5, content=, active=true, water=true), Menu(name=Menu Kids, price=12.5, content=, active=true, water=true)])
Order(date=Wed Sep 18 12:30:03 CEST 2024, waiter=Jazz, peopleQty=4, totalPayment=48.4, paid=true, table=Table(name=Table 01, description=Table type Modern, qty=4, busy=true), menus=[Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Vegan, price=10.5, content=, active=true, water=true), Menu(name=Menu Kids, price=12.5, content=, active=true, water=true)])
Table status (Table 01):false


Available tables:

Table 05
Table 03
Table 04
Table 02

Finish

commit 4bf6ce5

/home/albert/.jdks/corretto-21.0.4/bin/java -javaagent:/app/IDEA-C/lib/idea_rt.jar=33697:/app/IDEA-C/bin -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath /home/albert/MyProjects/Sandbox/RestaurantJava/target/classes:/home/albert/.m2/repository/org/projectlombok/lombok/1.18.34/lombok-1.18.34.jar org.example.App

Init

Main Menu
-------------

0-Quit
1-Create Order
2-List Tables
3-Pay
4-Admin
Option? 
1
Total to pay:48.4
Order(date=Thu Sep 19 13:05:27 CEST 2024, waiter=Jazz, peopleQty=4, totalPayment=48.4, paid=false, table=Table(name=Table 01, description=Table type Modern, qty=4, busy=true), menus=[Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Vegan, price=10.5, content=, active=true, water=true), Menu(name=Menu Kids, price=12.5, content=, active=true, water=true)])
Order(date=Thu Sep 19 13:05:27 CEST 2024, waiter=Jazz, peopleQty=4, totalPayment=48.4, paid=true, table=Table(name=Table 01, description=Table type Modern, qty=4, busy=true), menus=[Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Night, price=8.5, content=, active=true, water=true), Menu(name=Menu Vegan, price=10.5, content=, active=true, water=true), Menu(name=Menu Kids, price=12.5, content=, active=true, water=true)])
Table status (Table 01):false
Main Menu
-------------

0-Quit
1-Create Order
2-List Tables
3-Pay
4-Admin
Option? 
0

Finish

Process finished with exit code 0